import Database from 'better-sqlite3'; import { mkdirSync, readdirSync, readFileSync } from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { getPaths } from './config.mjs'; const projectRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); export function migrate(databasePath = getPaths().database) { mkdirSync(path.dirname(databasePath), { recursive: true }); mkdirSync(getPaths().uploads, { recursive: true }); const database = new Database(databasePath); database.pragma('foreign_keys = ON'); database.exec(` CREATE TABLE IF NOT EXISTS schema_migrations ( name TEXT PRIMARY KEY, applied_at_utc TEXT NOT NULL ) `); const applied = new Set( database .prepare('SELECT name FROM schema_migrations') .all() .map((row) => row.name) ); const migrations = readdirSync(path.join(projectRoot, 'migrations')) .filter((name) => /^\d+.+\.sql$/.test(name)) .sort(); for (const name of migrations) { if (applied.has(name)) continue; const sql = readFileSync(path.join(projectRoot, 'migrations', name), 'utf8'); database.exec('BEGIN IMMEDIATE'); try { database.exec(sql); database .prepare('INSERT INTO schema_migrations (name, applied_at_utc) VALUES (?, ?)') .run(name, new Date().toISOString()); database.exec('COMMIT'); console.log(`Migration applied: ${name}`); } catch (error) { database.exec('ROLLBACK'); database.close(); throw error; } } database.close(); console.log(`Database ready: ${databasePath}`); } if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) { migrate(); }