"""Remove product variant system — products are unique, no variant concept. Revision ID: 027 Revises: 026 Create Date: 2026-03-03 """ from alembic import op import sqlalchemy as sa revision = "027" down_revision = "026" branch_labels = None depends_on = None NIL_UUID = "00000000-0000-0000-0000-000000000000" def upgrade() -> None: # Drop variant-aware unique indexes on order_lines op.execute("DROP INDEX IF EXISTS uq_order_lines_tracking") op.execute("DROP INDEX IF EXISTS uq_order_lines_render") # Drop variant_id column from order_lines op.execute("ALTER TABLE order_lines DROP COLUMN IF EXISTS variant_id") # Deduplicate tracking-only lines (output_type_id IS NULL) — keep the newest row per # (order_id, product_id) pair so the unique index can be created cleanly. op.execute(""" DELETE FROM order_lines WHERE output_type_id IS NULL AND id NOT IN ( SELECT DISTINCT ON (order_id, product_id) id FROM order_lines WHERE output_type_id IS NULL ORDER BY order_id, product_id, created_at DESC ) """) # Deduplicate render lines — keep the newest row per (order_id, product_id, output_type_id). op.execute(""" DELETE FROM order_lines WHERE output_type_id IS NOT NULL AND id NOT IN ( SELECT DISTINCT ON (order_id, product_id, output_type_id) id FROM order_lines WHERE output_type_id IS NOT NULL ORDER BY order_id, product_id, output_type_id, created_at DESC ) """) # Recreate simpler unique indexes without variant_id op.execute( "CREATE UNIQUE INDEX uq_order_lines_tracking " "ON order_lines (order_id, product_id) " "WHERE output_type_id IS NULL" ) op.execute( "CREATE UNIQUE INDEX uq_order_lines_render " "ON order_lines (order_id, product_id, output_type_id) " "WHERE output_type_id IS NOT NULL" ) # Drop product_variants table (CASCADE removes its indexes automatically) op.execute("DROP TABLE IF EXISTS product_variants CASCADE") def downgrade() -> None: # Recreate product_variants table op.execute(""" CREATE TABLE product_variants ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), product_id UUID NOT NULL REFERENCES products(id) ON DELETE CASCADE, name VARCHAR(500) NOT NULL, gewuenschte_bildnummer VARCHAR(500), components JSONB NOT NULL DEFAULT '[]', is_default BOOLEAN NOT NULL DEFAULT false, source_excel VARCHAR(1000), created_at TIMESTAMP NOT NULL DEFAULT NOW(), updated_at TIMESTAMP NOT NULL DEFAULT NOW() ) """) op.execute( "CREATE UNIQUE INDEX uq_product_variants_product_name " "ON product_variants (product_id, lower(name))" ) op.execute("CREATE INDEX ON product_variants (product_id)") # Add back variant_id to order_lines op.execute( "ALTER TABLE order_lines ADD COLUMN variant_id UUID " "REFERENCES product_variants(id) ON DELETE SET NULL" ) # Drop simple indexes and restore variant-aware indexes op.execute("DROP INDEX IF EXISTS uq_order_lines_tracking") op.execute("DROP INDEX IF EXISTS uq_order_lines_render") op.execute( "CREATE UNIQUE INDEX uq_order_lines_tracking " f"ON order_lines (order_id, product_id, COALESCE(variant_id, '{NIL_UUID}'::uuid)) " "WHERE output_type_id IS NULL" ) op.execute( "CREATE UNIQUE INDEX uq_order_lines_render " "ON order_lines (order_id, product_id, output_type_id, " f"COALESCE(variant_id, '{NIL_UUID}'::uuid)) " "WHERE output_type_id IS NOT NULL" )