/** * Fix script: Re-insert historical migration records and apply new migration * using a direct pg connection (no Payload init to avoid dev-mode push loops). * * Run with: pnpm tsx --env-file=.env scripts/fix-migrations.ts */ import { createRequire } from 'module' const require = createRequire(import.meta.url) const { Pool } = require( 'd:/Project/gbmake/gb-payload/node_modules/.pnpm/pg@8.16.3/node_modules/pg' ) const pool = new Pool({ connectionString: process.env.DATABASE_URL ?? 'postgres://gb-payload:123123@localhost/gb-payload', }) async function run(sql: string, params: any[] = []) { const result = await pool.query(sql, params) return result.rows } // ── Check current migration state ──────────────────────────────────────────── console.log('📋 Checking payload_migrations table...') const existing = await run(`SELECT name FROM payload_migrations ORDER BY id`) const existingNames = new Set(existing.map((r: any) => r.name)) console.log('Currently recorded:', existingNames.size > 0 ? [...existingNames] : '(none)') // ── Mark all historical migrations as done ──────────────────────────────────── const historyMigrations = [ '20260208_171142', '20260212_193303', '20260212_202303', '20260222_170233', 'hero_slider_simplify', 'product_recommendations_simplify', ] for (const name of historyMigrations) { if (!existingNames.has(name)) { await run( `INSERT INTO payload_migrations (name, batch, updated_at, created_at) VALUES ($1, 1, now(), now())`, [name] ) console.log(`✅ Marked done: ${name}`) } else { console.log(`⏭️ Already recorded: ${name}`) } } // ── Skip if new migration already applied ───────────────────────────────────── if (existingNames.has('20260223_disassembly_refactor')) { console.log('\n⏭️ Migration 20260223_disassembly_refactor already applied.') await pool.end() process.exit(0) } // ── Show what disassembly tables exist ─────────────────────────────────────── const disasmTables = await run( `SELECT tablename FROM pg_tables WHERE schemaname='public' AND tablename LIKE 'disassembly%' ORDER BY tablename` ) console.log('\nCurrent disassembly tables:', disasmTables.map((r: any) => r.tablename)) console.log('\n🔧 Applying: 20260223_disassembly_refactor ...') try { // 1. disassembly_components await run(`CREATE TABLE IF NOT EXISTS disassembly_components ( id serial PRIMARY KEY NOT NULL, label varchar NOT NULL, start_coordinate_x numeric DEFAULT 0 NOT NULL, start_coordinate_y numeric DEFAULT 0 NOT NULL, start_radius numeric DEFAULT 20 NOT NULL, updated_at timestamp(3) with time zone DEFAULT now() NOT NULL, created_at timestamp(3) with time zone DEFAULT now() NOT NULL )`) await run(`CREATE INDEX IF NOT EXISTS disassembly_components_updated_at_idx ON disassembly_components USING btree (updated_at)`) await run(`CREATE INDEX IF NOT EXISTS disassembly_components_created_at_idx ON disassembly_components USING btree (created_at)`) console.log(' ✅ disassembly_components') // 2. disassembly_linked_products await run(`CREATE TABLE IF NOT EXISTS disassembly_linked_products ( id serial PRIMARY KEY NOT NULL, coordinate_x numeric DEFAULT 0 NOT NULL, coordinate_y numeric DEFAULT 0 NOT NULL, product_name varchar, updated_at timestamp(3) with time zone DEFAULT now() NOT NULL, created_at timestamp(3) with time zone DEFAULT now() NOT NULL )`) await run(`CREATE INDEX IF NOT EXISTS disassembly_linked_products_updated_at_idx ON disassembly_linked_products USING btree (updated_at)`) await run(`CREATE INDEX IF NOT EXISTS disassembly_linked_products_created_at_idx ON disassembly_linked_products USING btree (created_at)`) console.log(' ✅ disassembly_linked_products') // 3. disassembly_components_rels await run(`CREATE TABLE IF NOT EXISTS disassembly_components_rels ( id serial PRIMARY KEY NOT NULL, "order" integer, parent_id integer NOT NULL, path varchar NOT NULL, disassembly_linked_products_id integer )`) await run(`DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'disassembly_components_rels_parent_fk') THEN ALTER TABLE disassembly_components_rels ADD CONSTRAINT disassembly_components_rels_parent_fk FOREIGN KEY (parent_id) REFERENCES disassembly_components(id) ON DELETE cascade; END IF; END $$`) await run(`DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'disassembly_components_rels_disassembly_linked_products_fk') THEN ALTER TABLE disassembly_components_rels ADD CONSTRAINT disassembly_components_rels_disassembly_linked_products_fk FOREIGN KEY (disassembly_linked_products_id) REFERENCES disassembly_linked_products(id) ON DELETE cascade; END IF; END $$`) await run(`CREATE INDEX IF NOT EXISTS disassembly_components_rels_order_idx ON disassembly_components_rels USING btree ("order")`) await run(`CREATE INDEX IF NOT EXISTS disassembly_components_rels_parent_idx ON disassembly_components_rels USING btree (parent_id)`) await run(`CREATE INDEX IF NOT EXISTS disassembly_components_rels_path_idx ON disassembly_components_rels USING btree (path)`) await run(`CREATE INDEX IF NOT EXISTS disassembly_components_rels_disassembly_linked_products_id_idx ON disassembly_components_rels USING btree (disassembly_linked_products_id)`) console.log(' ✅ disassembly_components_rels') // 4. disassembly_linked_products_rels await run(`CREATE TABLE IF NOT EXISTS disassembly_linked_products_rels ( id serial PRIMARY KEY NOT NULL, "order" integer, parent_id integer NOT NULL, path varchar NOT NULL, products_id integer, preorder_products_id integer )`) await run(`DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'disassembly_linked_products_rels_parent_fk') THEN ALTER TABLE disassembly_linked_products_rels ADD CONSTRAINT disassembly_linked_products_rels_parent_fk FOREIGN KEY (parent_id) REFERENCES disassembly_linked_products(id) ON DELETE cascade; END IF; END $$`) await run(`DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'disassembly_linked_products_rels_products_fk') THEN ALTER TABLE disassembly_linked_products_rels ADD CONSTRAINT disassembly_linked_products_rels_products_fk FOREIGN KEY (products_id) REFERENCES products(id) ON DELETE cascade; END IF; END $$`) await run(`DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'disassembly_linked_products_rels_preorder_products_fk') THEN ALTER TABLE disassembly_linked_products_rels ADD CONSTRAINT disassembly_linked_products_rels_preorder_products_fk FOREIGN KEY (preorder_products_id) REFERENCES preorder_products(id) ON DELETE cascade; END IF; END $$`) await run(`CREATE INDEX IF NOT EXISTS disassembly_linked_products_rels_order_idx ON disassembly_linked_products_rels USING btree ("order")`) await run(`CREATE INDEX IF NOT EXISTS disassembly_linked_products_rels_parent_idx ON disassembly_linked_products_rels USING btree (parent_id)`) await run(`CREATE INDEX IF NOT EXISTS disassembly_linked_products_rels_path_idx ON disassembly_linked_products_rels USING btree (path)`) await run(`CREATE INDEX IF NOT EXISTS disassembly_linked_products_rels_products_id_idx ON disassembly_linked_products_rels USING btree (products_id)`) await run(`CREATE INDEX IF NOT EXISTS disassembly_linked_products_rels_preorder_products_id_idx ON disassembly_linked_products_rels USING btree (preorder_products_id)`) console.log(' ✅ disassembly_linked_products_rels') // 5. Update disassembly_pages_rels await run(`ALTER TABLE disassembly_pages_rels DROP CONSTRAINT IF EXISTS disassembly_pages_rels_products_fk`) await run(`ALTER TABLE disassembly_pages_rels DROP CONSTRAINT IF EXISTS disassembly_pages_rels_preorder_products_fk`) await run(`DROP INDEX IF EXISTS disassembly_pages_rels_products_id_idx`) await run(`DROP INDEX IF EXISTS disassembly_pages_rels_preorder_products_id_idx`) const pc = await run(`SELECT 1 FROM information_schema.columns WHERE table_name='disassembly_pages_rels' AND column_name='products_id'`) if (pc.length > 0) await run(`ALTER TABLE disassembly_pages_rels DROP COLUMN products_id`) const prc = await run(`SELECT 1 FROM information_schema.columns WHERE table_name='disassembly_pages_rels' AND column_name='preorder_products_id'`) if (prc.length > 0) await run(`ALTER TABLE disassembly_pages_rels DROP COLUMN preorder_products_id`) await run(`ALTER TABLE disassembly_pages_rels ADD COLUMN IF NOT EXISTS disassembly_components_id integer`) await run(`DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'disassembly_pages_rels_disassembly_components_fk') THEN ALTER TABLE disassembly_pages_rels ADD CONSTRAINT disassembly_pages_rels_disassembly_components_fk FOREIGN KEY (disassembly_components_id) REFERENCES disassembly_components(id) ON DELETE cascade; END IF; END $$`) await run(`CREATE INDEX IF NOT EXISTS disassembly_pages_rels_disassembly_components_id_idx ON disassembly_pages_rels USING btree (disassembly_components_id)`) console.log(' ✅ disassembly_pages_rels updated') // 6. Update payload_locked_documents_rels await run(`ALTER TABLE payload_locked_documents_rels ADD COLUMN IF NOT EXISTS disassembly_components_id integer`) await run(`ALTER TABLE payload_locked_documents_rels ADD COLUMN IF NOT EXISTS disassembly_linked_products_id integer`) await run(`DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'payload_locked_documents_rels_disassembly_components_fk') THEN ALTER TABLE payload_locked_documents_rels ADD CONSTRAINT payload_locked_documents_rels_disassembly_components_fk FOREIGN KEY (disassembly_components_id) REFERENCES disassembly_components(id) ON DELETE cascade; END IF; END $$`) await run(`DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'payload_locked_documents_rels_disassembly_linked_products_fk') THEN ALTER TABLE payload_locked_documents_rels ADD CONSTRAINT payload_locked_documents_rels_disassembly_linked_products_fk FOREIGN KEY (disassembly_linked_products_id) REFERENCES disassembly_linked_products(id) ON DELETE cascade; END IF; END $$`) await run(`CREATE INDEX IF NOT EXISTS payload_locked_documents_rels_disassembly_components_id_idx ON payload_locked_documents_rels USING btree (disassembly_components_id)`) await run(`CREATE INDEX IF NOT EXISTS payload_locked_documents_rels_disassembly_linked_products_id_idx ON payload_locked_documents_rels USING btree (disassembly_linked_products_id)`) console.log(' ✅ payload_locked_documents_rels updated') // 7. Drop old array tables await run(`DROP TABLE IF EXISTS disassembly_pages_components_linked_products CASCADE`) await run(`DROP TABLE IF EXISTS disassembly_pages_components CASCADE`) console.log(' ✅ Old array tables dropped') // 8. Record migration await run( `INSERT INTO payload_migrations (name, batch, updated_at, created_at) VALUES ($1, 2, now(), now())`, ['20260223_disassembly_refactor'] ) console.log('\n🎉 Migration 20260223_disassembly_refactor applied successfully!') } catch (err: any) { console.error('\n❌ Error:', err?.message ?? err) await pool.end() process.exit(1) } await pool.end() process.exit(0)