| import type { DatabaseSync } from "node:sqlite"; |
|
|
| export function ensureMemoryIndexSchema(params: { |
| db: DatabaseSync; |
| embeddingCacheTable: string; |
| ftsTable: string; |
| ftsEnabled: boolean; |
| }): { ftsAvailable: boolean; ftsError?: string } { |
| params.db.exec(` |
| CREATE TABLE IF NOT EXISTS meta ( |
| key TEXT PRIMARY KEY, |
| value TEXT NOT NULL |
| ); |
| `); |
| params.db.exec(` |
| CREATE TABLE IF NOT EXISTS files ( |
| path TEXT PRIMARY KEY, |
| source TEXT NOT NULL DEFAULT 'memory', |
| hash TEXT NOT NULL, |
| mtime INTEGER NOT NULL, |
| size INTEGER NOT NULL |
| ); |
| `); |
| params.db.exec(` |
| CREATE TABLE IF NOT EXISTS chunks ( |
| id TEXT PRIMARY KEY, |
| path TEXT NOT NULL, |
| source TEXT NOT NULL DEFAULT 'memory', |
| start_line INTEGER NOT NULL, |
| end_line INTEGER NOT NULL, |
| hash TEXT NOT NULL, |
| model TEXT NOT NULL, |
| text TEXT NOT NULL, |
| embedding TEXT NOT NULL, |
| updated_at INTEGER NOT NULL |
| ); |
| `); |
| params.db.exec(` |
| CREATE TABLE IF NOT EXISTS ${params.embeddingCacheTable} ( |
| provider TEXT NOT NULL, |
| model TEXT NOT NULL, |
| provider_key TEXT NOT NULL, |
| hash TEXT NOT NULL, |
| embedding TEXT NOT NULL, |
| dims INTEGER, |
| updated_at INTEGER NOT NULL, |
| PRIMARY KEY (provider, model, provider_key, hash) |
| ); |
| `); |
| params.db.exec( |
| `CREATE INDEX IF NOT EXISTS idx_embedding_cache_updated_at ON ${params.embeddingCacheTable}(updated_at);`, |
| ); |
|
|
| let ftsAvailable = false; |
| let ftsError: string | undefined; |
| if (params.ftsEnabled) { |
| try { |
| params.db.exec( |
| `CREATE VIRTUAL TABLE IF NOT EXISTS ${params.ftsTable} USING fts5(\n` + |
| ` text,\n` + |
| ` id UNINDEXED,\n` + |
| ` path UNINDEXED,\n` + |
| ` source UNINDEXED,\n` + |
| ` model UNINDEXED,\n` + |
| ` start_line UNINDEXED,\n` + |
| ` end_line UNINDEXED\n` + |
| `);`, |
| ); |
| ftsAvailable = true; |
| } catch (err) { |
| const message = err instanceof Error ? err.message : String(err); |
| ftsAvailable = false; |
| ftsError = message; |
| } |
| } |
|
|
| ensureColumn(params.db, "files", "source", "TEXT NOT NULL DEFAULT 'memory'"); |
| ensureColumn(params.db, "chunks", "source", "TEXT NOT NULL DEFAULT 'memory'"); |
| params.db.exec(`CREATE INDEX IF NOT EXISTS idx_chunks_path ON chunks(path);`); |
| params.db.exec(`CREATE INDEX IF NOT EXISTS idx_chunks_source ON chunks(source);`); |
|
|
| return { ftsAvailable, ...(ftsError ? { ftsError } : {}) }; |
| } |
|
|
| function ensureColumn( |
| db: DatabaseSync, |
| table: "files" | "chunks", |
| column: string, |
| definition: string, |
| ): void { |
| const rows = db.prepare(`PRAGMA table_info(${table})`).all() as Array<{ name: string }>; |
| if (rows.some((row) => row.name === column)) { |
| return; |
| } |
| db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${definition}`); |
| } |
|
|