import DB from "better-sqlite3"; import fs from "fs"; import type { SQLitePragmaOptions } from "./sqlite3-messages.worker.js"; import type { Database as IDatabase, Statement as IStatement, } from "./types.js"; const applyPragmas = (db: DB.Database, pragmas?: SQLitePragmaOptions) => { db.pragma("journal_mode = WAL"); db.pragma("foreign_keys = on"); db.pragma(`synchronous = ${(pragmas?.synchronous ?? "FULL").toUpperCase()}`); if (pragmas?.lockingMode) { db.pragma(`locking_mode = ${pragmas.lockingMode.toUpperCase()}`); } if (pragmas?.tempStore && pragmas.tempStore !== "DEFAULT") { db.pragma(`temp_store = ${pragmas.tempStore.toUpperCase()}`); } db.defaultSafeIntegers(true); }; let create = async ( directory?: string, options?: { pragmas?: SQLitePragmaOptions }, ) => { let db: DB.Database | undefined = undefined; let statements: Map = new Map(); let dbFileName: string; let close = () => { for (const stmt of statements.values()) { stmt.finalize?.(); } statements.clear(); if (db) { db.close(); db = undefined; } }; let drop = () => { if (db && !db?.memory) { fs.rmSync(dbFileName); db = undefined; } return close(); }; let open = () => { if (db?.open) { return db; } if (!db) { if (directory) { // if directory is provided, check if directory exist, if not create it if (!fs.existsSync(directory)) { fs.mkdirSync(directory, { recursive: true }); } dbFileName = `${directory}/db.sqlite`; } else { dbFileName = ":memory:"; } db = new DB(dbFileName, { fileMustExist: false, readonly: false /* , verbose: (message) => console.log(message) */, }); } applyPragmas(db, options?.pragmas); }; return { exec: (sql: string) => { if (!db) throw new Error("Database not open"); return db.exec(sql); }, async prepare(sql: string, id?: string) { if (!db) throw new Error("Database not open"); if (id != null) { let prev = statements.get(id); if (prev) { await prev.reset?.(); return prev; } } const stmt = db.prepare(sql) as any as IStatement; // TODO types if (id != null) { statements.set(id, stmt); } return stmt; }, statements, close, drop, open, status: () => (db ? "open" : "closed"), } as IDatabase; // TODO fix this }; export { create };