| |
| |
| import { PRAGMA_SQL } from "../schema.js"; |
|
|
| const CHECKPOINT_INTERVAL_MS = 60 * 1000; |
|
|
| export async function createNodeSqliteAdapter(filePath) { |
| |
| |
| const origEmit = process.emit; |
| process.emit = function (name, data, ...rest) { |
| if (name === "warning" && data?.name === "ExperimentalWarning" && /SQLite/i.test(data.message || "")) { |
| return false; |
| } |
| return origEmit.call(process, name, data, ...rest); |
| }; |
|
|
| |
| const sqlite = await import("node:sqlite"); |
| const Database = sqlite.DatabaseSync; |
| const db = new Database(filePath); |
|
|
| db.exec(PRAGMA_SQL); |
|
|
| const stmtCache = new Map(); |
| function prepare(sql) { |
| let stmt = stmtCache.get(sql); |
| if (!stmt) { |
| stmt = db.prepare(sql); |
| stmtCache.set(sql, stmt); |
| } |
| return stmt; |
| } |
|
|
| |
| const checkpointTimer = setInterval(() => { |
| try { db.exec("PRAGMA wal_checkpoint(TRUNCATE)"); } catch {} |
| }, CHECKPOINT_INTERVAL_MS); |
| if (typeof checkpointTimer.unref === "function") checkpointTimer.unref(); |
|
|
| function gracefulClose() { |
| try { db.exec("PRAGMA wal_checkpoint(TRUNCATE)"); } catch {} |
| try { stmtCache.clear(); } catch {} |
| try { db.close(); } catch {} |
| } |
| const onShutdown = () => gracefulClose(); |
| process.once("beforeExit", onShutdown); |
| process.once("SIGINT", () => { onShutdown(); process.exit(0); }); |
| process.once("SIGTERM", () => { onShutdown(); process.exit(0); }); |
|
|
| return { |
| driver: "node:sqlite", |
| run(sql, params = []) { |
| const r = prepare(sql).run(...params); |
| return { changes: Number(r.changes ?? 0), lastInsertRowid: Number(r.lastInsertRowid ?? 0) }; |
| }, |
| get(sql, params = []) { |
| return prepare(sql).get(...params); |
| }, |
| all(sql, params = []) { |
| return prepare(sql).all(...params); |
| }, |
| exec(sql) { return db.exec(sql); }, |
| transaction(fn) { |
| |
| const sp = `sp_${Math.random().toString(36).slice(2)}`; |
| db.exec(`SAVEPOINT ${sp}`); |
| try { |
| const r = fn(); |
| db.exec(`RELEASE ${sp}`); |
| return r; |
| } catch (e) { |
| try { db.exec(`ROLLBACK TO ${sp}`); db.exec(`RELEASE ${sp}`); } catch {} |
| throw e; |
| } |
| }, |
| checkpoint() { try { db.exec("PRAGMA wal_checkpoint(TRUNCATE)"); } catch {} }, |
| close() { |
| clearInterval(checkpointTimer); |
| gracefulClose(); |
| }, |
| raw: db, |
| }; |
| } |
|
|