package queryapi_test import ( "bytes" "encoding/json" "fmt" "net/http" "net/http/httptest" "testing" "time" queryapi "queryorchestration/api/queryAPI" "queryorchestration/internal/database/repository" "queryorchestration/internal/fieldextraction" "queryorchestration/internal/serviceconfig" "queryorchestration/internal/test" "github.com/google/uuid" "github.com/jackc/pgx/v5/pgtype" "github.com/labstack/echo/v4" openapi_types "github.com/oapi-codegen/runtime/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) type FieldExtractionsTestConfig struct { serviceconfig.BaseConfig } func (c *FieldExtractionsTestConfig) GetBackgroundRunner() any { return nil } func setupFieldExtractionsTestController(t *testing.T) (*queryapi.Controllers, *FieldExtractionsTestConfig, uuid.UUID, string) { t.Helper() cfg := &FieldExtractionsTestConfig{} test.CreateDB(t, cfg) // Create services fieldExtractionSvc := fieldextraction.New(cfg) services := &queryapi.Services{ FieldExtraction: fieldExtractionSvc, } // Create test client and document with unique IDs ctx := t.Context() uniqueID := uuid.New().String()[:8] clientID := fmt.Sprintf("test-client-%s", uniqueID) err := cfg.GetDBQueries().CreateClient(ctx, &repository.CreateClientParams{ Clientid: clientID, Name: "Test Client", }) require.NoError(t, err) filename := "test.pdf" documentID, err := cfg.GetDBQueries().CreateDocument(ctx, &repository.CreateDocumentParams{ Clientid: clientID, Hash: fmt.Sprintf("testhash-%s", uniqueID), // Unique hash per test Filename: &filename, }) require.NoError(t, err) ctrl := queryapi.NewControllers(services, nil) return ctrl, cfg, documentID, clientID } func TestCreateFieldExtraction_Success(t *testing.T) { ctrl, _, documentID, _ := setupFieldExtractionsTestController(t) // Create request body reqBody := queryapi.FieldExtractionRequest{ DocumentId: queryapi.DocumentID(documentID), CreatedBy: openapi_types.Email("test@example.com"), SingleFields: queryapi.SingleFields{ FileName: ptr("test.pdf"), ContractTitle: ptr("Test Contract"), ClientName: ptr("Test Client Inc"), }, ArrayFields: []queryapi.ArrayFieldItem{ { ExhibitTitle: ptr("Exhibit A"), ExhibitPage: ptr("1"), ReimbProvTin: ptr("123456789"), }, { ExhibitTitle: ptr("Exhibit B"), ExhibitPage: ptr("2"), ReimbProvTin: ptr("987654321"), }, }, } body, err := json.Marshal(reqBody) require.NoError(t, err) e := echo.New() req := httptest.NewRequest(http.MethodPost, "/field-extractions", bytes.NewReader(body)) req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) rec := httptest.NewRecorder() c := e.NewContext(req, rec) err = ctrl.CreateFieldExtraction(c) require.NoError(t, err) assert.Equal(t, http.StatusCreated, rec.Code) // Parse response var resp queryapi.FieldExtractionResponse err = json.Unmarshal(rec.Body.Bytes(), &resp) require.NoError(t, err) assert.Equal(t, documentID, uuid.UUID(resp.DocumentId)) assert.Equal(t, int32(1), resp.Version) // First version is 1 assert.Equal(t, "test@example.com", string(resp.CreatedBy)) assert.Equal(t, "test.pdf", *resp.SingleFields.FileName) assert.Equal(t, "Test Contract", *resp.SingleFields.ContractTitle) assert.Len(t, resp.ArrayFields, 2) assert.Equal(t, "Exhibit A", *resp.ArrayFields[0].ExhibitTitle) assert.Equal(t, "Exhibit B", *resp.ArrayFields[1].ExhibitTitle) } func TestCreateFieldExtraction_InvalidRequest(t *testing.T) { ctrl, _, _, _ := setupFieldExtractionsTestController(t) e := echo.New() req := httptest.NewRequest(http.MethodPost, "/field-extractions", bytes.NewReader([]byte("invalid json"))) req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) rec := httptest.NewRecorder() c := e.NewContext(req, rec) err := ctrl.CreateFieldExtraction(c) // Handler returns an echo.HTTPError which should be treated as an error require.Error(t, err) httpErr, ok := err.(*echo.HTTPError) require.True(t, ok) assert.Equal(t, http.StatusBadRequest, httpErr.Code) } func TestCreateFieldExtraction_MissingDocumentID(t *testing.T) { ctrl, _, _, _ := setupFieldExtractionsTestController(t) reqBody := queryapi.FieldExtractionRequest{ DocumentId: queryapi.DocumentID(uuid.Nil), CreatedBy: openapi_types.Email("test@example.com"), SingleFields: queryapi.SingleFields{ FileName: ptr("test.pdf"), }, ArrayFields: []queryapi.ArrayFieldItem{}, } body, err := json.Marshal(reqBody) require.NoError(t, err) e := echo.New() req := httptest.NewRequest(http.MethodPost, "/field-extractions", bytes.NewReader(body)) req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) rec := httptest.NewRecorder() c := e.NewContext(req, rec) err = ctrl.CreateFieldExtraction(c) require.Error(t, err) httpErr, ok := err.(*echo.HTTPError) require.True(t, ok) assert.Equal(t, http.StatusBadRequest, httpErr.Code) } func TestCreateFieldExtraction_MissingCreatedBy(t *testing.T) { // Use a simple controller without database since we're just testing validation ctrl := &queryapi.Controllers{} // Use a valid document ID but empty createdBy documentID := uuid.New() body := []byte(fmt.Sprintf(`{ "documentId": "%s", "createdBy": "", "singleFields": {"fileName": "test.pdf"}, "arrayFields": [] }`, documentID)) e := echo.New() req := httptest.NewRequest(http.MethodPost, "/field-extractions", bytes.NewReader(body)) req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) rec := httptest.NewRecorder() c := e.NewContext(req, rec) err := ctrl.CreateFieldExtraction(c) require.Error(t, err) httpErr, ok := err.(*echo.HTTPError) require.True(t, ok) assert.Equal(t, http.StatusBadRequest, httpErr.Code) } func TestGetCurrentFieldExtraction_Success(t *testing.T) { ctrl, cfg, documentID, _ := setupFieldExtractionsTestController(t) ctx := t.Context() // First create a field extraction using the service directly svc := fieldextraction.New(cfg) filename := "test.pdf" contractTitle := "Test Contract" _, err := svc.CreateFieldExtraction(ctx, &fieldextraction.CreateFieldExtractionInput{ DocumentID: documentID, SingleFields: &repository.AddFieldExtractionParams{ Documentid: documentID, Filename: &filename, Contracttitle: &contractTitle, Createdby: "user@example.com", }, ArrayFields: []*repository.AddFieldExtractionArrayFieldParams{}, }) require.NoError(t, err) // Now test the API e := echo.New() req := httptest.NewRequest(http.MethodGet, fmt.Sprintf("/field-extractions?documentId=%s", documentID), nil) rec := httptest.NewRecorder() c := e.NewContext(req, rec) params := queryapi.GetCurrentFieldExtractionParams{ DocumentId: queryapi.DocumentID(documentID), } err = ctrl.GetCurrentFieldExtraction(c, params) require.NoError(t, err) assert.Equal(t, http.StatusOK, rec.Code) // Parse response var resp queryapi.FieldExtractionResponse err = json.Unmarshal(rec.Body.Bytes(), &resp) require.NoError(t, err) assert.Equal(t, documentID, uuid.UUID(resp.DocumentId)) assert.Equal(t, int32(1), resp.Version) assert.Equal(t, "user@example.com", string(resp.CreatedBy)) assert.Equal(t, "Test Contract", *resp.SingleFields.ContractTitle) } func TestGetCurrentFieldExtraction_NotFound(t *testing.T) { ctrl, _, _, _ := setupFieldExtractionsTestController(t) // Use a random document ID that doesn't have any extractions randomDocID := uuid.New() e := echo.New() req := httptest.NewRequest(http.MethodGet, fmt.Sprintf("/field-extractions?documentId=%s", randomDocID), nil) rec := httptest.NewRecorder() c := e.NewContext(req, rec) params := queryapi.GetCurrentFieldExtractionParams{ DocumentId: queryapi.DocumentID(randomDocID), } err := ctrl.GetCurrentFieldExtraction(c, params) require.Error(t, err) httpErr, ok := err.(*echo.HTTPError) require.True(t, ok) assert.Equal(t, http.StatusNotFound, httpErr.Code) } func TestGetCurrentFieldExtraction_InvalidDocumentID(t *testing.T) { ctrl, _, _, _ := setupFieldExtractionsTestController(t) e := echo.New() req := httptest.NewRequest(http.MethodGet, "/field-extractions?documentId=", nil) rec := httptest.NewRecorder() c := e.NewContext(req, rec) params := queryapi.GetCurrentFieldExtractionParams{ DocumentId: queryapi.DocumentID(uuid.Nil), } err := ctrl.GetCurrentFieldExtraction(c, params) require.Error(t, err) httpErr, ok := err.(*echo.HTTPError) require.True(t, ok) assert.Equal(t, http.StatusBadRequest, httpErr.Code) } func TestGetFieldExtractionHistory_Success(t *testing.T) { ctrl, cfg, documentID, _ := setupFieldExtractionsTestController(t) ctx := t.Context() // Create multiple versions svc := fieldextraction.New(cfg) filename := "test.pdf" for i := 1; i <= 3; i++ { contractTitle := fmt.Sprintf("Contract Version %d", i) _, err := svc.CreateFieldExtraction(ctx, &fieldextraction.CreateFieldExtractionInput{ DocumentID: documentID, SingleFields: &repository.AddFieldExtractionParams{ Documentid: documentID, Filename: &filename, Contracttitle: &contractTitle, Createdby: fmt.Sprintf("user%d@example.com", i), }, ArrayFields: []*repository.AddFieldExtractionArrayFieldParams{}, }) require.NoError(t, err) } // Now test the API e := echo.New() req := httptest.NewRequest(http.MethodGet, fmt.Sprintf("/field-extractions/history?documentId=%s", documentID), nil) rec := httptest.NewRecorder() c := e.NewContext(req, rec) params := queryapi.GetFieldExtractionHistoryParams{ DocumentId: queryapi.DocumentID(documentID), } err := ctrl.GetFieldExtractionHistory(c, params) require.NoError(t, err) assert.Equal(t, http.StatusOK, rec.Code) // Parse response var resp struct { Versions []queryapi.FieldExtractionVersion `json:"versions"` } err = json.Unmarshal(rec.Body.Bytes(), &resp) require.NoError(t, err) // Should have 3 versions, most recent first assert.Len(t, resp.Versions, 3) assert.Equal(t, int32(3), resp.Versions[0].Version) assert.Equal(t, "user3@example.com", string(resp.Versions[0].CreatedBy)) assert.Equal(t, int32(2), resp.Versions[1].Version) assert.Equal(t, "user2@example.com", string(resp.Versions[1].CreatedBy)) assert.Equal(t, int32(1), resp.Versions[2].Version) assert.Equal(t, "user1@example.com", string(resp.Versions[2].CreatedBy)) } func TestGetFieldExtractionHistory_NoHistory(t *testing.T) { ctrl, cfg, _, clientID := setupFieldExtractionsTestController(t) ctx := t.Context() // Create a new document with no extractions filename := "nohistory.pdf" newDocID, err := cfg.GetDBQueries().CreateDocument(ctx, &repository.CreateDocumentParams{ Clientid: clientID, Hash: "nohistoryhash", Filename: &filename, }) require.NoError(t, err) e := echo.New() req := httptest.NewRequest(http.MethodGet, fmt.Sprintf("/field-extractions/history?documentId=%s", newDocID), nil) rec := httptest.NewRecorder() c := e.NewContext(req, rec) params := queryapi.GetFieldExtractionHistoryParams{ DocumentId: queryapi.DocumentID(newDocID), } err = ctrl.GetFieldExtractionHistory(c, params) require.NoError(t, err) assert.Equal(t, http.StatusOK, rec.Code) // Parse response var resp struct { Versions []queryapi.FieldExtractionVersion `json:"versions"` } err = json.Unmarshal(rec.Body.Bytes(), &resp) require.NoError(t, err) assert.Len(t, resp.Versions, 0) } func TestGetFieldExtractionHistory_InvalidDocumentID(t *testing.T) { ctrl, _, _, _ := setupFieldExtractionsTestController(t) e := echo.New() req := httptest.NewRequest(http.MethodGet, "/field-extractions/history?documentId=", nil) rec := httptest.NewRecorder() c := e.NewContext(req, rec) params := queryapi.GetFieldExtractionHistoryParams{ DocumentId: queryapi.DocumentID(uuid.Nil), } err := ctrl.GetFieldExtractionHistory(c, params) require.Error(t, err) httpErr, ok := err.(*echo.HTTPError) require.True(t, ok) assert.Equal(t, http.StatusBadRequest, httpErr.Code) } func TestCreateFieldExtraction_WithDates(t *testing.T) { ctrl, _, documentID, _ := setupFieldExtractionsTestController(t) effectiveDate := openapi_types.Date{Time: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)} terminationDate := openapi_types.Date{Time: time.Date(2025, 12, 31, 0, 0, 0, 0, time.UTC)} reimbEffectiveDate := openapi_types.Date{Time: time.Date(2024, 6, 1, 0, 0, 0, 0, time.UTC)} reqBody := queryapi.FieldExtractionRequest{ DocumentId: queryapi.DocumentID(documentID), CreatedBy: openapi_types.Email("test@example.com"), SingleFields: queryapi.SingleFields{ FileName: ptr("contract.pdf"), ContractTitle: ptr("Test Contract with Dates"), AareteDerivedEffectiveDt: &effectiveDate, AareteDerivedTerminationDt: &terminationDate, }, ArrayFields: []queryapi.ArrayFieldItem{ { ExhibitTitle: ptr("Exhibit A"), ReimbEffectiveDt: &reimbEffectiveDate, }, }, } body, err := json.Marshal(reqBody) require.NoError(t, err) e := echo.New() req := httptest.NewRequest(http.MethodPost, "/field-extractions", bytes.NewReader(body)) req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) rec := httptest.NewRecorder() c := e.NewContext(req, rec) err = ctrl.CreateFieldExtraction(c) require.NoError(t, err) assert.Equal(t, http.StatusCreated, rec.Code) // Parse response var resp queryapi.FieldExtractionResponse err = json.Unmarshal(rec.Body.Bytes(), &resp) require.NoError(t, err) // Verify dates are returned correctly require.NotNil(t, resp.SingleFields.AareteDerivedEffectiveDt) assert.Equal(t, 2024, resp.SingleFields.AareteDerivedEffectiveDt.Year()) assert.Equal(t, time.January, resp.SingleFields.AareteDerivedEffectiveDt.Month()) assert.Equal(t, 1, resp.SingleFields.AareteDerivedEffectiveDt.Day()) require.NotNil(t, resp.SingleFields.AareteDerivedTerminationDt) assert.Equal(t, 2025, resp.SingleFields.AareteDerivedTerminationDt.Year()) assert.Equal(t, time.December, resp.SingleFields.AareteDerivedTerminationDt.Month()) assert.Equal(t, 31, resp.SingleFields.AareteDerivedTerminationDt.Day()) require.NotNil(t, resp.ArrayFields[0].ReimbEffectiveDt) assert.Equal(t, 2024, resp.ArrayFields[0].ReimbEffectiveDt.Year()) assert.Equal(t, time.June, resp.ArrayFields[0].ReimbEffectiveDt.Month()) } func TestCreateFieldExtraction_WithNumericFields(t *testing.T) { ctrl, _, documentID, _ := setupFieldExtractionsTestController(t) reimbPctRate := 10.5 reimbFeeRate := 150.75 grouperBaseRate := 1000.00 reqBody := queryapi.FieldExtractionRequest{ DocumentId: queryapi.DocumentID(documentID), CreatedBy: openapi_types.Email("test@example.com"), SingleFields: queryapi.SingleFields{ FileName: ptr("numeric_test.pdf"), }, ArrayFields: []queryapi.ArrayFieldItem{ { ExhibitTitle: ptr("Exhibit A"), ReimbPctRate: &reimbPctRate, ReimbFeeRate: &reimbFeeRate, GrouperBaseRate: &grouperBaseRate, }, }, } body, err := json.Marshal(reqBody) require.NoError(t, err) e := echo.New() req := httptest.NewRequest(http.MethodPost, "/field-extractions", bytes.NewReader(body)) req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) rec := httptest.NewRecorder() c := e.NewContext(req, rec) err = ctrl.CreateFieldExtraction(c) require.NoError(t, err) assert.Equal(t, http.StatusCreated, rec.Code) // Parse response var resp queryapi.FieldExtractionResponse err = json.Unmarshal(rec.Body.Bytes(), &resp) require.NoError(t, err) // Verify numeric fields require.Len(t, resp.ArrayFields, 1) require.NotNil(t, resp.ArrayFields[0].ReimbPctRate) assert.InDelta(t, 10.5, *resp.ArrayFields[0].ReimbPctRate, 0.001) require.NotNil(t, resp.ArrayFields[0].ReimbFeeRate) assert.InDelta(t, 150.75, *resp.ArrayFields[0].ReimbFeeRate, 0.001) require.NotNil(t, resp.ArrayFields[0].GrouperBaseRate) assert.InDelta(t, 1000.00, *resp.ArrayFields[0].GrouperBaseRate, 0.001) } func TestCreateFieldExtraction_EmptyArrayFields(t *testing.T) { ctrl, _, documentID, _ := setupFieldExtractionsTestController(t) reqBody := queryapi.FieldExtractionRequest{ DocumentId: queryapi.DocumentID(documentID), CreatedBy: openapi_types.Email("test@example.com"), SingleFields: queryapi.SingleFields{ FileName: ptr("simple.pdf"), ContractTitle: ptr("Simple Contract"), }, ArrayFields: []queryapi.ArrayFieldItem{}, } body, err := json.Marshal(reqBody) require.NoError(t, err) e := echo.New() req := httptest.NewRequest(http.MethodPost, "/field-extractions", bytes.NewReader(body)) req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) rec := httptest.NewRecorder() c := e.NewContext(req, rec) err = ctrl.CreateFieldExtraction(c) require.NoError(t, err) assert.Equal(t, http.StatusCreated, rec.Code) // Parse response var resp queryapi.FieldExtractionResponse err = json.Unmarshal(rec.Body.Bytes(), &resp) require.NoError(t, err) assert.Len(t, resp.ArrayFields, 0) } func TestCreateFieldExtraction_LargeArrayFields(t *testing.T) { ctrl, _, documentID, _ := setupFieldExtractionsTestController(t) // Create 100 array field items arrayFields := make([]queryapi.ArrayFieldItem, 100) for i := range arrayFields { title := fmt.Sprintf("Exhibit %d", i) page := fmt.Sprintf("%d", i+1) arrayFields[i] = queryapi.ArrayFieldItem{ ExhibitTitle: &title, ExhibitPage: &page, } } reqBody := queryapi.FieldExtractionRequest{ DocumentId: queryapi.DocumentID(documentID), CreatedBy: openapi_types.Email("test@example.com"), SingleFields: queryapi.SingleFields{ FileName: ptr("large_array.pdf"), ContractTitle: ptr("Large Array Contract"), }, ArrayFields: arrayFields, } body, err := json.Marshal(reqBody) require.NoError(t, err) e := echo.New() req := httptest.NewRequest(http.MethodPost, "/field-extractions", bytes.NewReader(body)) req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) rec := httptest.NewRecorder() c := e.NewContext(req, rec) err = ctrl.CreateFieldExtraction(c) require.NoError(t, err) assert.Equal(t, http.StatusCreated, rec.Code) // Parse response var resp queryapi.FieldExtractionResponse err = json.Unmarshal(rec.Body.Bytes(), &resp) require.NoError(t, err) assert.Len(t, resp.ArrayFields, 100) assert.Equal(t, "Exhibit 0", *resp.ArrayFields[0].ExhibitTitle) assert.Equal(t, "Exhibit 99", *resp.ArrayFields[99].ExhibitTitle) } func TestCreateFieldExtraction_VersionIncrement(t *testing.T) { ctrl, cfg, documentID, _ := setupFieldExtractionsTestController(t) // Create first version via API reqBody := queryapi.FieldExtractionRequest{ DocumentId: queryapi.DocumentID(documentID), CreatedBy: openapi_types.Email("user1@example.com"), SingleFields: queryapi.SingleFields{ ContractTitle: ptr("Version 1"), }, ArrayFields: []queryapi.ArrayFieldItem{}, } body, _ := json.Marshal(reqBody) e := echo.New() req := httptest.NewRequest(http.MethodPost, "/field-extractions", bytes.NewReader(body)) req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) rec := httptest.NewRecorder() c := e.NewContext(req, rec) err := ctrl.CreateFieldExtraction(c) require.NoError(t, err) assert.Equal(t, http.StatusCreated, rec.Code) var resp1 queryapi.FieldExtractionResponse _ = json.Unmarshal(rec.Body.Bytes(), &resp1) assert.Equal(t, int32(1), resp1.Version) // Create second version reqBody.CreatedBy = openapi_types.Email("user2@example.com") reqBody.SingleFields.ContractTitle = ptr("Version 2") body, _ = json.Marshal(reqBody) req = httptest.NewRequest(http.MethodPost, "/field-extractions", bytes.NewReader(body)) req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) rec = httptest.NewRecorder() c = e.NewContext(req, rec) err = ctrl.CreateFieldExtraction(c) require.NoError(t, err) assert.Equal(t, http.StatusCreated, rec.Code) var resp2 queryapi.FieldExtractionResponse _ = json.Unmarshal(rec.Body.Bytes(), &resp2) assert.Equal(t, int32(2), resp2.Version) // GetCurrentFieldExtraction should return version 2 req = httptest.NewRequest(http.MethodGet, fmt.Sprintf("/field-extractions?documentId=%s", documentID), nil) rec = httptest.NewRecorder() c = e.NewContext(req, rec) _ = cfg // Keep cfg used for test context params := queryapi.GetCurrentFieldExtractionParams{ DocumentId: queryapi.DocumentID(documentID), } err = ctrl.GetCurrentFieldExtraction(c, params) require.NoError(t, err) assert.Equal(t, http.StatusOK, rec.Code) var currentResp queryapi.FieldExtractionResponse _ = json.Unmarshal(rec.Body.Bytes(), ¤tResp) assert.Equal(t, int32(2), currentResp.Version) assert.Equal(t, "Version 2", *currentResp.SingleFields.ContractTitle) } func TestGetFieldExtractionByVersion_Success(t *testing.T) { ctrl, cfg, documentID, _ := setupFieldExtractionsTestController(t) ctx := t.Context() // Create multiple versions with dates for coverage svc := fieldextraction.New(cfg) filename := "test.pdf" for i := 1; i <= 3; i++ { contractTitle := fmt.Sprintf("Contract Version %d", i) clientName := fmt.Sprintf("Client %d", i) // Include dates to test date conversion coverage effectiveDate := pgtype.Date{Time: time.Date(2024, 1, i, 0, 0, 0, 0, time.UTC), Valid: true} terminationDate := pgtype.Date{Time: time.Date(2024, 12, i, 0, 0, 0, 0, time.UTC), Valid: true} _, err := svc.CreateFieldExtraction(ctx, &fieldextraction.CreateFieldExtractionInput{ DocumentID: documentID, SingleFields: &repository.AddFieldExtractionParams{ Documentid: documentID, Filename: &filename, Contracttitle: &contractTitle, Clientname: &clientName, Aaretederivedeffectivedt: effectiveDate, Aaretederivedterminationdt: terminationDate, Createdby: fmt.Sprintf("user%d@example.com", i), }, ArrayFields: []*repository.AddFieldExtractionArrayFieldParams{ { Exhibittitle: ptr(fmt.Sprintf("Exhibit V%d", i)), }, }, }) require.NoError(t, err) } // Test retrieving version 2 e := echo.New() req := httptest.NewRequest(http.MethodGet, fmt.Sprintf("/field-extractions/version?documentId=%s&version=2", documentID), nil) rec := httptest.NewRecorder() c := e.NewContext(req, rec) params := queryapi.GetFieldExtractionByVersionParams{ DocumentId: queryapi.DocumentID(documentID), Version: 2, } err := ctrl.GetFieldExtractionByVersion(c, params) require.NoError(t, err) assert.Equal(t, http.StatusOK, rec.Code) // Parse response var resp queryapi.FieldExtractionResponse err = json.Unmarshal(rec.Body.Bytes(), &resp) require.NoError(t, err) // Verify we got version 2 assert.Equal(t, documentID, uuid.UUID(resp.DocumentId)) assert.Equal(t, int32(2), resp.Version) assert.Equal(t, "user2@example.com", string(resp.CreatedBy)) assert.Equal(t, "Contract Version 2", *resp.SingleFields.ContractTitle) assert.Equal(t, "Client 2", *resp.SingleFields.ClientName) // Verify dates are returned correctly require.NotNil(t, resp.SingleFields.AareteDerivedEffectiveDt, "Expected effective date in response") require.NotNil(t, resp.SingleFields.AareteDerivedTerminationDt, "Expected termination date in response") assert.Equal(t, 2024, resp.SingleFields.AareteDerivedEffectiveDt.Year()) assert.Equal(t, time.January, resp.SingleFields.AareteDerivedEffectiveDt.Month()) assert.Equal(t, 2, resp.SingleFields.AareteDerivedEffectiveDt.Day()) require.Len(t, resp.ArrayFields, 1) assert.Equal(t, "Exhibit V2", *resp.ArrayFields[0].ExhibitTitle) // Also test retrieving version 1 req = httptest.NewRequest(http.MethodGet, fmt.Sprintf("/field-extractions/version?documentId=%s&version=1", documentID), nil) rec = httptest.NewRecorder() c = e.NewContext(req, rec) params.Version = 1 err = ctrl.GetFieldExtractionByVersion(c, params) require.NoError(t, err) assert.Equal(t, http.StatusOK, rec.Code) err = json.Unmarshal(rec.Body.Bytes(), &resp) require.NoError(t, err) assert.Equal(t, int32(1), resp.Version) assert.Equal(t, "Contract Version 1", *resp.SingleFields.ContractTitle) assert.Equal(t, "Exhibit V1", *resp.ArrayFields[0].ExhibitTitle) } func TestGetFieldExtractionByVersion_NotFound(t *testing.T) { ctrl, cfg, documentID, _ := setupFieldExtractionsTestController(t) ctx := t.Context() // Create only one version svc := fieldextraction.New(cfg) filename := "test.pdf" contractTitle := "Test Contract" _, err := svc.CreateFieldExtraction(ctx, &fieldextraction.CreateFieldExtractionInput{ DocumentID: documentID, SingleFields: &repository.AddFieldExtractionParams{ Documentid: documentID, Filename: &filename, Contracttitle: &contractTitle, Createdby: "user@example.com", }, ArrayFields: []*repository.AddFieldExtractionArrayFieldParams{}, }) require.NoError(t, err) // Try to get version 5 (which doesn't exist) e := echo.New() req := httptest.NewRequest(http.MethodGet, fmt.Sprintf("/field-extractions/version?documentId=%s&version=5", documentID), nil) rec := httptest.NewRecorder() c := e.NewContext(req, rec) params := queryapi.GetFieldExtractionByVersionParams{ DocumentId: queryapi.DocumentID(documentID), Version: 5, } err = ctrl.GetFieldExtractionByVersion(c, params) require.Error(t, err) httpErr, ok := err.(*echo.HTTPError) require.True(t, ok) assert.Equal(t, http.StatusNotFound, httpErr.Code) } func TestGetFieldExtractionByVersion_InvalidDocumentID(t *testing.T) { ctrl, _, _, _ := setupFieldExtractionsTestController(t) e := echo.New() req := httptest.NewRequest(http.MethodGet, "/field-extractions/version?documentId=&version=1", nil) rec := httptest.NewRecorder() c := e.NewContext(req, rec) params := queryapi.GetFieldExtractionByVersionParams{ DocumentId: queryapi.DocumentID(uuid.Nil), Version: 1, } err := ctrl.GetFieldExtractionByVersion(c, params) require.Error(t, err) httpErr, ok := err.(*echo.HTTPError) require.True(t, ok) assert.Equal(t, http.StatusBadRequest, httpErr.Code) } func TestGetFieldExtractionByVersion_InvalidVersion(t *testing.T) { ctrl, _, documentID, _ := setupFieldExtractionsTestController(t) e := echo.New() req := httptest.NewRequest(http.MethodGet, fmt.Sprintf("/field-extractions/version?documentId=%s&version=0", documentID), nil) rec := httptest.NewRecorder() c := e.NewContext(req, rec) params := queryapi.GetFieldExtractionByVersionParams{ DocumentId: queryapi.DocumentID(documentID), Version: 0, // Invalid: version must be >= 1 } err := ctrl.GetFieldExtractionByVersion(c, params) require.Error(t, err) httpErr, ok := err.(*echo.HTTPError) require.True(t, ok) assert.Equal(t, http.StatusBadRequest, httpErr.Code) } func TestGetFieldExtractionByVersion_NoExtractions(t *testing.T) { ctrl, _, documentID, _ := setupFieldExtractionsTestController(t) // Document exists but has no field extractions e := echo.New() req := httptest.NewRequest(http.MethodGet, fmt.Sprintf("/field-extractions/version?documentId=%s&version=1", documentID), nil) rec := httptest.NewRecorder() c := e.NewContext(req, rec) params := queryapi.GetFieldExtractionByVersionParams{ DocumentId: queryapi.DocumentID(documentID), Version: 1, } err := ctrl.GetFieldExtractionByVersion(c, params) require.Error(t, err) httpErr, ok := err.(*echo.HTTPError) require.True(t, ok) assert.Equal(t, http.StatusNotFound, httpErr.Code) } // Helper function to create string pointer func ptr(s string) *string { return &s }