From ea9a79226a7d3eb964e86c1d8749a6c6e31beee4 Mon Sep 17 00:00:00 2001 From: Hendrik Date: Fri, 17 Apr 2026 15:41:20 +0200 Subject: [PATCH] feat(db): bundle migration SQL via Vite glob + auto-create data dirs Co-Authored-By: Claude Opus 4.7 (1M context) --- src/lib/server/db/index.ts | 5 +++++ src/lib/server/db/migrate.ts | 29 ++++++++++++++++------------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/lib/server/db/index.ts b/src/lib/server/db/index.ts index 795ea1a..a1e4a92 100644 --- a/src/lib/server/db/index.ts +++ b/src/lib/server/db/index.ts @@ -1,10 +1,15 @@ import Database from 'better-sqlite3'; +import { mkdirSync } from 'node:fs'; +import { dirname } from 'node:path'; import { runMigrations } from './migrate'; let instance: Database.Database | null = null; export function getDb(path = process.env.DATABASE_PATH ?? './data/kochwas.db'): Database.Database { if (instance) return instance; + mkdirSync(dirname(path), { recursive: true }); + const imageDir = process.env.IMAGE_DIR ?? './data/images'; + mkdirSync(imageDir, { recursive: true }); instance = new Database(path); instance.pragma('journal_mode = WAL'); instance.pragma('foreign_keys = ON'); diff --git a/src/lib/server/db/migrate.ts b/src/lib/server/db/migrate.ts index 1ee546a..3242b9a 100644 --- a/src/lib/server/db/migrate.ts +++ b/src/lib/server/db/migrate.ts @@ -1,7 +1,17 @@ import type Database from 'better-sqlite3'; -import { readdirSync, readFileSync } from 'node:fs'; -import { join, dirname } from 'node:path'; -import { fileURLToPath } from 'node:url'; + +// Vite bundles these SQL files as strings at build time. In dev this is also live. +const migrations = import.meta.glob('./migrations/*.sql', { + eager: true, + query: '?raw', + import: 'default' +}) as Record; + +function orderedMigrations(): { name: string; sql: string }[] { + return Object.entries(migrations) + .map(([path, sql]) => ({ name: path.split('/').pop()!, sql })) + .sort((a, b) => a.name.localeCompare(b.name)); +} export function runMigrations(db: Database.Database): void { db.exec(`CREATE TABLE IF NOT EXISTS schema_migration ( @@ -9,22 +19,15 @@ export function runMigrations(db: Database.Database): void { applied_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP );`); - const here = dirname(fileURLToPath(import.meta.url)); - const dir = join(here, 'migrations'); - const files = readdirSync(dir) - .filter((f) => f.endsWith('.sql')) - .sort(); - const applied = new Set( (db.prepare('SELECT name FROM schema_migration').all() as { name: string }[]).map((r) => r.name) ); - for (const file of files) { - if (applied.has(file)) continue; - const sql = readFileSync(join(dir, file), 'utf8'); + for (const { name, sql } of orderedMigrations()) { + if (applied.has(name)) continue; const tx = db.transaction(() => { db.exec(sql); - db.prepare('INSERT INTO schema_migration(name) VALUES (?)').run(file); + db.prepare('INSERT INTO schema_migration(name) VALUES (?)').run(name); }); tx(); }