Files
WRNexusJS/packages/db/src/adapters/sqlite.ts
T
2026-07-12 15:55:18 +05:30

61 lines
1.8 KiB
TypeScript

/**
* SQLite adapter, built on Bun's zero-dependency `bun:sqlite`. Use a file URL
* (`file:./dev.db`) or the default in-memory database (great for tests). This is
* the reference adapter — it needs no external service to run.
*/
import { Database } from "bun:sqlite";
import type { Driver, ExecResult, Row, TxHandle } from "../driver.ts";
/** SQLite can only bind numbers/strings/bigints/null/blobs — coerce JS values. */
function bind(params: unknown[]): unknown[] {
return params.map((p) => {
if (p === true) return 1;
if (p === false) return 0;
if (p === undefined) return null;
if (p instanceof Date) return p.toISOString();
return p;
});
}
/** Create a SQLite driver. `url` may be `file:./x.db`, a path, or `:memory:`. */
export function sqlite(url = ":memory:"): Driver {
const path = url.replace(/^(file:|sqlite:)/, "") || ":memory:";
const database = new Database(path);
database.exec("PRAGMA foreign_keys = ON;");
const runner: TxHandle = {
async query(sql, params = []): Promise<Row[]> {
return database.query(sql).all(...(bind(params) as never[])) as Row[];
},
async exec(sql, params = []): Promise<ExecResult> {
if (params.length === 0) {
database.exec(sql); // DDL / multi-statement
return { changes: 0 };
}
const result = database.query(sql).run(...(bind(params) as never[]));
return { changes: result.changes, lastInsertId: Number(result.lastInsertRowid) };
},
};
return {
dialect: "sqlite",
query: runner.query,
exec: runner.exec,
async transaction(fn) {
database.exec("BEGIN");
try {
const result = await fn(runner);
database.exec("COMMIT");
return result;
} catch (err) {
database.exec("ROLLBACK");
throw err;
}
},
close() {
database.close();
},
};
}