spb/chat-spboucher-ai
Public
1/** Applies db/migrations/*.sql in order, tracking them in schema_migrations. */2import postgres from "postgres";3import fs from "node:fs";4import path from "node:path";56const url = process.env.DATABASE_URL;7if (!url) { console.error("DATABASE_URL is required"); process.exit(1); }8const sql = postgres(url, { max: 1, onnotice: () => {} });910async function main() {11 await sql`CREATE TABLE IF NOT EXISTS schema_migrations (name text PRIMARY KEY, applied_at timestamptz NOT NULL DEFAULT now())`;12 const done = new Set((await sql<{ name: string }[]>`SELECT name FROM schema_migrations`).map(r => r.name));13 const dir = path.resolve("db/migrations");14 const files = fs.readdirSync(dir).filter(f => f.endsWith(".sql")).sort();15 for (const f of files) {16 if (done.has(f)) continue;17 const body = fs.readFileSync(path.join(dir, f), "utf8");18 process.stdout.write(`applying ${f} … `);19 await sql.begin(async tx => { await tx.unsafe(body); await tx`INSERT INTO schema_migrations (name) VALUES (${f})`; });20 console.log("ok");21 }22 console.log(`migrations up to date (${files.length} total)`);23 await sql.end();24}25main().catch(e => { console.error(e); process.exit(1); });26