import { MigrationInterface, QueryRunner } from 'typeorm'; export class AddBookingsRemainingForeignKeys1748800000000 implements MigrationInterface { name = 'AddBookingsRemainingForeignKeys1748800000000'; public async up(queryRunner: QueryRunner): Promise { const publicCustomersExists = await queryRunner.query(` SELECT EXISTS ( SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'customers' ) AS exists `); const hasPublicCustomers = Boolean(publicCustomersExists[0]?.exists); // ── freight.bookings: nullable FK cleanup ───────────────────────────── await queryRunner.query(` UPDATE freight.bookings b SET train_id = NULL WHERE b.train_id IS NOT NULL AND NOT EXISTS (SELECT 1 FROM freight.trains t WHERE t.id = b.train_id); `); await queryRunner.query(` UPDATE freight.bookings b SET previous_contract_id = NULL WHERE b.previous_contract_id IS NOT NULL AND NOT EXISTS (SELECT 1 FROM freight.bookings pb WHERE pb.id = b.previous_contract_id); `); await queryRunner.query(` UPDATE freight.bookings b SET consolidation_partner_id = NULL WHERE b.consolidation_partner_id IS NOT NULL AND NOT EXISTS (SELECT 1 FROM freight.bookings pb WHERE pb.id = b.consolidation_partner_id); `); // Legacy DBs only: public.customers is created/moved in MoveCustomersToFreightSchema (174890). if (hasPublicCustomers) { await queryRunner.query(` DELETE FROM freight.booking_cargo_modifier bcm USING freight.bookings b WHERE bcm.booking_id = b.id AND NOT EXISTS (SELECT 1 FROM public.customers c WHERE c.id = b.customer_id); `); await queryRunner.query(` DELETE FROM freight.booking_approval_step bas USING freight.bookings b WHERE bas.booking_id = b.id AND NOT EXISTS (SELECT 1 FROM public.customers c WHERE c.id = b.customer_id); `); await queryRunner.query(` DELETE FROM freight.booking_rate_snapshot brs USING freight.bookings b WHERE brs.booking_id = b.id AND NOT EXISTS (SELECT 1 FROM public.customers c WHERE c.id = b.customer_id); `); await queryRunner.query(` DELETE FROM freight.booking_container bc USING freight.bookings b WHERE bc.booking_id = b.id AND NOT EXISTS (SELECT 1 FROM public.customers c WHERE c.id = b.customer_id); `); await queryRunner.query(` DELETE FROM freight.bookings b WHERE NOT EXISTS (SELECT 1 FROM public.customers c WHERE c.id = b.customer_id); `); await queryRunner.query(` DO $$ BEGIN ALTER TABLE freight.bookings ADD CONSTRAINT "FK_bookings_customer_id" FOREIGN KEY (customer_id) REFERENCES public.customers(id) ON DELETE RESTRICT; EXCEPTION WHEN duplicate_object THEN NULL; END $$; `); } // ── freight.bookings FKs ──────────────────────────────────────────── await queryRunner.query(` DO $$ BEGIN ALTER TABLE freight.bookings ADD CONSTRAINT "FK_bookings_train_id" FOREIGN KEY (train_id) REFERENCES freight.trains(id) ON DELETE SET NULL; EXCEPTION WHEN duplicate_object THEN NULL; END $$; `); await queryRunner.query(` DO $$ BEGIN ALTER TABLE freight.bookings ADD CONSTRAINT "FK_bookings_previous_contract_id" FOREIGN KEY (previous_contract_id) REFERENCES freight.bookings(id) ON DELETE SET NULL; EXCEPTION WHEN duplicate_object THEN NULL; END $$; `); await queryRunner.query(` DO $$ BEGIN ALTER TABLE freight.bookings ADD CONSTRAINT "FK_bookings_consolidation_partner_id" FOREIGN KEY (consolidation_partner_id) REFERENCES freight.bookings(id) ON DELETE SET NULL; EXCEPTION WHEN duplicate_object THEN NULL; END $$; `); // ── freight.booking_container ───────────────────────────────────────── await queryRunner.query(` UPDATE freight.booking_container bc SET weight_limit_rule_id = NULL WHERE bc.weight_limit_rule_id IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM freight.weight_limit_rules wlr WHERE wlr.id = bc.weight_limit_rule_id ); `); await queryRunner.query(` DELETE FROM freight.booking_container bc WHERE NOT EXISTS (SELECT 1 FROM freight.container_types ct WHERE ct.id = bc.container_type_id); `); await queryRunner.query(` DO $$ BEGIN ALTER TABLE freight.booking_container ADD CONSTRAINT "FK_booking_container_container_type_id" FOREIGN KEY (container_type_id) REFERENCES freight.container_types(id) ON DELETE RESTRICT; EXCEPTION WHEN duplicate_object THEN NULL; END $$; `); await queryRunner.query(` DO $$ BEGIN ALTER TABLE freight.booking_container ADD CONSTRAINT "FK_booking_container_weight_limit_rule_id" FOREIGN KEY (weight_limit_rule_id) REFERENCES freight.weight_limit_rules(id) ON DELETE SET NULL; EXCEPTION WHEN duplicate_object THEN NULL; END $$; `); // ── freight.booking_rate_snapshot ───────────────────────────────────── await queryRunner.query(` DELETE FROM freight.booking_cargo_modifier bcm USING freight.booking_rate_snapshot brs WHERE bcm.rate_snapshot_id = brs.id AND ( NOT EXISTS (SELECT 1 FROM freight.bookings b WHERE b.id = brs.booking_id) OR NOT EXISTS (SELECT 1 FROM freight.rates r WHERE r.id = brs.rate_id) ); `); await queryRunner.query(` DELETE FROM freight.booking_rate_snapshot brs WHERE NOT EXISTS (SELECT 1 FROM freight.bookings b WHERE b.id = brs.booking_id) OR NOT EXISTS (SELECT 1 FROM freight.rates r WHERE r.id = brs.rate_id); `); await queryRunner.query(` DO $$ BEGIN ALTER TABLE freight.booking_rate_snapshot ADD CONSTRAINT "FK_booking_rate_snapshot_booking_id" FOREIGN KEY (booking_id) REFERENCES freight.bookings(id) ON DELETE CASCADE; EXCEPTION WHEN duplicate_object THEN NULL; END $$; `); await queryRunner.query(` DO $$ BEGIN ALTER TABLE freight.booking_rate_snapshot ADD CONSTRAINT "FK_booking_rate_snapshot_rate_id" FOREIGN KEY (rate_id) REFERENCES freight.rates(id) ON DELETE RESTRICT; EXCEPTION WHEN duplicate_object THEN NULL; END $$; `); // ── freight.booking_approval_step ───────────────────────────────────── await queryRunner.query(` DELETE FROM freight.booking_approval_step bas WHERE NOT EXISTS (SELECT 1 FROM freight.bookings b WHERE b.id = bas.booking_id) OR NOT EXISTS (SELECT 1 FROM freight.approval_rules ar WHERE ar.id = bas.approval_rule_id); `); await queryRunner.query(` DO $$ BEGIN ALTER TABLE freight.booking_approval_step ADD CONSTRAINT "FK_booking_approval_step_booking_id" FOREIGN KEY (booking_id) REFERENCES freight.bookings(id) ON DELETE CASCADE; EXCEPTION WHEN duplicate_object THEN NULL; END $$; `); await queryRunner.query(` DO $$ BEGIN ALTER TABLE freight.booking_approval_step ADD CONSTRAINT "FK_booking_approval_step_approval_rule_id" FOREIGN KEY (approval_rule_id) REFERENCES freight.approval_rules(id) ON DELETE RESTRICT; EXCEPTION WHEN duplicate_object THEN NULL; END $$; `); // ── freight.booking_cargo_modifier ──────────────────────────────────── await queryRunner.query(` DELETE FROM freight.booking_cargo_modifier bcm WHERE NOT EXISTS (SELECT 1 FROM freight.bookings b WHERE b.id = bcm.booking_id) OR NOT EXISTS (SELECT 1 FROM freight.surcharge_types st WHERE st.id = bcm.surcharge_type_id) OR NOT EXISTS ( SELECT 1 FROM freight.booking_rate_snapshot brs WHERE brs.id = bcm.rate_snapshot_id ); `); await queryRunner.query(` DO $$ BEGIN ALTER TABLE freight.booking_cargo_modifier ADD CONSTRAINT "FK_booking_cargo_modifier_booking_id" FOREIGN KEY (booking_id) REFERENCES freight.bookings(id) ON DELETE CASCADE; EXCEPTION WHEN duplicate_object THEN NULL; END $$; `); await queryRunner.query(` DO $$ BEGIN ALTER TABLE freight.booking_cargo_modifier ADD CONSTRAINT "FK_booking_cargo_modifier_surcharge_type_id" FOREIGN KEY (surcharge_type_id) REFERENCES freight.surcharge_types(id) ON DELETE RESTRICT; EXCEPTION WHEN duplicate_object THEN NULL; END $$; `); await queryRunner.query(` DO $$ BEGIN ALTER TABLE freight.booking_cargo_modifier ADD CONSTRAINT "FK_booking_cargo_modifier_rate_snapshot_id" FOREIGN KEY (rate_snapshot_id) REFERENCES freight.booking_rate_snapshot(id) ON DELETE RESTRICT; EXCEPTION WHEN duplicate_object THEN NULL; END $$; `); } public async down(queryRunner: QueryRunner): Promise { await queryRunner.query(` ALTER TABLE freight.booking_cargo_modifier DROP CONSTRAINT IF EXISTS "FK_booking_cargo_modifier_rate_snapshot_id"; `); await queryRunner.query(` ALTER TABLE freight.booking_cargo_modifier DROP CONSTRAINT IF EXISTS "FK_booking_cargo_modifier_surcharge_type_id"; `); await queryRunner.query(` ALTER TABLE freight.booking_cargo_modifier DROP CONSTRAINT IF EXISTS "FK_booking_cargo_modifier_booking_id"; `); await queryRunner.query(` ALTER TABLE freight.booking_approval_step DROP CONSTRAINT IF EXISTS "FK_booking_approval_step_approval_rule_id"; `); await queryRunner.query(` ALTER TABLE freight.booking_approval_step DROP CONSTRAINT IF EXISTS "FK_booking_approval_step_booking_id"; `); await queryRunner.query(` ALTER TABLE freight.booking_rate_snapshot DROP CONSTRAINT IF EXISTS "FK_booking_rate_snapshot_rate_id"; `); await queryRunner.query(` ALTER TABLE freight.booking_rate_snapshot DROP CONSTRAINT IF EXISTS "FK_booking_rate_snapshot_booking_id"; `); await queryRunner.query(` ALTER TABLE freight.booking_container DROP CONSTRAINT IF EXISTS "FK_booking_container_weight_limit_rule_id"; `); await queryRunner.query(` ALTER TABLE freight.booking_container DROP CONSTRAINT IF EXISTS "FK_booking_container_container_type_id"; `); await queryRunner.query(` ALTER TABLE freight.bookings DROP CONSTRAINT IF EXISTS "FK_bookings_consolidation_partner_id"; `); await queryRunner.query(` ALTER TABLE freight.bookings DROP CONSTRAINT IF EXISTS "FK_bookings_previous_contract_id"; `); await queryRunner.query(` ALTER TABLE freight.bookings DROP CONSTRAINT IF EXISTS "FK_bookings_train_id"; `); await queryRunner.query(` ALTER TABLE freight.bookings DROP CONSTRAINT IF EXISTS "FK_bookings_customer_id"; `); } }