fix: verify sqlite-vec readiness after extension load. Closes #169

This commit is contained in:
Claude 2026-02-13 19:20:55 -05:00 committed by Tobi Lütke
parent 96643a28ed
commit 73136e4f59
No known key found for this signature in database
2 changed files with 56 additions and 6 deletions

View File

@ -8,6 +8,7 @@
import { describe, test, expect, beforeAll, afterAll, beforeEach, afterEach, mock, spyOn } from "bun:test";
import { Database } from "bun:sqlite";
import * as sqliteVec from "sqlite-vec";
import { unlink, mkdtemp, rmdir, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
@ -15,6 +16,7 @@ import YAML from "yaml";
import { disposeDefaultLlamaCpp } from "./llm.js";
import {
createStore,
verifySqliteVecLoaded,
getDefaultDbPath,
homedir,
resolve,
@ -452,6 +454,25 @@ describe("Store Creation", () => {
await cleanupTestDb(store);
});
test("verifySqliteVecLoaded throws when sqlite-vec is not loaded", () => {
const db = new Database(":memory:");
try {
expect(() => verifySqliteVecLoaded(db)).toThrow("sqlite-vec extension is unavailable");
} finally {
db.close();
}
});
test("verifySqliteVecLoaded succeeds when sqlite-vec is loaded", () => {
const db = new Database(":memory:");
try {
sqliteVec.load(db);
expect(() => verifySqliteVecLoaded(db)).not.toThrow();
} finally {
db.close();
}
});
test("store.close closes the database connection", async () => {
const store = await createTestStore();
store.close();

View File

@ -458,17 +458,46 @@ function setSQLiteFromBrewPrefixEnv(): void {
setSQLiteFromBrewPrefixEnv();
function createSqliteVecUnavailableError(reason: string): Error {
return new Error(
"sqlite-vec extension is unavailable. " +
`${reason}. ` +
"Install Homebrew SQLite so the sqlite-vec extension can be loaded, " +
"and set BREW_PREFIX if Homebrew is installed in a non-standard location."
);
}
function getErrorMessage(err: unknown): string {
return err instanceof Error ? err.message : String(err);
}
export function verifySqliteVecLoaded(db: Database): void {
try {
const row = db.prepare(`SELECT vec_version() AS version`).get() as { version?: string } | null;
if (!row?.version || typeof row.version !== "string") {
throw new Error("vec_version() returned no version");
}
} catch (err) {
const message = getErrorMessage(err);
throw createSqliteVecUnavailableError(`sqlite-vec probe failed (${message})`);
}
}
function initializeDatabase(db: Database): void {
try {
sqliteVec.load(db);
verifySqliteVecLoaded(db);
} catch (err) {
if (err instanceof Error && err.message.includes("does not support dynamic extension loading")) {
throw new Error(
"SQLite build does not support dynamic extension loading. " +
"Install Homebrew SQLite so the sqlite-vec extension can be loaded, " +
"and set BREW_PREFIX if Homebrew is installed in a non-standard location."
);
const message = getErrorMessage(err);
if (message.includes("does not support dynamic extension loading")) {
throw createSqliteVecUnavailableError("SQLite build does not support dynamic extension loading");
}
if (message.includes("sqlite-vec extension is unavailable")) {
throw err;
}
throw err;
}
db.exec("PRAGMA journal_mode = WAL");