import { afterEach, describe, expect, it } from "vitest"; import { requireNodeSqlite } from "./node-sqlite.js"; import { runSqliteImmediateTransactionSync } from "./sqlite-transaction.js"; const openDatabases: Array = []; function createDatabase(): import("node:sqlite").DatabaseSync { const { DatabaseSync } = requireNodeSqlite(); const db = new DatabaseSync(":memory:"); db.exec("CREATE TABLE entries (id TEXT NOT NULL PRIMARY KEY, value TEXT NOT NULL);"); openDatabases.push(db); return db; } function readEntries(db: import("node:sqlite").DatabaseSync): string[] { return db .prepare("SELECT id FROM entries ORDER BY id") .all() .map((row) => (row as { id: string }).id); } afterEach(() => { for (const db of openDatabases.splice(0)) { db.close(); } }); describe("runSqliteImmediateTransactionSync", () => { it("keeps outer writes when a nested savepoint rolls back", () => { const db = createDatabase(); runSqliteImmediateTransactionSync(db, () => { db.prepare("INSERT INTO entries(id, value) VALUES (?, ?)").run("outer", "kept"); expect(() => runSqliteImmediateTransactionSync(db, () => { db.prepare("INSERT INTO entries(id, value) VALUES (?, ?)").run("inner", "rolled back"); throw new Error("nested failure"); }), ).toThrow("nested failure"); }); expect(readEntries(db)).toEqual(["outer"]); }); it("commits nested savepoint writes with the outer transaction", () => { const db = createDatabase(); runSqliteImmediateTransactionSync(db, () => { db.prepare("INSERT INTO entries(id, value) VALUES (?, ?)").run("outer", "kept"); runSqliteImmediateTransactionSync(db, () => { db.prepare("INSERT INTO entries(id, value) VALUES (?, ?)").run("inner", "kept"); }); }); expect(readEntries(db)).toEqual(["inner", "outer"]); }); it("rejects Promise-returning operations and rolls back their synchronous writes", () => { const db = createDatabase(); expect(() => runSqliteImmediateTransactionSync(db, async () => { db.prepare("INSERT INTO entries(id, value) VALUES (?, ?)").run("async", "rolled back"); return "done"; }), ).toThrow("must be synchronous"); expect(readEntries(db)).toEqual([]); runSqliteImmediateTransactionSync(db, () => { db.prepare("INSERT INTO entries(id, value) VALUES (?, ?)").run("after", "works"); }); expect(readEntries(db)).toEqual(["after"]); }); });