diff --git a/hindsight-api-slim/hindsight_api/alembic/versions/f6g7h8i9j0k1_chunk_fk_cascade_delete.py b/hindsight-api-slim/hindsight_api/alembic/versions/f6g7h8i9j0k1_chunk_fk_cascade_delete.py index f0311496..96031733 100644 --- a/hindsight-api-slim/hindsight_api/alembic/versions/f6g7h8i9j0k1_chunk_fk_cascade_delete.py +++ b/hindsight-api-slim/hindsight_api/alembic/versions/f6g7h8i9j0k1_chunk_fk_cascade_delete.py @@ -24,9 +24,28 @@ def upgrade() -> None: the memory_units rows survived with chunk_id = NULL, leaving ghost records. Switching to CASCADE ensures they are removed together with their chunk. """ - op.drop_constraint("memory_units_chunk_fkey", "memory_units", type_="foreignkey") - op.create_foreign_key( - "memory_units_chunk_fkey", "memory_units", "chunks", ["chunk_id"], ["chunk_id"], ondelete="CASCADE" + from alembic import context + + schema = context.config.get_main_option("target_schema") + schema_prefix = f'"{schema}".' if schema else "" + # Use raw SQL with IF EXISTS so this is safe on schemas where the FK was + # already dropped or never existed under this name. + op.execute(f"ALTER TABLE {schema_prefix}memory_units DROP CONSTRAINT IF EXISTS memory_units_chunk_fkey") + # Use a DO block so the ADD is also idempotent: if the FK already exists (e.g. + # the schema was provisioned after the base migration already added it) the + # duplicate_object exception is swallowed rather than failing the migration. + op.execute( + f""" + DO $$ BEGIN + ALTER TABLE {schema_prefix}memory_units + ADD CONSTRAINT memory_units_chunk_fkey + FOREIGN KEY (chunk_id) + REFERENCES {schema_prefix}chunks (chunk_id) + ON DELETE CASCADE; + EXCEPTION + WHEN duplicate_object THEN NULL; + END $$; + """ )