Files
query-orchestration/internal/folder/service.go
T
Jay Brown c45e1dd427 Merged in feature/textExtractionsPart1 (pull request #192)
all schema and rest apis for text extraction support

* in progress

* stage 8 complete

* phase 9 completed

* phase 9 complete

* ongoing - s3 path fix

* working

* optimize ci build

* e2e tests

* missing test
2025-11-26 19:23:42 +00:00

201 lines
5.7 KiB
Go

package folder
import (
"context"
"fmt"
"queryorchestration/internal/database/repository"
"queryorchestration/internal/serviceconfig"
"github.com/google/uuid"
)
// Service provides folder management operations
type Service struct {
cfg serviceconfig.ConfigProvider
}
// New creates a new folder service instance
func New(cfg serviceconfig.ConfigProvider) *Service {
return &Service{
cfg: cfg,
}
}
// CreateFolder creates a new folder with validation
// Validates that parent folder exists if parentId is provided
func (s *Service) CreateFolder(ctx context.Context, path string, parentID *uuid.UUID, clientID string, createdBy string) (*repository.Folder, error) {
if path == "" {
return nil, fmt.Errorf("folder path cannot be empty")
}
if clientID == "" {
return nil, fmt.Errorf("clientID cannot be empty")
}
if createdBy == "" {
return nil, fmt.Errorf("createdBy cannot be empty")
}
// Validate parent folder exists if parentID is provided
if parentID != nil {
parent, err := s.cfg.GetDBQueries().GetFolderByID(ctx, *parentID)
if err != nil {
return nil, fmt.Errorf("parent folder not found: %w", err)
}
// Ensure parent belongs to same client
if parent.Clientid != clientID {
return nil, fmt.Errorf("parent folder belongs to different client")
}
}
folder, err := s.cfg.GetDBQueries().CreateFolder(ctx, &repository.CreateFolderParams{
Path: path,
Parentid: parentID,
Clientid: clientID,
Createdby: createdBy,
})
if err != nil {
return nil, fmt.Errorf("failed to create folder: %w", err)
}
return folder, nil
}
// GetFolder retrieves a folder by ID
func (s *Service) GetFolder(ctx context.Context, folderID uuid.UUID) (*repository.Folder, error) {
folder, err := s.cfg.GetDBQueries().GetFolderByID(ctx, folderID)
if err != nil {
return nil, fmt.Errorf("folder not found: %w", err)
}
return folder, nil
}
// GetFolderByPath retrieves a folder by client and path
func (s *Service) GetFolderByPath(ctx context.Context, clientID string, path string) (*repository.Folder, error) {
folder, err := s.cfg.GetDBQueries().GetFolderByPath(ctx, &repository.GetFolderByPathParams{
Clientid: clientID,
Path: path,
})
if err != nil {
return nil, fmt.Errorf("folder not found: %w", err)
}
return folder, nil
}
// RenameFolder renames a folder
func (s *Service) RenameFolder(ctx context.Context, folderID uuid.UUID, newPath string) error {
if newPath == "" {
return fmt.Errorf("new path cannot be empty")
}
// Verify folder exists
_, err := s.cfg.GetDBQueries().GetFolderByID(ctx, folderID)
if err != nil {
return fmt.Errorf("folder not found: %w", err)
}
err = s.cfg.GetDBQueries().RenameFolder(ctx, &repository.RenameFolderParams{
ID: folderID,
Path: newPath,
})
if err != nil {
return fmt.Errorf("failed to rename folder: %w", err)
}
return nil
}
// GetFolderTree retrieves a folder and all its descendants (recursive)
func (s *Service) GetFolderTree(ctx context.Context, folderID uuid.UUID) ([]*repository.GetFolderTreeRow, error) {
folders, err := s.cfg.GetDBQueries().GetFolderTree(ctx, &folderID)
if err != nil {
return nil, fmt.Errorf("failed to get folder tree: %w", err)
}
return folders, nil
}
// GetFoldersByClient retrieves all folders for a client
func (s *Service) GetFoldersByClient(ctx context.Context, clientID string) ([]*repository.Folder, error) {
folders, err := s.cfg.GetDBQueries().GetFoldersByClientID(ctx, clientID)
if err != nil {
return nil, fmt.Errorf("failed to get folders: %w", err)
}
return folders, nil
}
// GetRootFolders retrieves all root folders (parentId IS NULL) for a client
func (s *Service) GetRootFolders(ctx context.Context, clientID string) ([]*repository.Folder, error) {
folders, err := s.cfg.GetDBQueries().GetRootFolders(ctx, clientID)
if err != nil {
return nil, fmt.Errorf("failed to get root folders: %w", err)
}
return folders, nil
}
// GetSubfolders retrieves direct child folders of a parent folder
func (s *Service) GetSubfolders(ctx context.Context, parentID uuid.UUID) ([]*repository.Folder, error) {
folders, err := s.cfg.GetDBQueries().GetFoldersByParentID(ctx, &parentID)
if err != nil {
return nil, fmt.Errorf("failed to get subfolders: %w", err)
}
return folders, nil
}
// GetDocumentsByFolder retrieves all documents in a specific folder
func (s *Service) GetDocumentsByFolder(ctx context.Context, folderID uuid.UUID) ([]*repository.Document, error) {
documents, err := s.cfg.GetDBQueries().GetDocumentsByFolder(ctx, &folderID)
if err != nil {
return nil, fmt.Errorf("failed to get documents by folder: %w", err)
}
return documents, nil
}
// FolderMetrics contains aggregated metrics for a folder
type FolderMetrics struct {
TotalDocuments int32
ByLabel map[string]int32
}
// GetFolderMetrics retrieves processing metrics for a folder including document counts by label
func (s *Service) GetFolderMetrics(ctx context.Context, folderID uuid.UUID) (*FolderMetrics, error) {
// Get total document count
total, err := s.cfg.GetDBQueries().CountDocumentsByFolder(ctx, &folderID)
if err != nil {
return nil, fmt.Errorf("failed to count documents: %w", err)
}
// Get label counts
labelCounts, err := s.cfg.GetDBQueries().GetFolderLabelCounts(ctx, &folderID)
if err != nil {
return nil, fmt.Errorf("failed to get label counts: %w", err)
}
byLabel := make(map[string]int32)
for _, lc := range labelCounts {
byLabel[lc.Label] = safeInt64ToInt32(lc.Count)
}
return &FolderMetrics{
TotalDocuments: safeInt64ToInt32(total),
ByLabel: byLabel,
}, nil
}
// safeInt64ToInt32 safely converts int64 to int32, clamping at max int32 if necessary
func safeInt64ToInt32(n int64) int32 {
const maxInt32 = 2147483647
if n > maxInt32 {
return maxInt32
}
return int32(n) //nolint:gosec // bounds check performed above
}