fix(migrations): rend la migration ingredient_taxonomy_rework safe sur des données existantes

La version générée automatiquement par `prisma migrate diff` castait
directement chaque valeur `category` existante (ancien enum à 18
valeurs) vers le nouvel enum à 7 valeurs — échoue pour toute ligne déjà
seedée, puisqu'aucune ancienne valeur n'existe dans le nouvel enum.
En local ça passait inaperçu (reset complet sur une base vide), mais en
production (données déjà seedées) la migration échoue avec "invalid
input value for enum".

Réécrite pour ajouter les nouvelles colonnes avec une valeur par défaut
sûre (aucun cast des données existantes), puis les substituer aux
anciennes — même logique que les défauts `@default(...)` déjà
documentés dans schema.prisma : seedReferenceData() (relancée à chaque
démarrage du conteneur, voir apps/api/Dockerfile) corrige tout de suite
après la vraie catégorie/sous-catégorie de chaque ligne.

Ajoute aussi un DROP TYPE IF EXISTS défensif : une tentative précédente
de cette migration laisse le type IngredientSubcategory orphelin (son
CREATE TYPE s'exécute hors de la transaction qui échoue plus loin), une
nouvelle tentative sans ce garde-fou échouerait différemment ("type
already exists").

Vérifiée en rejouant l'historique complet des migrations sur une base
de test jetable, avec des lignes portant les anciennes valeurs d'enum
insérées à la main pour reproduire exactement l'échec signalé — la
version corrigée s'applique proprement et préserve les id existants
(donc toute vraie ligne RecipeIngredient qui y référence).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Nicolas 2026-08-18 12:47:14 +02:00
parent 78e0f89503
commit d761a3795f

View file

@ -1,18 +1,38 @@
-- Rewritten after this migration failed on a database that already had
-- seeded ingredient rows: the original version (auto-generated by `prisma
-- migrate diff`) cast every existing `category` value directly from the
-- old 18-value enum to the new 7-value one, which fails for every row
-- since none of the old values exist in the new enum. This version instead
-- adds the new columns with a safe default (never casting existing data),
-- then swaps them in — the same "add with a default, correct for real on
-- the next seed run" pattern already used for `IngredientCategory`'s and
-- `IngredientSubcategory`'s own `@default(...)` (see their doc comments in
-- schema.prisma). `seedReferenceData()` runs right after `migrate deploy`
-- on every container start (see apps/api/Dockerfile) and corrects every
-- row's real category/subcategory immediately.
--
-- `DROP TYPE IF EXISTS "IngredientSubcategory"` guards against a previous
-- failed attempt at this exact migration: that CREATE TYPE statement runs
-- outside the AlterEnum transaction below and so persists even though the
-- rest of that failed attempt rolled back — retrying without this guard
-- would hit "type already exists".
-- CreateEnum
DROP TYPE IF EXISTS "IngredientSubcategory";
CREATE TYPE "IngredientSubcategory" AS ENUM ('LEGUMES', 'FRUITS', 'HERBES_FRAICHES', 'VIANDES', 'VOLAILLES', 'POISSONS', 'CRUSTACES_FRUITS_DE_MER', 'FECULENTS', 'LEGUMINEUSES', 'GRAINES_FRUITS_SECS', 'AUTRES', 'PAINS', 'PATES_A_CUIRE', 'PRODUITS_LAITIERS', 'OEUFS', 'ALTERNATIVES', 'EPICES', 'SAUCES', 'ASSAISONNEMENTS', 'BASES', 'EPAISSISSANTS', 'SUCRES');
-- AlterEnum
BEGIN;
-- CreateEnum
DROP TYPE IF EXISTS "IngredientCategory_new";
CREATE TYPE "IngredientCategory_new" AS ENUM ('PRODUITS_FRAIS', 'BOUCHERIE_POISSONNERIE', 'EPICERIE_SECHE', 'BOULANGERIE', 'CREMERIE_FROMAGE', 'CONDIMENTS_EPICES', 'AIDES_CULINAIRES');
ALTER TABLE "ingredients" ALTER COLUMN "category" DROP DEFAULT;
ALTER TABLE "ingredients" ALTER COLUMN "category" TYPE "IngredientCategory_new" USING ("category"::text::"IngredientCategory_new");
ALTER TYPE "IngredientCategory" RENAME TO "IngredientCategory_old";
-- AlterTable: add the new columns at their defaults — no cast of existing
-- `category` values, so this succeeds regardless of what the table
-- currently holds.
ALTER TABLE "ingredients" ADD COLUMN "category_new" "IngredientCategory_new" NOT NULL DEFAULT 'EPICERIE_SECHE';
ALTER TABLE "ingredients" ADD COLUMN "subcategory" "IngredientSubcategory" NOT NULL DEFAULT 'AUTRES';
-- Swap the old `category` column (old 18-value enum) out for the new one.
ALTER TABLE "ingredients" DROP COLUMN "category";
ALTER TABLE "ingredients" RENAME COLUMN "category_new" TO "category";
DROP TYPE "IngredientCategory";
ALTER TYPE "IngredientCategory_new" RENAME TO "IngredientCategory";
DROP TYPE "IngredientCategory_old";
ALTER TABLE "ingredients" ALTER COLUMN "category" SET DEFAULT 'EPICERIE_SECHE';
COMMIT;
-- AlterTable
ALTER TABLE "ingredients" ADD COLUMN "subcategory" "IngredientSubcategory" NOT NULL DEFAULT 'AUTRES',
ALTER COLUMN "category" SET DEFAULT 'EPICERIE_SECHE';