Merged in feature/textExtractionsPart3 (pull request #195)

enrich doc responses

* enrich doc responses
This commit is contained in:
Jay Brown
2025-12-11 14:25:51 +00:00
parent a94637ab13
commit 8c218f162b
22 changed files with 1797 additions and 363 deletions
+301 -219
View File
@@ -576,24 +576,69 @@ type DocClient struct {
Name ClientName `json:"name"`
}
// Document The document properties.
type Document struct {
// DocumentEnriched Enriched document details with additional metadata
type DocumentEnriched struct {
// ClientId The client external id
ClientId ClientID `json:"client_id"`
// Fields The fields and the value for the document
Fields map[string]interface{} `json:"fields"`
// Filename Original filename of the document
Filename *string `json:"filename,omitempty"`
// FolderId Parent folder ID, null if document is not in a folder
FolderId *openapi_types.UUID `json:"folderId,omitempty"`
// HasTextRecord Whether a text extraction (field extraction) record exists for this document
HasTextRecord bool `json:"hasTextRecord"`
// Hash The document hash
Hash Hash `json:"hash"`
// Id The document id.
Id DocumentID `json:"id"`
// Labels All labels applied to this document
Labels []LabelRecord `json:"labels"`
// OriginalPath Original path provided during upload (immutable)
OriginalPath *string `json:"originalPath,omitempty"`
// TextRecord Field extraction with version information
TextRecord *FieldExtractionResponse `json:"textRecord,omitempty"`
}
// DocumentID The document id.
type DocumentID = openapi_types.UUID
// DocumentInFolder Document within a folder with enriched metadata (lighter format, excludes client_id and fields)
type DocumentInFolder struct {
// Filename Original filename of the document
Filename *string `json:"filename,omitempty"`
// FolderId Parent folder ID
FolderId *openapi_types.UUID `json:"folderId,omitempty"`
// HasTextRecord Whether a text extraction record exists for this document
HasTextRecord bool `json:"hasTextRecord"`
// Hash The document hash
Hash Hash `json:"hash"`
// Id The document id.
Id DocumentID `json:"id"`
// Labels All labels applied to this document
Labels []LabelRecord `json:"labels"`
// OriginalPath Original path provided during upload (immutable)
OriginalPath *string `json:"originalPath,omitempty"`
// TextRecord Field extraction with version information
TextRecord *FieldExtractionResponse `json:"textRecord,omitempty"`
}
// DocumentSummary The document summary properties.
type DocumentSummary struct {
// Hash The document hash
@@ -1060,6 +1105,12 @@ type ListClientFoldersParams struct {
Metrics *bool `form:"metrics,omitempty" json:"metrics,omitempty"`
}
// GetDocumentParams defines parameters for GetDocument.
type GetDocumentParams struct {
// TextRecord When true, includes the full text extraction record in the response
TextRecord *bool `form:"textRecord,omitempty" json:"textRecord,omitempty"`
}
// GetCurrentFieldExtractionParams defines parameters for GetCurrentFieldExtraction.
type GetCurrentFieldExtractionParams struct {
// DocumentId The document ID
@@ -1081,6 +1132,12 @@ type GetFieldExtractionByVersionParams struct {
Version int64 `form:"version" json:"version"`
}
// GetFolderDocumentsParams defines parameters for GetFolderDocuments.
type GetFolderDocumentsParams struct {
// TextRecord When true, includes the full text extraction record for each document
TextRecord *bool `form:"textRecord,omitempty" json:"textRecord,omitempty"`
}
// GetDocumentsByLabelParams defines parameters for GetDocumentsByLabel.
type GetDocumentsByLabelParams struct {
// ClientId The client ID to filter documents
@@ -1214,7 +1271,7 @@ type ServerInterface interface {
ListClients(ctx echo.Context) error
// Get document details by its id
// (GET /document/{id})
GetDocument(ctx echo.Context, id DocumentID) error
GetDocument(ctx echo.Context, id DocumentID, params GetDocumentParams) error
// Get all labels for a document
// (GET /documents/{documentId}/labels)
GetDocumentLabels(ctx echo.Context, documentId openapi_types.UUID) error
@@ -1244,7 +1301,7 @@ type ServerInterface interface {
RenameFolder(ctx echo.Context, folderId openapi_types.UUID) error
// Get documents in a folder
// (GET /folders/{folderId}/documents)
GetFolderDocuments(ctx echo.Context, folderId openapi_types.UUID) error
GetFolderDocuments(ctx echo.Context, folderId openapi_types.UUID, params GetFolderDocumentsParams) error
// Get folder processing metrics
// (GET /folders/{folderId}/metrics)
GetFolderMetrics(ctx echo.Context, folderId openapi_types.UUID) error
@@ -1778,8 +1835,17 @@ func (w *ServerInterfaceWrapper) GetDocument(ctx echo.Context) error {
ctx.Set(JwtAuthScopes, []string{})
// Parameter object where we will unmarshal all parameters from the context
var params GetDocumentParams
// ------------- Optional query parameter "textRecord" -------------
err = runtime.BindQueryParameter("form", true, false, "textRecord", ctx.QueryParams(), &params.TextRecord)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter textRecord: %s", err))
}
// Invoke the callback with all the unmarshaled arguments
err = w.Handler.GetDocument(ctx, id)
err = w.Handler.GetDocument(ctx, id, params)
return err
}
@@ -1957,8 +2023,17 @@ func (w *ServerInterfaceWrapper) GetFolderDocuments(ctx echo.Context) error {
ctx.Set(JwtAuthScopes, []string{})
// Parameter object where we will unmarshal all parameters from the context
var params GetFolderDocumentsParams
// ------------- Optional query parameter "textRecord" -------------
err = runtime.BindQueryParameter("form", true, false, "textRecord", ctx.QueryParams(), &params.TextRecord)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter textRecord: %s", err))
}
// Invoke the callback with all the unmarshaled arguments
err = w.Handler.GetFolderDocuments(ctx, folderId)
err = w.Handler.GetFolderDocuments(ctx, folderId, params)
return err
}
@@ -2220,219 +2295,226 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
// Base64 encoded, gzipped, json marshaled Swagger object
var swaggerSpec = []string{
"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",
}
// GetSwagger returns the content of the embedded swagger specification file
+55 -9
View File
@@ -5,12 +5,14 @@ import (
"log/slog"
"net/http"
"queryorchestration/internal/database/repository"
"queryorchestration/internal/document/batch/storage"
documentupload "queryorchestration/internal/document/upload"
"github.com/google/uuid"
"github.com/labstack/echo/v4"
"github.com/oapi-codegen/nullable"
openapi_types "github.com/oapi-codegen/runtime/types"
)
func (s *Controllers) UploadDocument(ctx echo.Context, clientId ClientID) error {
@@ -64,18 +66,62 @@ func (s *Controllers) ListDocumentsByClientId(ctx echo.Context, clientId ClientI
return ctx.JSON(http.StatusOK, docs)
}
func (s *Controllers) GetDocument(ctx echo.Context, id DocumentID) error {
document, err := s.svc.Document.GetExternal(ctx.Request().Context(), id)
// GetDocument retrieves document details by ID with enriched metadata.
// When textRecord=true, includes the full field extraction response.
func (s *Controllers) GetDocument(ctx echo.Context, id DocumentID, params GetDocumentParams) error {
includeTextRecord := params.TextRecord != nil && *params.TextRecord
document, err := s.svc.Document.GetEnriched(ctx.Request().Context(), uuid.UUID(id), includeTextRecord)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Unable to list documents: %s", err))
slog.Error("unable to get document", "error", err, "document_id", id)
return echo.NewHTTPError(http.StatusNotFound, fmt.Sprintf("Unable to get document: %s", err))
}
return ctx.JSON(http.StatusOK, Document{
Id: document.Id,
ClientId: document.ClientID,
Hash: document.Hash,
Fields: document.Fields,
})
// Convert labels to API format
labels := make([]LabelRecord, len(document.Labels))
for i, lbl := range document.Labels {
labels[i] = LabelRecord{
Id: openapi_types.UUID(lbl.ID),
DocumentId: DocumentID(lbl.DocumentID),
Label: lbl.Label,
AppliedBy: openapi_types.Email(lbl.AppliedBy),
AppliedAt: lbl.AppliedAt,
}
}
response := DocumentEnriched{
Id: DocumentID(document.ID),
ClientId: ClientID(document.ClientID),
Hash: Hash(document.Hash),
Fields: document.Fields,
HasTextRecord: document.HasTextRecord,
Labels: labels,
}
if document.FolderID != nil {
response.FolderId = (*openapi_types.UUID)(document.FolderID)
}
if document.Filename != nil {
response.Filename = document.Filename
}
if document.OriginalPath != nil {
response.OriginalPath = document.OriginalPath
}
// Include text record if requested and available
if document.TextRecord != nil {
// The TextRecord contains repository types that we need to convert
current, ok := document.TextRecord.SingleFields.(*repository.Currentfieldextraction)
if ok && current != nil {
arrayFields, ok := document.TextRecord.ArrayFields.([]*repository.Documentfieldextractionarrayfield)
if ok {
textRecord := buildFieldExtractionResponse(current, arrayFields)
response.TextRecord = textRecord
}
}
}
return ctx.JSON(http.StatusOK, response)
}
// ListDocumentBatches lists batch uploads for a client
+192 -6
View File
@@ -21,6 +21,7 @@ import (
queryapi "queryorchestration/api/queryAPI"
"queryorchestration/internal/database/repository"
"queryorchestration/internal/fieldextraction"
"queryorchestration/internal/test"
)
@@ -109,17 +110,202 @@ func TestGetDocument(t *testing.T) {
ctx, rec := createContext(t)
err = cons.GetDocument(ctx, docId)
err = cons.GetDocument(ctx, docId, queryapi.GetDocumentParams{})
require.NoError(t, err)
assert.Equal(t, http.StatusOK, rec.Code)
assertBody(t, rec, queryapi.Document{
Id: docId,
ClientId: "client_id",
Hash: "hash",
Fields: map[string]interface{}{},
assertBody(t, rec, queryapi.DocumentEnriched{
Id: docId,
ClientId: "client_id",
Hash: "hash",
Fields: map[string]interface{}{},
HasTextRecord: false,
Labels: []queryapi.LabelRecord{},
})
}
func TestGetDocumentWithEnrichedFields(t *testing.T) {
cfg := &ControllerConfig{}
test.CreateDB(t, cfg)
initializeTestConfig(t, cfg)
svc := createControllerServices(cfg)
cons := queryapi.NewControllers(svc, cfg)
// Create test client with root folder
test.CreateTestClient(t, cfg, "enriched_client", "Enriched Client")
// Create folder
folder, err := cfg.GetDBQueries().CreateFolder(t.Context(), &repository.CreateFolderParams{
Path: "/documents",
Clientid: "enriched_client",
Createdby: "testuser",
})
require.NoError(t, err)
// Create document with folder, filename, originalPath
filename := "test-document.pdf"
originalPath := "/uploads/test-document.pdf"
docId, err := cfg.GetDBQueries().CreateDocument(t.Context(), &repository.CreateDocumentParams{
Clientid: "enriched_client",
Hash: "enriched_hash",
Filename: &filename,
Originalpath: &originalPath,
Folderid: &folder.ID,
})
require.NoError(t, err)
// Add labels to document - use a label that exists in the lookup table
_, err = cfg.GetDBQueries().ApplyLabel(t.Context(), &repository.ApplyLabelParams{
Documentid: docId,
Label: "Ingested", // This label is seeded in migration
Appliedby: "testuser@example.com",
})
require.NoError(t, err)
ctx, rec := createContext(t)
// Test without textRecord parameter
err = cons.GetDocument(ctx, docId, queryapi.GetDocumentParams{})
require.NoError(t, err)
assert.Equal(t, http.StatusOK, rec.Code)
var result queryapi.DocumentEnriched
err = json.Unmarshal(rec.Body.Bytes(), &result)
require.NoError(t, err)
// Verify enriched fields
assert.Equal(t, docId, result.Id)
assert.Equal(t, queryapi.ClientID("enriched_client"), result.ClientId)
assert.Equal(t, queryapi.Hash("enriched_hash"), result.Hash)
assert.NotNil(t, result.Filename)
assert.Equal(t, filename, *result.Filename)
assert.NotNil(t, result.OriginalPath)
assert.Equal(t, originalPath, *result.OriginalPath)
assert.NotNil(t, result.FolderId)
assert.Equal(t, folder.ID.String(), result.FolderId.String())
assert.False(t, result.HasTextRecord)
assert.Nil(t, result.TextRecord)
// Verify labels
assert.Len(t, result.Labels, 1)
assert.Equal(t, "Ingested", result.Labels[0].Label)
assert.Equal(t, "testuser@example.com", string(result.Labels[0].AppliedBy))
}
func TestGetDocumentWithTextRecord(t *testing.T) {
cfg := &ControllerConfig{}
test.CreateDB(t, cfg)
initializeTestConfig(t, cfg)
svc := createControllerServices(cfg)
cons := queryapi.NewControllers(svc, cfg)
// Create test client with root folder
test.CreateTestClient(t, cfg, "textrecord_client", "TextRecord Client")
// Create document
filename := "contract.pdf"
docId, err := cfg.GetDBQueries().CreateDocument(t.Context(), &repository.CreateDocumentParams{
Clientid: "textrecord_client",
Hash: "textrecord_hash",
Filename: &filename,
})
require.NoError(t, err)
// Create field extraction using the fieldextraction service (which properly inserts into versions table)
fieldSvc := fieldextraction.New(cfg)
contractTitle := "Test Contract Title"
extractionUser := "extraction@example.com"
input := &fieldextraction.CreateFieldExtractionInput{
DocumentID: docId,
SingleFields: &repository.AddFieldExtractionParams{
Documentid: docId,
Filename: &filename,
Contracttitle: &contractTitle,
Createdby: extractionUser,
},
ArrayFields: []*repository.AddFieldExtractionArrayFieldParams{},
}
_, err = fieldSvc.CreateFieldExtraction(t.Context(), input)
require.NoError(t, err)
// Test with textRecord=true parameter
includeTextRecord := true
ctx, rec := createContext(t)
err = cons.GetDocument(ctx, docId, queryapi.GetDocumentParams{
TextRecord: &includeTextRecord,
})
require.NoError(t, err)
assert.Equal(t, http.StatusOK, rec.Code)
var result queryapi.DocumentEnriched
err = json.Unmarshal(rec.Body.Bytes(), &result)
require.NoError(t, err)
// Verify document has text record
assert.Equal(t, docId, result.Id)
assert.True(t, result.HasTextRecord)
assert.NotNil(t, result.TextRecord)
assert.Equal(t, int32(1), result.TextRecord.Version)
assert.Equal(t, extractionUser, string(result.TextRecord.CreatedBy))
assert.NotNil(t, result.TextRecord.SingleFields.ContractTitle)
assert.Equal(t, contractTitle, *result.TextRecord.SingleFields.ContractTitle)
}
func TestGetDocumentWithTextRecordNotRequested(t *testing.T) {
cfg := &ControllerConfig{}
test.CreateDB(t, cfg)
initializeTestConfig(t, cfg)
svc := createControllerServices(cfg)
cons := queryapi.NewControllers(svc, cfg)
// Create test client with root folder
test.CreateTestClient(t, cfg, "notext_client", "NoText Client")
// Create document
filename := "contract2.pdf"
docId, err := cfg.GetDBQueries().CreateDocument(t.Context(), &repository.CreateDocumentParams{
Clientid: "notext_client",
Hash: "notext_hash",
Filename: &filename,
})
require.NoError(t, err)
// Create field extraction using the fieldextraction service
fieldSvc := fieldextraction.New(cfg)
contractTitle := "Another Contract"
input := &fieldextraction.CreateFieldExtractionInput{
DocumentID: docId,
SingleFields: &repository.AddFieldExtractionParams{
Documentid: docId,
Filename: &filename,
Contracttitle: &contractTitle,
Createdby: "extraction2@example.com",
},
ArrayFields: []*repository.AddFieldExtractionArrayFieldParams{},
}
_, err = fieldSvc.CreateFieldExtraction(t.Context(), input)
require.NoError(t, err)
// Test without textRecord parameter (should still have hasTextRecord=true but no textRecord body)
ctx, rec := createContext(t)
err = cons.GetDocument(ctx, docId, queryapi.GetDocumentParams{})
require.NoError(t, err)
assert.Equal(t, http.StatusOK, rec.Code)
var result queryapi.DocumentEnriched
err = json.Unmarshal(rec.Body.Bytes(), &result)
require.NoError(t, err)
// Verify document indicates it has text record but doesn't include the full body
assert.Equal(t, docId, result.Id)
assert.True(t, result.HasTextRecord)
assert.Nil(t, result.TextRecord) // Not requested, so should be nil
}
func TestListDocumentBatches(t *testing.T) {
cfg := &ControllerConfig{}
test.CreateDB(t, cfg)
+51 -8
View File
@@ -70,21 +70,64 @@ func (s *Controllers) RenameFolder(ctx echo.Context, folderId openapi_types.UUID
return ctx.NoContent(http.StatusNoContent)
}
// GetFolderDocuments retrieves all documents in a specific folder.
// GetFolderDocuments retrieves all documents in a specific folder with enriched metadata.
// GET /folders/{folderId}/documents
// Returns a list of documents in the specified folder.
func (s *Controllers) GetFolderDocuments(ctx echo.Context, folderId openapi_types.UUID) error {
documents, err := s.svc.Folder.GetDocumentsByFolder(ctx.Request().Context(), uuid.UUID(folderId))
// Parameters:
// - folderId: UUID of the folder
// - params: Query parameters including optional textRecord flag
//
// When textRecord=true, includes the full field extraction response for each document.
// Returns a list of DocumentInFolder objects (lighter format excluding client_id and computed fields).
func (s *Controllers) GetFolderDocuments(ctx echo.Context, folderId openapi_types.UUID, params GetFolderDocumentsParams) error {
includeTextRecord := params.TextRecord != nil && *params.TextRecord
documents, err := s.svc.Folder.GetDocumentsEnriched(ctx.Request().Context(), uuid.UUID(folderId), includeTextRecord)
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, err.Error())
}
// Convert to API response format
apiDocs := make([]DocumentSummary, len(documents))
apiDocs := make([]DocumentInFolder, len(documents))
for i, doc := range documents {
apiDocs[i] = DocumentSummary{
Hash: doc.Hash,
Id: openapi_types.UUID(doc.ID),
// Convert labels to API format
labels := make([]LabelRecord, len(doc.Labels))
for j, lbl := range doc.Labels {
labels[j] = LabelRecord{
Id: openapi_types.UUID(lbl.ID),
DocumentId: DocumentID(lbl.DocumentID),
Label: lbl.Label,
AppliedBy: openapi_types.Email(lbl.AppliedBy),
AppliedAt: lbl.AppliedAt,
}
}
apiDocs[i] = DocumentInFolder{
Id: DocumentID(doc.ID),
Hash: Hash(doc.Hash),
HasTextRecord: doc.HasTextRecord,
Labels: labels,
}
if doc.FolderID != nil {
apiDocs[i].FolderId = (*openapi_types.UUID)(doc.FolderID)
}
if doc.Filename != nil {
apiDocs[i].Filename = doc.Filename
}
if doc.OriginalPath != nil {
apiDocs[i].OriginalPath = doc.OriginalPath
}
// Include text record if available
if doc.TextRecord != nil {
current, ok := doc.TextRecord.SingleFields.(*repository.Currentfieldextraction)
if ok && current != nil {
arrayFields, ok := doc.TextRecord.ArrayFields.([]*repository.Documentfieldextractionarrayfield)
if ok {
textRecord := buildFieldExtractionResponse(current, arrayFields)
apiDocs[i].TextRecord = textRecord
}
}
}
}
+4 -4
View File
@@ -302,12 +302,12 @@ func TestGetFolderDocuments_Success(t *testing.T) {
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)
err = ctrl.GetFolderDocuments(c, openapi_types.UUID(folderRec.ID))
err = ctrl.GetFolderDocuments(c, openapi_types.UUID(folderRec.ID), queryapi.GetFolderDocumentsParams{})
require.NoError(t, err)
assert.Equal(t, http.StatusOK, rec.Code)
var resp struct {
Documents []queryapi.DocumentSummary `json:"documents"`
Documents []queryapi.DocumentInFolder `json:"documents"`
}
err = json.Unmarshal(rec.Body.Bytes(), &resp)
require.NoError(t, err)
@@ -340,12 +340,12 @@ func TestGetFolderDocuments_EmptyFolder(t *testing.T) {
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)
err = ctrl.GetFolderDocuments(c, openapi_types.UUID(folderRec.ID))
err = ctrl.GetFolderDocuments(c, openapi_types.UUID(folderRec.ID), queryapi.GetFolderDocumentsParams{})
require.NoError(t, err)
assert.Equal(t, http.StatusOK, rec.Code)
var resp struct {
Documents []queryapi.DocumentSummary `json:"documents"`
Documents []queryapi.DocumentInFolder `json:"documents"`
}
err = json.Unmarshal(rec.Body.Bytes(), &resp)
require.NoError(t, err)