CI / install-and-build (pull_request) Successful in 1m29s
CI / format (pull_request) Successful in 51s
CI / typecheck-source (pull_request) Successful in 41s
CI / typecheck-tests (pull_request) Successful in 39s
CI / test (pull_request) Successful in 51s
CI / lint (pull_request) Successful in 21s
Co-Authored-By: gpt-5.6-terra <noreply@openai.com>
124 lines
3.9 KiB
TypeScript
124 lines
3.9 KiB
TypeScript
import { describe, it, before, after } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { WrappedNodeSqliteDb } from "../../../src/db/sqlite/impl/node-sqlite.js";
|
|
import { sql, unsafeSql } from "../../../src/db/sqlite/sql.js";
|
|
import type { WrappedDb } from "../../../src/db/sqlite/impl/types.js";
|
|
|
|
function runWrappedDbSuite(name: string, makeDb: () => WrappedDb) {
|
|
describe(`${name}: WrappedDb`, () => {
|
|
let db: WrappedDb;
|
|
|
|
before(() => {
|
|
db = makeDb();
|
|
db.run(
|
|
unsafeSql(
|
|
"CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY, val TEXT NOT NULL)",
|
|
),
|
|
);
|
|
});
|
|
|
|
after(() => db.destroy());
|
|
|
|
it("run INSERT returns changes count", () => {
|
|
const { changes } = db.run(
|
|
sql`INSERT INTO test(val) VALUES(${{ text: "hello" }})`,
|
|
);
|
|
assert.equal(changes, 1);
|
|
});
|
|
|
|
it("all SELECT returns all rows", () => {
|
|
db.run(unsafeSql("DELETE FROM test"));
|
|
db.run(sql`INSERT INTO test(val) VALUES(${{ text: "a" }})`);
|
|
db.run(sql`INSERT INTO test(val) VALUES(${{ text: "b" }})`);
|
|
const rows = db.all<{ val: string }>(
|
|
unsafeSql("SELECT val FROM test ORDER BY val"),
|
|
);
|
|
assert.equal(rows.length, 2);
|
|
assert.equal(rows[0].val, "a");
|
|
assert.equal(rows[1].val, "b");
|
|
});
|
|
|
|
it("get returns single row or null", () => {
|
|
db.run(unsafeSql("DELETE FROM test"));
|
|
db.run(sql`INSERT INTO test(val) VALUES(${{ text: "one" }})`);
|
|
const row = db.get<{ val: string }>(unsafeSql("SELECT val FROM test"));
|
|
assert.ok(row !== null);
|
|
assert.equal(row.val, "one");
|
|
|
|
const none = db.get<{ val: string }>(
|
|
sql`SELECT val FROM test WHERE val = ${{ text: "none" }}`,
|
|
);
|
|
assert.equal(none, null);
|
|
});
|
|
|
|
it("get throws when multiple rows match", () => {
|
|
db.run(unsafeSql("DELETE FROM test"));
|
|
db.run(sql`INSERT INTO test(val) VALUES(${{ text: "dup1" }})`);
|
|
db.run(sql`INSERT INTO test(val) VALUES(${{ text: "dup2" }})`);
|
|
assert.throws(
|
|
() => db.get<{ val: string }>(unsafeSql("SELECT val FROM test")),
|
|
/Multiple results/,
|
|
);
|
|
});
|
|
|
|
it("multi commits on success", () => {
|
|
db.run(unsafeSql("DELETE FROM test"));
|
|
db.multi(() => {
|
|
db.run(sql`INSERT INTO test(val) VALUES(${{ text: "in-tx" }})`);
|
|
});
|
|
const rows = db.all<{ val: string }>(unsafeSql("SELECT val FROM test"));
|
|
assert.equal(rows.length, 1);
|
|
assert.equal(rows[0].val, "in-tx");
|
|
});
|
|
|
|
it("multi rolls back on error", () => {
|
|
db.run(unsafeSql("DELETE FROM test"));
|
|
assert.throws(() =>
|
|
db.multi(() => {
|
|
db.run(sql`INSERT INTO test(val) VALUES(${{ text: "rollback" }})`);
|
|
throw new Error("abort!");
|
|
}),
|
|
);
|
|
const rows = db.all<{ val: string }>(unsafeSql("SELECT val FROM test"));
|
|
assert.equal(rows.length, 0);
|
|
});
|
|
|
|
it("rethrow passes through return value", () => {
|
|
const result = db.rethrow(() => 42);
|
|
assert.equal(result, 42);
|
|
});
|
|
|
|
it("rethrow propagates non-SQLite errors unchanged", () => {
|
|
const err = new Error("custom error");
|
|
assert.throws(
|
|
() =>
|
|
db.rethrow(() => {
|
|
throw err;
|
|
}),
|
|
(e) => e === err,
|
|
);
|
|
});
|
|
});
|
|
}
|
|
|
|
runWrappedDbSuite("node-sqlite", () => new WrappedNodeSqliteDb(":memory:"));
|
|
|
|
describe("better-sqlite3 WrappedDb", async () => {
|
|
let bs3Ctor: (new (path: string) => WrappedDb) | null = null;
|
|
|
|
try {
|
|
const mod = await import("../../../src/db/sqlite/impl/better-sqlite3.js");
|
|
bs3Ctor = mod.WrappedBetterSqlite3Db;
|
|
} catch {
|
|
// better-sqlite3 not available, skip
|
|
}
|
|
|
|
if (bs3Ctor) {
|
|
runWrappedDbSuite("better-sqlite3", () => new bs3Ctor!(":memory:"));
|
|
} else {
|
|
it("better-sqlite3 is not available - skipped", (t) => {
|
|
t.skip("better-sqlite3 optional dependency not found");
|
|
});
|
|
}
|
|
});
|