import { CompiledQuery, Kysely } from 'kysely'; import { NodeNativeSqliteDialect } from 'kysely-node-native-sqlite'; import type { DatabaseTables } from './tables.ts'; import type { Logger } from '../../utils/logger.ts'; /** Options required to open a SQLite database connection. */ export type DatabaseOptions = { /** Filesystem path to the SQLite database file. */ path: string; /** Logger extended with a database namespace for diagnostics. */ debug: Logger; }; /** * Thin wrapper around Kysely and NodeNativeSqliteDialect (which uses node:sqlite). * * Owns connection setup, pragma configuration, and graceful teardown. */ export class Database { private readonly debug: Logger; private readonly dialect: NodeNativeSqliteDialect; private readonly kysely: Kysely; /** * Open a SQLite database and configure it for concurrent writes. * * @param options - Database file path and debug logger. */ constructor(options: DatabaseOptions) { // Extend the debug logger to include the database namespace. this.debug = options.debug.extend('database'); // Create the SQLite database. this.dialect = new NodeNativeSqliteDialect(options.path); // Create the Kysely database. this.kysely = new Kysely({ dialect: this.dialect, }); // Configure the SQLite pragmas. this.configurePragmas(); } /** * Gets the Kysely database. * * @returns The typed Kysely query builder for DatabaseTables. */ get db(): Kysely { return this.kysely; } /** * Destroys the database connection. */ async destroy(): Promise { this.debug('destroying database connection'); await this.kysely.destroy(); } /** * Configures the SQLite pragmas. * * WAL improves write concurrency; foreign keys enforce referential integrity. */ private configurePragmas(): void { this.debug('configuring SQLite pragmas'); this.kysely.executeQuery(CompiledQuery.raw('PRAGMA journal_mode = WAL')); this.kysely.executeQuery(CompiledQuery.raw('PRAGMA foreign_keys = ON')); } }