9router/src/lib/db/adapters/betterSqliteAdapter.js
decolua bee8dad946 feat(db): migrate from lowdb to SQLite with repos pattern
- Add modular DB layer (adapters, migrations, repos, helpers)
- Replace localDb/usageDb/requestDetailsDb monoliths with repos
- Add Tailscale tunnel integration & status check API
- Add /api/cli-tools/all-statuses aggregated endpoint
- Add settingsStore (Zustand) and mitm/dbReader
- Add DB unit tests (benchmark, concurrent, migration, vs-lowdb)
2026-05-09 17:48:20 +07:00

55 lines
1.8 KiB
JavaScript

import Database from "better-sqlite3";
import { PRAGMA_SQL } from "../schema.js";
// Periodic checkpoint to keep WAL file small (avoid huge -wal/-shm growth)
const CHECKPOINT_INTERVAL_MS = 60 * 1000;
export function createBetterSqliteAdapter(filePath) {
const db = new Database(filePath);
db.exec(PRAGMA_SQL);
// Schema is created/synced by migrate.js after adapter init
const stmtCache = new Map();
function prepare(sql) {
let stmt = stmtCache.get(sql);
if (!stmt) {
stmt = db.prepare(sql);
stmtCache.set(sql, stmt);
}
return stmt;
}
// Truncate WAL periodically so file stays small for backup/copy
const checkpointTimer = setInterval(() => {
try { db.pragma("wal_checkpoint(TRUNCATE)"); } catch {}
}, CHECKPOINT_INTERVAL_MS);
if (typeof checkpointTimer.unref === "function") checkpointTimer.unref();
function gracefulClose() {
try { db.pragma("wal_checkpoint(TRUNCATE)"); } catch {}
try { stmtCache.clear(); } catch {}
try { db.close(); } catch {}
}
// Ensure WAL is flushed and -wal/-shm files removed on shutdown
const onShutdown = () => gracefulClose();
process.once("beforeExit", onShutdown);
process.once("SIGINT", () => { onShutdown(); process.exit(0); });
process.once("SIGTERM", () => { onShutdown(); process.exit(0); });
return {
driver: "better-sqlite3",
run(sql, params = []) { return prepare(sql).run(params); },
get(sql, params = []) { return prepare(sql).get(params); },
all(sql, params = []) { return prepare(sql).all(params); },
exec(sql) { return db.exec(sql); },
transaction(fn) { return db.transaction(fn)(); },
checkpoint() { try { db.pragma("wal_checkpoint(TRUNCATE)"); } catch {} },
close() {
clearInterval(checkpointTimer);
gracefulClose();
},
raw: db,
};
}