/** Applies db/migrations/*.sql in order, tracking them in schema_migrations. */ import postgres from "postgres"; import fs from "node:fs"; import path from "node:path"; const url = process.env.DATABASE_URL; if (!url) { console.error("DATABASE_URL is required"); process.exit(1); } const sql = postgres(url, { max: 1, onnotice: () => {} }); async function main() { await sql`CREATE TABLE IF NOT EXISTS schema_migrations (name text PRIMARY KEY, applied_at timestamptz NOT NULL DEFAULT now())`; const done = new Set((await sql<{ name: string }[]>`SELECT name FROM schema_migrations`).map(r => r.name)); const dir = path.resolve("db/migrations"); const files = fs.readdirSync(dir).filter(f => f.endsWith(".sql")).sort(); for (const f of files) { if (done.has(f)) continue; const body = fs.readFileSync(path.join(dir, f), "utf8"); process.stdout.write(`applying ${f} … `); await sql.begin(async tx => { await tx.unsafe(body); await tx`INSERT INTO schema_migrations (name) VALUES (${f})`; }); console.log("ok"); } console.log(`migrations up to date (${files.length} total)`); await sql.end(); } main().catch(e => { console.error(e); process.exit(1); });