-- Las compras dejan de apuntar a un texto y apuntan a la canción. -- -- Siete tablas guardaban `cancion_slug` sin clave foránea, porque cuando se -- escribieron el catálogo vivía en archivos y no había a qué apuntar. -- Renombrar un slug dejaba huérfana una compra **en silencio**: nadie se -- enteraba hasta que alguien intentaba descargar lo que había pagado. -- -- Ahora apuntan a `cancion.id`, que es opaco y no cambia nunca. El slug se -- queda de momento en su columna, sin obligación, y se borra en la migración -- siguiente: así el despliegue no necesita parar el sitio —la versión vieja -- del código sigue leyendo su columna mientras la nueva ya escribe la otra—. -- -- El borrado no se propaga igual en todas: -- -- · `compra`, `pedido_item` y `descarga` lo RESTRINGEN. Una canción que -- alguien ha pagado no se puede borrar de la base, y el registro de -- entrega tiene que sobrevivir a lo que prueba. Para sacar un tema del -- catálogo está `estado = 'retirado'`, que es lo que esa columna vino a -- resolver. -- · `carrito_item`, `favorito`, `valoracion` y `reproduccion` CAEN con ella: -- sin la canción no significan nada. DROP INDEX "reproduccion_cancion";--> statement-breakpoint DROP INDEX "idx_valoracion_cancion";--> statement-breakpoint -- Primero la columna vacía; el `NOT NULL` va al final, cuando esté llena. ALTER TABLE "descarga" ADD COLUMN "cancion_id" text;--> statement-breakpoint ALTER TABLE "carrito_item" ADD COLUMN "cancion_id" text;--> statement-breakpoint ALTER TABLE "compra" ADD COLUMN "cancion_id" text;--> statement-breakpoint ALTER TABLE "pedido_item" ADD COLUMN "cancion_id" text;--> statement-breakpoint ALTER TABLE "favorito" ADD COLUMN "cancion_id" text;--> statement-breakpoint ALTER TABLE "reproduccion" ADD COLUMN "cancion_id" text;--> statement-breakpoint ALTER TABLE "valoracion" ADD COLUMN "cancion_id" text;--> statement-breakpoint UPDATE "descarga" d SET "cancion_id" = c."id" FROM "cancion" c WHERE c."slug" = d."cancion_slug";--> statement-breakpoint UPDATE "carrito_item" t SET "cancion_id" = c."id" FROM "cancion" c WHERE c."slug" = t."cancion_slug";--> statement-breakpoint UPDATE "compra" t SET "cancion_id" = c."id" FROM "cancion" c WHERE c."slug" = t."cancion_slug";--> statement-breakpoint UPDATE "pedido_item" t SET "cancion_id" = c."id" FROM "cancion" c WHERE c."slug" = t."cancion_slug";--> statement-breakpoint UPDATE "favorito" t SET "cancion_id" = c."id" FROM "cancion" c WHERE c."slug" = t."cancion_slug";--> statement-breakpoint UPDATE "reproduccion" t SET "cancion_id" = c."id" FROM "cancion" c WHERE c."slug" = t."cancion_slug";--> statement-breakpoint UPDATE "valoracion" t SET "cancion_id" = c."id" FROM "cancion" c WHERE c."slug" = t."cancion_slug";--> statement-breakpoint -- Lo que no se pudo traducir. -- -- En lo que vale dinero, la migración se para: una compra que apunta a un slug -- que ya no existe es exactamente el fallo que esto viene a arreglar, y -- borrarla en silencio sería repetirlo con otra forma. Hay que mirar esas -- filas a mano y decidir. DO $$ DECLARE sueltas integer; BEGIN SELECT (SELECT count(*) FROM "compra" WHERE "cancion_id" IS NULL) + (SELECT count(*) FROM "pedido_item" WHERE "cancion_id" IS NULL) + (SELECT count(*) FROM "descarga" WHERE "cancion_id" IS NULL) INTO sueltas; IF sueltas > 0 THEN RAISE EXCEPTION 'Hay % filas de compra, pedido_item o descarga cuyo cancion_slug no existe en cancion. Revísalas antes de migrar: son temas pagados que apuntan a la nada.', sueltas; END IF; END $$;--> statement-breakpoint -- En lo que no vale dinero sí se borran, pero se dice cuántas. DO $$ DECLARE quitadas integer := 0; n integer; BEGIN DELETE FROM "carrito_item" WHERE "cancion_id" IS NULL; GET DIAGNOSTICS n = ROW_COUNT; quitadas := quitadas + n; DELETE FROM "favorito" WHERE "cancion_id" IS NULL; GET DIAGNOSTICS n = ROW_COUNT; quitadas := quitadas + n; DELETE FROM "valoracion" WHERE "cancion_id" IS NULL; GET DIAGNOSTICS n = ROW_COUNT; quitadas := quitadas + n; DELETE FROM "reproduccion" WHERE "cancion_id" IS NULL; GET DIAGNOSTICS n = ROW_COUNT; quitadas := quitadas + n; IF quitadas > 0 THEN RAISE NOTICE 'Se han borrado % filas de carrito, favoritos, valoraciones o escuchas que apuntaban a un tema inexistente.', quitadas; END IF; END $$;--> statement-breakpoint ALTER TABLE "descarga" ALTER COLUMN "cancion_id" SET NOT NULL;--> statement-breakpoint ALTER TABLE "carrito_item" ALTER COLUMN "cancion_id" SET NOT NULL;--> statement-breakpoint ALTER TABLE "compra" ALTER COLUMN "cancion_id" SET NOT NULL;--> statement-breakpoint ALTER TABLE "pedido_item" ALTER COLUMN "cancion_id" SET NOT NULL;--> statement-breakpoint ALTER TABLE "favorito" ALTER COLUMN "cancion_id" SET NOT NULL;--> statement-breakpoint ALTER TABLE "reproduccion" ALTER COLUMN "cancion_id" SET NOT NULL;--> statement-breakpoint ALTER TABLE "valoracion" ALTER COLUMN "cancion_id" SET NOT NULL;--> statement-breakpoint -- La identidad de la fila pasa a ser el par cuenta-canción, no cuenta-texto. ALTER TABLE "carrito_item" DROP CONSTRAINT "carrito_item_carrito_id_cancion_slug_pk";--> statement-breakpoint ALTER TABLE "compra" DROP CONSTRAINT "compra_usuario_id_cancion_slug_pk";--> statement-breakpoint ALTER TABLE "pedido_item" DROP CONSTRAINT "pedido_item_pedido_id_cancion_slug_pk";--> statement-breakpoint ALTER TABLE "favorito" DROP CONSTRAINT "favorito_usuario_id_cancion_slug_pk";--> statement-breakpoint ALTER TABLE "valoracion" DROP CONSTRAINT "valoracion_usuario_id_cancion_slug_pk";--> statement-breakpoint ALTER TABLE "carrito_item" ADD CONSTRAINT "carrito_item_carrito_id_cancion_id_pk" PRIMARY KEY("carrito_id","cancion_id");--> statement-breakpoint ALTER TABLE "compra" ADD CONSTRAINT "compra_usuario_id_cancion_id_pk" PRIMARY KEY("usuario_id","cancion_id");--> statement-breakpoint ALTER TABLE "pedido_item" ADD CONSTRAINT "pedido_item_pedido_id_cancion_id_pk" PRIMARY KEY("pedido_id","cancion_id");--> statement-breakpoint ALTER TABLE "favorito" ADD CONSTRAINT "favorito_usuario_id_cancion_id_pk" PRIMARY KEY("usuario_id","cancion_id");--> statement-breakpoint ALTER TABLE "valoracion" ADD CONSTRAINT "valoracion_usuario_id_cancion_id_pk" PRIMARY KEY("usuario_id","cancion_id");--> statement-breakpoint -- La columna vieja se queda un despliegue más, ya sin obligar a nada. ALTER TABLE "descarga" ALTER COLUMN "cancion_slug" DROP NOT NULL;--> statement-breakpoint ALTER TABLE "carrito_item" ALTER COLUMN "cancion_slug" DROP NOT NULL;--> statement-breakpoint ALTER TABLE "compra" ALTER COLUMN "cancion_slug" DROP NOT NULL;--> statement-breakpoint ALTER TABLE "pedido_item" ALTER COLUMN "cancion_slug" DROP NOT NULL;--> statement-breakpoint ALTER TABLE "favorito" ALTER COLUMN "cancion_slug" DROP NOT NULL;--> statement-breakpoint ALTER TABLE "reproduccion" ALTER COLUMN "cancion_slug" DROP NOT NULL;--> statement-breakpoint ALTER TABLE "valoracion" ALTER COLUMN "cancion_slug" DROP NOT NULL;--> statement-breakpoint ALTER TABLE "descarga" ADD CONSTRAINT "descarga_cancion_id_cancion_id_fk" FOREIGN KEY ("cancion_id") REFERENCES "public"."cancion"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint ALTER TABLE "carrito_item" ADD CONSTRAINT "carrito_item_cancion_id_cancion_id_fk" FOREIGN KEY ("cancion_id") REFERENCES "public"."cancion"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint ALTER TABLE "compra" ADD CONSTRAINT "compra_cancion_id_cancion_id_fk" FOREIGN KEY ("cancion_id") REFERENCES "public"."cancion"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint ALTER TABLE "pedido_item" ADD CONSTRAINT "pedido_item_cancion_id_cancion_id_fk" FOREIGN KEY ("cancion_id") REFERENCES "public"."cancion"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint ALTER TABLE "favorito" ADD CONSTRAINT "favorito_cancion_id_cancion_id_fk" FOREIGN KEY ("cancion_id") REFERENCES "public"."cancion"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint ALTER TABLE "reproduccion" ADD CONSTRAINT "reproduccion_cancion_id_cancion_id_fk" FOREIGN KEY ("cancion_id") REFERENCES "public"."cancion"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint ALTER TABLE "valoracion" ADD CONSTRAINT "valoracion_cancion_id_cancion_id_fk" FOREIGN KEY ("cancion_id") REFERENCES "public"."cancion"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint CREATE INDEX "reproduccion_cancion" ON "reproduccion" USING btree ("cancion_id");--> statement-breakpoint CREATE INDEX "idx_valoracion_cancion" ON "valoracion" USING btree ("cancion_id");