import { MigrateUpArgs, MigrateDownArgs, sql } from '@payloadcms/db-postgres' /** * Migration: Add BlogWoman Collections * * Creates: * - favorites table (Affiliate-Produkte) * - favorites_rels (relations to media) * - series table (YouTube-Serien) * - series_locales (localized fields) * - series_rels (relations to media) */ export async function up({ db, payload, req }: MigrateUpArgs): Promise { await db.execute(sql` -- ============================================================ -- ENUMS FOR FAVORITES -- ============================================================ DO $$ BEGIN CREATE TYPE "public"."enum_favorites_category" AS ENUM('fashion', 'beauty', 'travel', 'tech', 'home'); EXCEPTION WHEN duplicate_object THEN null; END $$; DO $$ BEGIN CREATE TYPE "public"."enum_favorites_price_range" AS ENUM('budget', 'mid', 'premium', 'luxury'); EXCEPTION WHEN duplicate_object THEN null; END $$; DO $$ BEGIN CREATE TYPE "public"."enum_favorites_affiliate_network" AS ENUM('amazon', 'awin', 'ltk', 'direct', 'other'); EXCEPTION WHEN duplicate_object THEN null; END $$; DO $$ BEGIN CREATE TYPE "public"."enum_favorites_badge" AS ENUM('investment-piece', 'daily-driver', 'grfi-approved', 'new', 'bestseller'); EXCEPTION WHEN duplicate_object THEN null; END $$; -- ============================================================ -- FAVORITES TABLE -- ============================================================ CREATE TABLE IF NOT EXISTS "favorites" ( "id" serial PRIMARY KEY NOT NULL, "tenant_id" integer, "title" varchar NOT NULL, "slug" varchar NOT NULL, "description" varchar, "category" "enum_favorites_category" NOT NULL, "subcategory" varchar, "price" numeric, "price_range" "enum_favorites_price_range", "affiliate_url" varchar NOT NULL, "affiliate_network" "enum_favorites_affiliate_network", "image_id" integer, "badge" "enum_favorites_badge", "featured" boolean DEFAULT false, "is_active" boolean NOT NULL DEFAULT true, "order" numeric DEFAULT 0, "updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL, "created_at" timestamp(3) with time zone DEFAULT now() NOT NULL ); -- Add unique constraint for slug DO $$ BEGIN ALTER TABLE "favorites" ADD CONSTRAINT "favorites_slug_idx" UNIQUE ("slug"); EXCEPTION WHEN duplicate_table THEN null; WHEN duplicate_object THEN null; END $$; -- Foreign key for tenant DO $$ BEGIN ALTER TABLE "favorites" ADD CONSTRAINT "favorites_tenant_id_tenants_id_fk" FOREIGN KEY ("tenant_id") REFERENCES "public"."tenants"("id") ON DELETE set null ON UPDATE no action; EXCEPTION WHEN duplicate_object THEN null; END $$; -- Foreign key for image DO $$ BEGIN ALTER TABLE "favorites" ADD CONSTRAINT "favorites_image_id_media_id_fk" FOREIGN KEY ("image_id") REFERENCES "public"."media"("id") ON DELETE set null ON UPDATE no action; EXCEPTION WHEN duplicate_object THEN null; END $$; -- Indexes CREATE INDEX IF NOT EXISTS "favorites_tenant_idx" ON "favorites" USING btree ("tenant_id"); CREATE INDEX IF NOT EXISTS "favorites_image_idx" ON "favorites" USING btree ("image_id"); CREATE INDEX IF NOT EXISTS "favorites_created_at_idx" ON "favorites" USING btree ("created_at"); -- ============================================================ -- FAVORITES_RELS TABLE (for polymorphic relations) -- ============================================================ CREATE TABLE IF NOT EXISTS "favorites_rels" ( "id" serial PRIMARY KEY NOT NULL, "order" integer, "parent_id" integer NOT NULL, "path" varchar NOT NULL, "media_id" integer ); DO $$ BEGIN ALTER TABLE "favorites_rels" ADD CONSTRAINT "favorites_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."favorites"("id") ON DELETE cascade ON UPDATE no action; EXCEPTION WHEN duplicate_object THEN null; END $$; DO $$ BEGIN ALTER TABLE "favorites_rels" ADD CONSTRAINT "favorites_rels_media_fk" FOREIGN KEY ("media_id") REFERENCES "public"."media"("id") ON DELETE cascade ON UPDATE no action; EXCEPTION WHEN duplicate_object THEN null; END $$; CREATE INDEX IF NOT EXISTS "favorites_rels_order_idx" ON "favorites_rels" USING btree ("order"); CREATE INDEX IF NOT EXISTS "favorites_rels_parent_idx" ON "favorites_rels" USING btree ("parent_id"); CREATE INDEX IF NOT EXISTS "favorites_rels_path_idx" ON "favorites_rels" USING btree ("path"); CREATE INDEX IF NOT EXISTS "favorites_rels_media_idx" ON "favorites_rels" USING btree ("media_id"); -- ============================================================ -- SERIES TABLE -- ============================================================ CREATE TABLE IF NOT EXISTS "series" ( "id" serial PRIMARY KEY NOT NULL, "tenant_id" integer, "slug" varchar NOT NULL, "logo_id" integer, "cover_image_id" integer, "brand_color" varchar, "accent_color" varchar, "youtube_playlist_id" varchar, "youtube_playlist_url" varchar, "order" numeric DEFAULT 0, "is_active" boolean NOT NULL DEFAULT true, "updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL, "created_at" timestamp(3) with time zone DEFAULT now() NOT NULL ); -- Add unique constraint for slug DO $$ BEGIN ALTER TABLE "series" ADD CONSTRAINT "series_slug_idx" UNIQUE ("slug"); EXCEPTION WHEN duplicate_table THEN null; WHEN duplicate_object THEN null; END $$; -- Foreign keys DO $$ BEGIN ALTER TABLE "series" ADD CONSTRAINT "series_tenant_id_tenants_id_fk" FOREIGN KEY ("tenant_id") REFERENCES "public"."tenants"("id") ON DELETE set null ON UPDATE no action; EXCEPTION WHEN duplicate_object THEN null; END $$; DO $$ BEGIN ALTER TABLE "series" ADD CONSTRAINT "series_logo_id_media_id_fk" FOREIGN KEY ("logo_id") REFERENCES "public"."media"("id") ON DELETE set null ON UPDATE no action; EXCEPTION WHEN duplicate_object THEN null; END $$; DO $$ BEGIN ALTER TABLE "series" ADD CONSTRAINT "series_cover_image_id_media_id_fk" FOREIGN KEY ("cover_image_id") REFERENCES "public"."media"("id") ON DELETE set null ON UPDATE no action; EXCEPTION WHEN duplicate_object THEN null; END $$; -- Indexes CREATE INDEX IF NOT EXISTS "series_tenant_idx" ON "series" USING btree ("tenant_id"); CREATE INDEX IF NOT EXISTS "series_logo_idx" ON "series" USING btree ("logo_id"); CREATE INDEX IF NOT EXISTS "series_cover_image_idx" ON "series" USING btree ("cover_image_id"); CREATE INDEX IF NOT EXISTS "series_created_at_idx" ON "series" USING btree ("created_at"); -- ============================================================ -- SERIES_LOCALES TABLE (for localized fields) -- ============================================================ CREATE TABLE IF NOT EXISTS "series_locales" ( "title" varchar NOT NULL, "tagline" varchar, "description" jsonb, "id" serial PRIMARY KEY NOT NULL, "_locale" "_locales" NOT NULL, "_parent_id" integer NOT NULL ); DO $$ BEGIN ALTER TABLE "series_locales" ADD CONSTRAINT "series_locales_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."series"("id") ON DELETE cascade ON UPDATE no action; EXCEPTION WHEN duplicate_object THEN null; END $$; -- Unique constraint for parent + locale combination DO $$ BEGIN ALTER TABLE "series_locales" ADD CONSTRAINT "series_locales_locale_parent_id_unique" UNIQUE ("_locale", "_parent_id"); EXCEPTION WHEN duplicate_object THEN null; END $$; -- ============================================================ -- SERIES_RELS TABLE (for polymorphic relations) -- ============================================================ CREATE TABLE IF NOT EXISTS "series_rels" ( "id" serial PRIMARY KEY NOT NULL, "order" integer, "parent_id" integer NOT NULL, "path" varchar NOT NULL, "media_id" integer ); DO $$ BEGIN ALTER TABLE "series_rels" ADD CONSTRAINT "series_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."series"("id") ON DELETE cascade ON UPDATE no action; EXCEPTION WHEN duplicate_object THEN null; END $$; DO $$ BEGIN ALTER TABLE "series_rels" ADD CONSTRAINT "series_rels_media_fk" FOREIGN KEY ("media_id") REFERENCES "public"."media"("id") ON DELETE cascade ON UPDATE no action; EXCEPTION WHEN duplicate_object THEN null; END $$; CREATE INDEX IF NOT EXISTS "series_rels_order_idx" ON "series_rels" USING btree ("order"); CREATE INDEX IF NOT EXISTS "series_rels_parent_idx" ON "series_rels" USING btree ("parent_id"); CREATE INDEX IF NOT EXISTS "series_rels_path_idx" ON "series_rels" USING btree ("path"); CREATE INDEX IF NOT EXISTS "series_rels_media_idx" ON "series_rels" USING btree ("media_id"); `) } export async function down({ db, payload, req }: MigrateDownArgs): Promise { await db.execute(sql` -- Drop tables in reverse order of dependencies DROP TABLE IF EXISTS "series_rels"; DROP TABLE IF EXISTS "series_locales"; DROP TABLE IF EXISTS "series"; DROP TABLE IF EXISTS "favorites_rels"; DROP TABLE IF EXISTS "favorites"; -- Drop enums DROP TYPE IF EXISTS "enum_favorites_category"; DROP TYPE IF EXISTS "enum_favorites_price_range"; DROP TYPE IF EXISTS "enum_favorites_affiliate_network"; DROP TYPE IF EXISTS "enum_favorites_badge"; `) }