From 4e09a66fbff1b3d10ebf1ca96d89c0f9c303980b Mon Sep 17 00:00:00 2001 From: saeed Date: Tue, 27 Oct 2026 17:46:41 +0330 Subject: [PATCH] fix(api): relink legacy cities after province inserts in seed_iran_cities The migration re-pointed Branch/Customer at hardcoded prov-* ids before they existed (the insert is skipped when a city already has the name), causing Branch_cityId_fkey failures on boot. Merge now runs after the inserts, resolves the target province by name, and relinks every table with a City foreign key before deleting the legacy row. Co-Authored-By: Claude Sonnet 5.5 --- .../migration.sql | 60 ++++++++++++------- .../migration.sql | 60 ++++++++++++------- 2 files changed, 74 insertions(+), 46 deletions(-) diff --git a/apps/api/prisma/migrations/20261025120000_seed_iran_cities/migration.sql b/apps/api/prisma/migrations/20261025120000_seed_iran_cities/migration.sql index c5a7150..5a5993f 100644 --- a/apps/api/prisma/migrations/20261025120000_seed_iran_cities/migration.sql +++ b/apps/api/prisma/migrations/20261025120000_seed_iran_cities/migration.sql @@ -5,29 +5,6 @@ INSERT INTO "City" ("id", "name", "parentId") VALUES ('city-iran', 'ایران', NULL) ON CONFLICT ("id") DO NOTHING; --- If rows with 'city-tehran', etc. exist and have child relations, re-link them before cleanup -DO $$ -BEGIN - IF EXISTS (SELECT 1 FROM "City" WHERE "id" = 'city-tehran') THEN - UPDATE "Customer" SET "cityId" = 'prov-e9dedb90e02298da' WHERE "cityId" = 'city-tehran'; - UPDATE "Branch" SET "cityId" = 'prov-e9dedb90e02298da' WHERE "cityId" = 'city-tehran'; - DELETE FROM "City" WHERE "id" = 'city-tehran'; - END IF; - IF EXISTS (SELECT 1 FROM "City" WHERE "id" = 'city-mashhad') THEN - UPDATE "Customer" SET "cityId" = 'prov-e10485d2d3377704' WHERE "cityId" = 'city-mashhad'; - UPDATE "Branch" SET "cityId" = 'prov-e10485d2d3377704' WHERE "cityId" = 'city-mashhad'; - DELETE FROM "City" WHERE "id" = 'city-mashhad'; - END IF; - IF EXISTS (SELECT 1 FROM "City" WHERE "id" = 'city-isfahan') THEN - UPDATE "Customer" SET "cityId" = 'prov-4bb74d0dee027e26' WHERE "cityId" = 'city-isfahan'; - DELETE FROM "City" WHERE "id" = 'city-isfahan'; - END IF; - IF EXISTS (SELECT 1 FROM "City" WHERE "id" = 'city-tabriz') THEN - UPDATE "Customer" SET "cityId" = 'prov-368ec488a60e1e68' WHERE "cityId" = 'city-tabriz'; - DELETE FROM "City" WHERE "id" = 'city-tabriz'; - END IF; -END $$; - -- Strip any existing 'استان ' prefix UPDATE "City" SET "name" = regexp_replace("name", '^استان\s+', '') @@ -157,6 +134,43 @@ INSERT INTO "City" ("id", "name", "parentId") SELECT 'prov-8eafb7340d3dfe31', 'یزد', 'city-iran' WHERE NOT EXISTS (SELECT 1 FROM "City" WHERE "name" = 'یزد'); +-- Legacy demo cities (city-tehran, ...) are folded into their province. This +-- runs after the province inserts and the prefix strip so the target exists, +-- and the target is looked up by name under 'city-iran' rather than assumed: +-- when a legacy row already carried the province's name the 'prov-*' insert +-- above was skipped, and the province is then e.g. 'city-prov-tehran'. +-- Every table with a City foreign key is re-pointed before the delete. +DO $$ +DECLARE + m RECORD; + t TEXT; + target TEXT; +BEGIN + FOR m IN + SELECT * FROM (VALUES + ('city-tehran', 'تهران'), + ('city-mashhad', 'خراسان رضوی'), + ('city-isfahan', 'اصفهان'), + ('city-tabriz', 'آذربایجان شرقی') + ) AS v(legacy_id, province_name) + LOOP + IF NOT EXISTS (SELECT 1 FROM "City" WHERE "id" = m.legacy_id) THEN + CONTINUE; + END IF; + SELECT "id" INTO target FROM "City" + WHERE "name" = m.province_name AND "parentId" = 'city-iran' AND "id" <> m.legacy_id + ORDER BY "id" LIMIT 1; + IF target IS NULL THEN + CONTINUE; + END IF; + FOREACH t IN ARRAY ARRAY['Customer', 'CustomerAddress', 'Branch', 'PreOrder', 'SalesExpertProfile'] + LOOP + EXECUTE format('UPDATE %I SET "cityId" = %L WHERE "cityId" = %L', t, target, m.legacy_id); + END LOOP; + DELETE FROM "City" WHERE "id" = m.legacy_id; + END LOOP; +END $$; + UPDATE "City" SET "parentId" = 'city-iran' WHERE "parentId" IS NULL AND "id" <> 'city-iran'; diff --git a/apps/api/release/migrations/20261025120000_seed_iran_cities/migration.sql b/apps/api/release/migrations/20261025120000_seed_iran_cities/migration.sql index c5a7150..5a5993f 100644 --- a/apps/api/release/migrations/20261025120000_seed_iran_cities/migration.sql +++ b/apps/api/release/migrations/20261025120000_seed_iran_cities/migration.sql @@ -5,29 +5,6 @@ INSERT INTO "City" ("id", "name", "parentId") VALUES ('city-iran', 'ایران', NULL) ON CONFLICT ("id") DO NOTHING; --- If rows with 'city-tehran', etc. exist and have child relations, re-link them before cleanup -DO $$ -BEGIN - IF EXISTS (SELECT 1 FROM "City" WHERE "id" = 'city-tehran') THEN - UPDATE "Customer" SET "cityId" = 'prov-e9dedb90e02298da' WHERE "cityId" = 'city-tehran'; - UPDATE "Branch" SET "cityId" = 'prov-e9dedb90e02298da' WHERE "cityId" = 'city-tehran'; - DELETE FROM "City" WHERE "id" = 'city-tehran'; - END IF; - IF EXISTS (SELECT 1 FROM "City" WHERE "id" = 'city-mashhad') THEN - UPDATE "Customer" SET "cityId" = 'prov-e10485d2d3377704' WHERE "cityId" = 'city-mashhad'; - UPDATE "Branch" SET "cityId" = 'prov-e10485d2d3377704' WHERE "cityId" = 'city-mashhad'; - DELETE FROM "City" WHERE "id" = 'city-mashhad'; - END IF; - IF EXISTS (SELECT 1 FROM "City" WHERE "id" = 'city-isfahan') THEN - UPDATE "Customer" SET "cityId" = 'prov-4bb74d0dee027e26' WHERE "cityId" = 'city-isfahan'; - DELETE FROM "City" WHERE "id" = 'city-isfahan'; - END IF; - IF EXISTS (SELECT 1 FROM "City" WHERE "id" = 'city-tabriz') THEN - UPDATE "Customer" SET "cityId" = 'prov-368ec488a60e1e68' WHERE "cityId" = 'city-tabriz'; - DELETE FROM "City" WHERE "id" = 'city-tabriz'; - END IF; -END $$; - -- Strip any existing 'استان ' prefix UPDATE "City" SET "name" = regexp_replace("name", '^استان\s+', '') @@ -157,6 +134,43 @@ INSERT INTO "City" ("id", "name", "parentId") SELECT 'prov-8eafb7340d3dfe31', 'یزد', 'city-iran' WHERE NOT EXISTS (SELECT 1 FROM "City" WHERE "name" = 'یزد'); +-- Legacy demo cities (city-tehran, ...) are folded into their province. This +-- runs after the province inserts and the prefix strip so the target exists, +-- and the target is looked up by name under 'city-iran' rather than assumed: +-- when a legacy row already carried the province's name the 'prov-*' insert +-- above was skipped, and the province is then e.g. 'city-prov-tehran'. +-- Every table with a City foreign key is re-pointed before the delete. +DO $$ +DECLARE + m RECORD; + t TEXT; + target TEXT; +BEGIN + FOR m IN + SELECT * FROM (VALUES + ('city-tehran', 'تهران'), + ('city-mashhad', 'خراسان رضوی'), + ('city-isfahan', 'اصفهان'), + ('city-tabriz', 'آذربایجان شرقی') + ) AS v(legacy_id, province_name) + LOOP + IF NOT EXISTS (SELECT 1 FROM "City" WHERE "id" = m.legacy_id) THEN + CONTINUE; + END IF; + SELECT "id" INTO target FROM "City" + WHERE "name" = m.province_name AND "parentId" = 'city-iran' AND "id" <> m.legacy_id + ORDER BY "id" LIMIT 1; + IF target IS NULL THEN + CONTINUE; + END IF; + FOREACH t IN ARRAY ARRAY['Customer', 'CustomerAddress', 'Branch', 'PreOrder', 'SalesExpertProfile'] + LOOP + EXECUTE format('UPDATE %I SET "cityId" = %L WHERE "cityId" = %L', t, target, m.legacy_id); + END LOOP; + DELETE FROM "City" WHERE "id" = m.legacy_id; + END LOOP; +END $$; + UPDATE "City" SET "parentId" = 'city-iran' WHERE "parentId" IS NULL AND "id" <> 'city-iran';