import { readdir, readFile } from 'node:fs/promises'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { closePool, query } from './pool.js'; const migrationsDir = path.resolve(process.cwd(), 'migrations'); async function ensureMigrationTable(): Promise { await query(` CREATE TABLE IF NOT EXISTS schema_migrations ( filename VARCHAR(255) PRIMARY KEY, applied_at TIMESTAMP NOT NULL DEFAULT now() ) `); } async function appliedMigrations(): Promise> { const result = await query<{ filename: string }>('SELECT filename FROM schema_migrations'); return new Set(result.rows.map((row) => row.filename)); } export async function runMigrations(): Promise { await ensureMigrationTable(); const applied = await appliedMigrations(); const files = (await readdir(migrationsDir)) .filter((file) => file.endsWith('.sql')) .sort(); for (const file of files) { if (applied.has(file)) continue; const sql = await readFile(path.join(migrationsDir, file), 'utf8'); await query('BEGIN'); try { await query(sql); await query('INSERT INTO schema_migrations (filename) VALUES ($1)', [file]); await query('COMMIT'); console.log(`Applied migration ${file}`); } catch (error) { await query('ROLLBACK'); throw error; } } } if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) { runMigrations() .then(async () => { await closePool(); }) .catch(async (error: unknown) => { console.error(error); await closePool(); process.exitCode = 1; }); }