44 lines
1.8 KiB
TypeScript
44 lines
1.8 KiB
TypeScript
import Database from "better-sqlite3";
|
|||
|
|
import { drizzle } from "drizzle-orm/better-sqlite3";
|
||
|
|
import { mkdirSync } from "node:fs";
|
||
|
|
import { dirname } from "node:path";
|
||
|
|
import { getEnv } from "@/lib/env";
|
||
|
|
import * as schema from "./schema";
|
||
|
|
|
||
|
|
const globalForDb = globalThis as unknown as { __bpSqlite?: Database.Database };
|
||
|
|
|
||
|
|
function openDatabase(): Database.Database {
|
||
|
|
if (globalForDb.__bpSqlite) return globalForDb.__bpSqlite;
|
||
|
|
|
||
|
|
const path = getEnv().DATABASE_PATH;
|
||
|
|
mkdirSync(dirname(path), { recursive: true });
|
||
|
|
|
||
|
|
const instance = new Database(path);
|
||
|
|
instance.pragma("journal_mode = WAL");
|
||
|
|
instance.pragma("foreign_keys = ON");
|
||
|
|
|
||
|
|
// Reused across hot-reloads in dev so we don't leak file handles / open a
|
||
|
|
// fresh WAL-mode connection on every request.
|
||
|
|
globalForDb.__bpSqlite = instance;
|
||
|
|
return instance;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Lazy by design: `next build` imports this module's whole graph while
|
||
|
|
// collecting route metadata, even for force-dynamic pages that are never
|
||
|
|
// actually rendered at build time. Opening the DB (and requiring env vars)
|
||
|
|
// as a module-level side effect would make `pnpm build` fail in CI, where
|
||
|
|
// no secrets are configured. The proxy defers both until first real query.
|
||
|
|
export const sqlite = new Proxy({} as Database.Database, {
|
||
|
|
get(_target, prop) {
|
||
|
|
// drizzle-orm's `isConfig()` probes `.constructor.name` on its first
|
||
|
|
// argument to tell a client instance from a plain config object - that
|
||
|
|
// introspection must not itself trigger opening the real connection.
|
||
|
|
if (prop === "constructor") return Database;
|
||
|
|
const instance = openDatabase();
|
||
|
|
const value = Reflect.get(instance, prop, instance);
|
||
|
|
return typeof value === "function" ? value.bind(instance) : value;
|
||
|
|
},
|
||
|
|
}) as Database.Database;
|
||
|
|
|
||
|
|
export const db = drizzle(sqlite, { schema });
|