Files
backspace/packages/server/src/db/index.ts
T
Jannis Braun ab5e7c8839 refactor(server): delete baseline + heal functions now unreachable under single-baseline history
baselineExistingInstall, healInitialSchemaDrift, and healRenamedColumns
existed only because of pre-squash intermediate states: dev DBs drifted
against drizzle-kit's assumed 0000 baseline, or carried pre-rename
columns from the old manual migration system. Under a single squashed
baseline there are no intermediate states to drift against, and these
functions are unreachable.

initDatabase() is now: pragmas -> drizzle() -> migrate() -> ensureDefaults().
ensureDefaults stays (idempotent startup seeding for settings row, worker
ID, first-admin promotion).

Refs backlog #31 Phase 2.
2026-04-24 23:33:35 +02:00

70 lines
2.0 KiB
TypeScript

import Database from 'better-sqlite3';
import { drizzle } from 'drizzle-orm/better-sqlite3';
import { migrate } from 'drizzle-orm/better-sqlite3/migrator';
import { config } from '../config.js';
import * as schema from './schema.js';
import { ensureDefaults } from './migrate.js';
import { setWorkerId } from '../utils/snowflake.js';
import { mkdirSync } from 'fs';
import { dirname, resolve } from 'path';
import { fileURLToPath } from 'url';
const __dirname = dirname(fileURLToPath(import.meta.url));
let sqlite: Database.Database;
function ensureDirectory(filePath: string): void {
const dir = dirname(filePath);
mkdirSync(dir, { recursive: true });
}
export function initDatabase() {
ensureDirectory(config.dbPath);
sqlite = new Database(config.dbPath);
sqlite.pragma('journal_mode = WAL');
sqlite.pragma('foreign_keys = ON');
// Apply any pending Drizzle migrations
const migrationsFolder = resolve(__dirname, '../../drizzle');
const db = drizzle(sqlite, { schema });
migrate(db, { migrationsFolder });
// Ensure data invariants (settings row, worker ID, first admin)
ensureDefaults(sqlite);
// Initialize Snowflake worker ID from persisted value
const settings = sqlite.prepare('SELECT worker_id FROM instance_settings WHERE id = 1').get() as { worker_id: number } | undefined;
if (settings?.worker_id !== undefined && settings.worker_id !== null) {
setWorkerId(settings.worker_id);
console.log(`Snowflake worker ID: ${settings.worker_id}`);
} else {
throw new Error('Snowflake worker_id not found in instance_settings — migration failed');
}
console.log(`Database initialized at ${config.dbPath}`);
return db;
}
export type DB = ReturnType<typeof initDatabase>;
let db: DB;
export function getDb(): DB {
if (!db) {
db = initDatabase();
}
return db;
}
export function getRawDb(): Database.Database {
return sqlite;
}
export function closeDatabase(): void {
if (sqlite) {
sqlite.close();
}
}
export { schema };