155 lines
4.8 KiB
Go
155 lines
4.8 KiB
Go
|
|
package fieldextraction
|
||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"fmt"
|
||
|
|
|
||
|
|
"queryorchestration/internal/database/repository"
|
||
|
|
"queryorchestration/internal/serviceconfig"
|
||
|
|
|
||
|
|
"github.com/google/uuid"
|
||
|
|
"github.com/jackc/pgx/v5"
|
||
|
|
)
|
||
|
|
|
||
|
|
// Service provides field extraction operations
|
||
|
|
type Service struct {
|
||
|
|
cfg serviceconfig.ConfigProvider
|
||
|
|
}
|
||
|
|
|
||
|
|
// New creates a new field extraction service
|
||
|
|
func New(cfg serviceconfig.ConfigProvider) *Service {
|
||
|
|
return &Service{cfg: cfg}
|
||
|
|
}
|
||
|
|
|
||
|
|
// CreateFieldExtraction creates a new field extraction with all single and array fields
|
||
|
|
// in a single transaction. All array fields must have consistent length.
|
||
|
|
// Returns the created field extraction record.
|
||
|
|
func (s *Service) CreateFieldExtraction(ctx context.Context, input *CreateFieldExtractionInput) (*repository.Documentfieldextraction, error) {
|
||
|
|
if input == nil {
|
||
|
|
return nil, fmt.Errorf("input cannot be nil")
|
||
|
|
}
|
||
|
|
|
||
|
|
if input.DocumentID == uuid.Nil {
|
||
|
|
return nil, fmt.Errorf("documentID cannot be nil")
|
||
|
|
}
|
||
|
|
|
||
|
|
if input.SingleFields == nil {
|
||
|
|
return nil, fmt.Errorf("singleFields cannot be nil")
|
||
|
|
}
|
||
|
|
|
||
|
|
if input.SingleFields.Createdby == "" {
|
||
|
|
return nil, fmt.Errorf("createdBy cannot be empty")
|
||
|
|
}
|
||
|
|
|
||
|
|
// Validate array consistency
|
||
|
|
_, err := ValidateArrayConsistency(input.ArrayFields)
|
||
|
|
if err != nil {
|
||
|
|
return nil, fmt.Errorf("array validation failed: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Begin transaction
|
||
|
|
tx, err := s.cfg.GetDBPool().Begin(ctx)
|
||
|
|
if err != nil {
|
||
|
|
return nil, fmt.Errorf("failed to begin transaction: %w", err)
|
||
|
|
}
|
||
|
|
defer func() {
|
||
|
|
_ = tx.Rollback(ctx)
|
||
|
|
}()
|
||
|
|
|
||
|
|
queries := s.cfg.GetDBQueries().WithTx(tx)
|
||
|
|
|
||
|
|
// Set document ID in single fields
|
||
|
|
input.SingleFields.Documentid = input.DocumentID
|
||
|
|
|
||
|
|
// Create main field extraction record with single fields
|
||
|
|
fieldExtraction, err := queries.AddFieldExtraction(ctx, input.SingleFields)
|
||
|
|
if err != nil {
|
||
|
|
return nil, fmt.Errorf("failed to create field extraction: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Get the next version number for this document
|
||
|
|
history, err := queries.GetFieldExtractionsByDocumentID(ctx, input.DocumentID)
|
||
|
|
if err != nil {
|
||
|
|
return nil, fmt.Errorf("failed to get field extraction history: %w", err)
|
||
|
|
}
|
||
|
|
version := int64(len(history))
|
||
|
|
|
||
|
|
// Create version entry
|
||
|
|
err = queries.AddFieldExtractionEntry(ctx, &repository.AddFieldExtractionEntryParams{
|
||
|
|
Fieldextractionid: fieldExtraction.ID,
|
||
|
|
Version: version,
|
||
|
|
Createdby: input.SingleFields.Createdby,
|
||
|
|
})
|
||
|
|
if err != nil {
|
||
|
|
return nil, fmt.Errorf("failed to create field extraction version entry: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Insert all array field rows
|
||
|
|
for arrayIndex, arrayField := range input.ArrayFields {
|
||
|
|
// Set field extraction ID and array index
|
||
|
|
arrayField.Fieldextractionid = fieldExtraction.ID
|
||
|
|
//nolint:gosec // Array index is expected to be small, int16 is sufficient
|
||
|
|
arrayField.Arrayindex = int16(arrayIndex)
|
||
|
|
|
||
|
|
err = queries.AddFieldExtractionArrayField(ctx, arrayField)
|
||
|
|
if err != nil {
|
||
|
|
return nil, fmt.Errorf("failed to create array field at index %d: %w", arrayIndex, err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Commit transaction
|
||
|
|
if err := tx.Commit(ctx); err != nil {
|
||
|
|
return nil, fmt.Errorf("failed to commit transaction: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
return fieldExtraction, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// GetCurrentFieldExtraction retrieves the most recent field extraction for a document
|
||
|
|
// Returns nil if no field extraction exists for the document
|
||
|
|
func (s *Service) GetCurrentFieldExtraction(ctx context.Context, documentID uuid.UUID) (*repository.Currentfieldextraction, error) {
|
||
|
|
if documentID == uuid.Nil {
|
||
|
|
return nil, fmt.Errorf("documentID cannot be nil")
|
||
|
|
}
|
||
|
|
|
||
|
|
fieldExtraction, err := s.cfg.GetDBQueries().GetCurrentFieldExtraction(ctx, documentID)
|
||
|
|
if err != nil {
|
||
|
|
if err == pgx.ErrNoRows {
|
||
|
|
return nil, nil
|
||
|
|
}
|
||
|
|
return nil, fmt.Errorf("failed to get current field extraction: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
return fieldExtraction, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// GetFieldExtractionHistory retrieves all field extraction versions for a document
|
||
|
|
// ordered by version (most recent first)
|
||
|
|
func (s *Service) GetFieldExtractionHistory(ctx context.Context, documentID uuid.UUID) ([]*repository.GetFieldExtractionHistoryRow, error) {
|
||
|
|
if documentID == uuid.Nil {
|
||
|
|
return nil, fmt.Errorf("documentID cannot be nil")
|
||
|
|
}
|
||
|
|
|
||
|
|
history, err := s.cfg.GetDBQueries().GetFieldExtractionHistory(ctx, documentID)
|
||
|
|
if err != nil {
|
||
|
|
return nil, fmt.Errorf("failed to get field extraction history: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
return history, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// GetFieldExtractionArrayFields retrieves all array fields for a specific field extraction
|
||
|
|
// ordered by arrayIndex
|
||
|
|
func (s *Service) GetFieldExtractionArrayFields(ctx context.Context, fieldExtractionID uuid.UUID) ([]*repository.Documentfieldextractionarrayfield, error) {
|
||
|
|
if fieldExtractionID == uuid.Nil {
|
||
|
|
return nil, fmt.Errorf("fieldExtractionID cannot be nil")
|
||
|
|
}
|
||
|
|
|
||
|
|
arrayFields, err := s.cfg.GetDBQueries().GetFieldExtractionArrayFields(ctx, fieldExtractionID)
|
||
|
|
if err != nil {
|
||
|
|
return nil, fmt.Errorf("failed to get array fields: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
return arrayFields, nil
|
||
|
|
}
|