/** * fix-migration.mjs (v2) * * Run from your project root: * node fix-migration.mjs * * What it does: * 1. Deletes the broken migration file (the newest one) * 2. Removes it from migrations/index.ts * 3. Writes a cleanup-orphaned-types.sql file to your project root * 4. Tells you exactly what to run next */ import { readFileSync, writeFileSync, unlinkSync, readdirSync, statSync } from 'fs' import { join } from 'path' const MIGRATIONS_DIR = './src/migrations' // ── Find the newest migration .ts file ─────────────────────────────────────── const tsFiles = readdirSync(MIGRATIONS_DIR) .filter(f => f.endsWith('.ts') && f !== 'index.ts') .map(f => ({ name: f, mtime: statSync(join(MIGRATIONS_DIR, f)).mtime })) .sort((a, b) => b.mtime - a.mtime) if (tsFiles.length === 0) { console.error('❌ No migration files found in', MIGRATIONS_DIR) process.exit(1) } const migrationName = tsFiles[0].name.replace('.ts', '') const newestTs = join(MIGRATIONS_DIR, tsFiles[0].name) const newestJson = newestTs.replace('.ts', '.json') console.log(`\n🗑️ Deleting broken migration: ${tsFiles[0].name}`) try { unlinkSync(newestTs); console.log(` ✅ deleted .ts`) } catch(e) { console.log(` ⚠️ .ts: ${e.message}`) } try { unlinkSync(newestJson); console.log(` ✅ deleted .json`) } catch(e) { console.log(` (no .json found)`) } // ── Remove from migrations/index.ts ────────────────────────────────────────── const indexPath = join(MIGRATIONS_DIR, 'index.ts') let indexSrc = readFileSync(indexPath, 'utf8') // Remove any line that references this migration name const safeRef = migrationName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') indexSrc = indexSrc.replace(new RegExp(`^.*${safeRef}.*\\n`, 'gm'), '') writeFileSync(indexPath, indexSrc, 'utf8') console.log(` ✅ removed from migrations/index.ts`) // ── Write cleanup SQL ───────────────────────────────────────────────────────── const cleanupSql = `-- cleanup-orphaned-types.sql -- Run this against your database BEFORE regenerating the migration. -- Safe to run — all statements use IF EXISTS. -- Orphaned enum types from failed migration attempts DROP TYPE IF EXISTS "public"."enum_pages_blocks_lm_product_detail_section_background" CASCADE; DROP TYPE IF EXISTS "public"."enum__pages_v_blocks_lm_product_detail_section_background" CASCADE; DROP TYPE IF EXISTS "public"."enum_pages_blocks_lm_service_cards_cards_icon_slug" CASCADE; DROP TYPE IF EXISTS "public"."enum__pages_v_blocks_lm_service_cards_cards_icon_slug" CASCADE; -- Orphaned tables (if partially created) DROP TABLE IF EXISTS "public"."_pages_v_blocks_lm_product_detail_locales" CASCADE; DROP TABLE IF EXISTS "public"."_pages_v_blocks_lm_product_detail" CASCADE; DROP TABLE IF EXISTS "public"."pages_blocks_lm_product_detail_locales" CASCADE; DROP TABLE IF EXISTS "public"."pages_blocks_lm_product_detail" CASCADE; -- Orphaned columns added to service_cards (will be re-added by fresh migration) ALTER TABLE IF EXISTS "public"."pages_blocks_lm_service_cards_cards" DROP COLUMN IF EXISTS "icon_slug"; ALTER TABLE IF EXISTS "public"."pages_blocks_lm_service_cards_cards_locales" DROP COLUMN IF EXISTS "eyebrow"; ALTER TABLE IF EXISTS "public"."_pages_v_blocks_lm_service_cards_cards" DROP COLUMN IF EXISTS "icon_slug"; ALTER TABLE IF EXISTS "public"."_pages_v_blocks_lm_service_cards_cards_locales" DROP COLUMN IF EXISTS "eyebrow"; ` writeFileSync('./cleanup-orphaned-types.sql', cleanupSql, 'utf8') console.log(`\n📄 Generated: cleanup-orphaned-types.sql`) console.log(` ${'─'.repeat(60)} 👉 Run these 3 commands in order: 1. psql $DATABASE_URI -f cleanup-orphaned-types.sql (or open cleanup-orphaned-types.sql in TablePlus / Postico / any DB GUI and run it as a query) 2. pnpm payload migrate:create 3. pnpm payload migrate ${'─'.repeat(60)} `)