( projectRoot: string, embeddingModel: string, chunks: Chunk[], )
| 103 | * index at the path. Returns false if better-sqlite3 can't be loaded. |
| 104 | */ |
| 105 | export async function buildSqliteIndex( |
| 106 | projectRoot: string, |
| 107 | embeddingModel: string, |
| 108 | chunks: Chunk[], |
| 109 | ): Promise<boolean> { |
| 110 | const Database = await loadSqlite(); |
| 111 | if (!Database) return false; |
| 112 | |
| 113 | const p = sqliteIndexPath(projectRoot, embeddingModel); |
| 114 | await fs.mkdir(path.dirname(p), { recursive: true }); |
| 115 | // Remove stale file so we never half-overwrite. |
| 116 | try { await fs.unlink(p); } catch { /* none */ } |
| 117 | |
| 118 | const db = new Database(p); |
| 119 | db.pragma('journal_mode = WAL'); |
| 120 | db.exec(` |
| 121 | CREATE TABLE meta (key TEXT PRIMARY KEY, value TEXT); |
| 122 | CREATE TABLE chunks ( |
| 123 | id INTEGER PRIMARY KEY, |
| 124 | file TEXT, start_line INTEGER, end_line INTEGER, |
| 125 | symbol TEXT, text TEXT, hash TEXT, |
| 126 | scale REAL, vec BLOB |
| 127 | ); |
| 128 | `); |
| 129 | |
| 130 | const dims = chunks.find(c => c.embedding)?.embedding?.length ?? 0; |
| 131 | const insertMeta = db.prepare('INSERT INTO meta(key,value) VALUES (?,?)'); |
| 132 | insertMeta.run('projectRoot', projectRoot); |
| 133 | insertMeta.run('embeddingModel', embeddingModel); |
| 134 | insertMeta.run('dims', String(dims)); |
| 135 | insertMeta.run('builtAt', String(Date.now())); |
| 136 | |
| 137 | const insertChunk = db.prepare( |
| 138 | 'INSERT INTO chunks(id,file,start_line,end_line,symbol,text,hash,scale,vec) VALUES (?,?,?,?,?,?,?,?,?)', |
| 139 | ); |
| 140 | const tx = db.transaction((rows: Chunk[]) => { |
| 141 | let id = 0; |
| 142 | for (const c of rows) { |
| 143 | if (!c.embedding || c.embedding.length === 0) continue; |
| 144 | const q = quantize(c.embedding); |
| 145 | insertChunk.run( |
| 146 | id++, c.file, c.startLine, c.endLine, c.symbol ?? null, |
| 147 | c.text, c.hash, q.scale, Buffer.from(q.bytes.buffer), |
| 148 | ); |
| 149 | } |
| 150 | }); |
| 151 | tx(chunks); |
| 152 | db.close(); |
| 153 | return true; |
| 154 | } |
| 155 | |
| 156 | export async function openSqliteIndex( |
| 157 | projectRoot: string, |
no test coverage detected