/** * Database Service Interface * * Defines the contract for database implementations. * Currently implemented by LibSQLDatabase. */ import { Context, Effect } from "effect"; import type { DatabaseError, Document, PDFChunk, SearchOptions, SearchResult, } from "../types.js"; // ============================================================================ // Service Definition // ============================================================================ export class Database extends Context.Tag("Database")< Database, { // Document operations readonly addDocument: (doc: Document) => Effect.Effect; readonly getDocument: ( id: string ) => Effect.Effect; readonly getDocumentByPath: ( path: string ) => Effect.Effect; readonly listDocuments: ( tag?: string ) => Effect.Effect; readonly deleteDocument: (id: string) => Effect.Effect; readonly updateTags: ( id: string, tags: string[] ) => Effect.Effect; // Chunk operations readonly addChunks: ( chunks: Array<{ id: string; docId: string; page: number; chunkIndex: number; content: string; }> ) => Effect.Effect; readonly getChunk: ( chunkId: string ) => Effect.Effect; readonly listChunksByDocument: ( docId: string, opts?: { page?: number } ) => Effect.Effect; readonly addEmbeddings: ( embeddings: Array<{ chunkId: string; embedding: number[] }> ) => Effect.Effect; // Atomic rebuild/replace (non-destructive): replace a document's chunks+embeddings // in a single transaction so agents can safely rerun chunking algorithms. readonly replaceDocument: ( doc: Document, chunks: Array<{ id: string; docId: string; page: number; chunkIndex: number; content: string; }>, embeddings: Array<{ chunkId: string; embedding: number[] }>, ) => Effect.Effect; // Search operations readonly vectorSearch: ( embedding: number[], options?: SearchOptions ) => Effect.Effect; readonly ftsSearch: ( query: string, options?: SearchOptions ) => Effect.Effect; // Context expansion readonly getExpandedContext: ( docId: string, page: number, chunkIndex: number, options?: { maxChars?: number; direction?: "before" | "after" | "both" } ) => Effect.Effect< { content: string; startChunk: string; endChunk: string }, DatabaseError >; // Stats readonly getStats: () => Effect.Effect< { documents: number; chunks: number; embeddings: number }, DatabaseError >; // Cheap aggregation helpers (avoid loading full chunk content into memory) readonly countChunksByDocumentIds: ( docIds: string[] ) => Effect.Effect, DatabaseError>; // Maintenance readonly repair: () => Effect.Effect< { orphanedChunks: number; orphanedEmbeddings: number; zeroVectorEmbeddings: number; }, DatabaseError >; // WAL management (libSQL syncs automatically, but interface kept for compatibility) readonly checkpoint: () => Effect.Effect; // Backup/restore readonly dumpDataDir: () => Effect.Effect; // Streaming operations (for large datasets) readonly streamEmbeddings: ( batchSize: number ) => AsyncGenerator< Array<{ chunkId: string; embedding: number[] }>, void, unknown >; // Bulk operations (for batch processing) readonly bulkInsertClusterAssignments: ( assignments: Array<{ chunkId: string; clusterId: number; distance: number; }> ) => Effect.Effect; } >() {}