/** * Validate that pending migrations apply cleanly without committing changes. * Invoked by `pnpm db:check` — designed for CI pull-request gates. * * Strategy: redirect Drizzle's bookkeeping table to a scratch schema, run * the migrations against it, then `DROP SCHEMA ... CASCADE`. The check * verifies the migration SQL parses + the bookkeeping plumbing works. For * full destructive-change preview (does the SQL still apply against the * current production data?), run against an ephemeral clone separately. * * Uses PGlite when `DATABASE_URL` is unset so CI runners can validate * migrations without provisioning Postgres. */ import { resolve } from "node:path"; import { dryRun } from "@raredays/postgres/migrations"; import * as appSchema from "./schema.ts"; const migrationsFolder = resolve(import.meta.dirname, "migrations"); const databaseUrl = process.env.DATABASE_URL; async function main(): Promise { if (databaseUrl) { const { createDb } = await import("@raredays/postgres-neon"); const { migrate } = await import("drizzle-orm/neon-http/migrator"); const db = createDb(databaseUrl, { schema: appSchema }); await dryRun({ db, migrate, migrationsFolder }); return; } console.warn( "[db:check] DATABASE_URL is not set — validating against in-process PGlite.", ); const { createPglite } = await import("@raredays/postgres-pglite"); const { migrate } = await import("drizzle-orm/pglite/migrator"); const handle = await createPglite({ schema: appSchema }); try { await dryRun({ db: handle.db, migrate, migrationsFolder }); } finally { await handle.close(); } } main().catch((err) => { console.error("[db:check] failed:", err); process.exit(1); });