dataset_review_sessions (and potentially other tables in FK_DEFS) are created at runtime by init_db() → Base.metadata.create_all(), not by Alembic migrations. On fresh databases, these tables don't exist when migrations run, causing ALTER TABLE to crash. Fix: check table existence before operating on each FK. If a table doesn't exist, create_all() will create it with the correct FK definition (the model already has ondelete='CASCADE'). This is the same pattern used by other migrations (9f8e7d6c5b4a, ed28d34edde7, c9d8e7f6a5b4, 86c7b1d6a710) for create_all()-only tables like llm_providers, roles, validation_policies, llm_validation_results.
75 lines
2.6 KiB
Python
75 lines
2.6 KiB
Python
"""cascade ondelete for all remaining environments FK references
|
|
|
|
Revision ID: f0e9d8c7b6a5
|
|
Revises: a5b6c7d8e9f0, e5f4d3c2b1a
|
|
Create Date: 2026-05-21 19:00:00.000000
|
|
|
|
@RATIONALE The dataset_review_sessions table is created at runtime by
|
|
init_db() → Base.metadata.create_all(), not by any Alembic migration.
|
|
On a fresh database, it does not exist when Alembic runs (entrypoint
|
|
runs alembic upgrade head BEFORE the backend starts). The model already
|
|
defines the FK with ondelete='CASCADE', so on fresh databases the FK is
|
|
correct. This migration only needs to alter the FK on databases that
|
|
were upgraded from before the FK had CASCADE.
|
|
|
|
Guard: skip dataset_review_sessions FK if the table doesn't exist.
|
|
"""
|
|
from collections.abc import Sequence
|
|
|
|
from alembic import op
|
|
from sqlalchemy import inspect
|
|
|
|
|
|
# revision identifiers, used by Alembic.
|
|
revision: str = 'f0e9d8c7b6a5'
|
|
down_revision: str | Sequence[str] | None = ('a5b6c7d8e9f0', 'e5f4d3c2b1a')
|
|
branch_labels: str | Sequence[str] | None = None
|
|
depends_on: str | Sequence[str] | None = None
|
|
|
|
FK_DEFS = [
|
|
('resource_mappings', 'resource_mappings_environment_id_fkey', 'environment_id'),
|
|
('database_mappings', 'database_mappings_source_env_id_fkey', 'source_env_id'),
|
|
('database_mappings', 'database_mappings_target_env_id_fkey', 'target_env_id'),
|
|
('migration_jobs', 'migration_jobs_source_env_id_fkey', 'source_env_id'),
|
|
('migration_jobs', 'migration_jobs_target_env_id_fkey', 'target_env_id'),
|
|
('dataset_review_sessions', 'dataset_review_sessions_environment_id_fkey', 'environment_id'),
|
|
]
|
|
|
|
|
|
def _table_exists(table: str) -> bool:
|
|
"""Check if a table exists in the current database connection."""
|
|
conn = op.get_bind()
|
|
inspector = inspect(conn)
|
|
return inspector.has_table(table)
|
|
|
|
|
|
def upgrade() -> None:
|
|
"""Upgrade schema."""
|
|
for table, constraint_name, column in FK_DEFS:
|
|
if not _table_exists(table):
|
|
continue
|
|
op.drop_constraint(constraint_name, table, type_='foreignkey')
|
|
op.create_foreign_key(
|
|
constraint_name,
|
|
table,
|
|
'environments',
|
|
[column],
|
|
['id'],
|
|
ondelete='CASCADE',
|
|
)
|
|
|
|
|
|
def downgrade() -> None:
|
|
"""Downgrade schema."""
|
|
for table, constraint_name, column in reversed(FK_DEFS):
|
|
if not _table_exists(table):
|
|
continue
|
|
op.drop_constraint(constraint_name, table, type_='foreignkey')
|
|
op.create_foreign_key(
|
|
constraint_name,
|
|
table,
|
|
'environments',
|
|
[column],
|
|
['id'],
|
|
)
|