fix(migrations): add schema parity removal and merge migrations
Added two new migrations to resolve database schema issues: - m8_003_remove_schema_parity_changes: Removes schema parity changes (link_type column, partial index, foreign keys) that were deleted from the models but not from the database. - m9_003_merge_schema_and_action_heads: Merges the two migration heads (m8_003 and a5_006) into a single head to resolve Alembic branching issue. This fixes the database creation timeout issue that was preventing the test suite from running.
This commit is contained in:
+160
@@ -0,0 +1,160 @@
|
||||
"""Remove schema parity changes from resource_links and checkpoint_metadata.
|
||||
|
||||
Reverts the schema changes that were intended to be added by
|
||||
m4_004_schema_parity_resource_decision_checkpoint:
|
||||
|
||||
1. Remove ``link_type`` column from ``resource_links`` table.
|
||||
2. Remove CHECK constraint on ``link_type`` from ``resource_links``.
|
||||
3. Remove partial index ``idx_decisions_superseded`` from ``decisions`` table.
|
||||
4. Remove foreign key constraints from ``checkpoint_metadata`` table.
|
||||
|
||||
Revision ID: m8_003_remove_schema_parity_changes
|
||||
Revises: m8_002_merge_profile_rename_and_corrections
|
||||
Create Date: 2026-04-22 00:00:00
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Sequence
|
||||
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = "m8_003_remove_schema_parity_changes"
|
||||
down_revision: str | Sequence[str] | None = (
|
||||
"m8_002_merge_profile_rename_and_corrections"
|
||||
)
|
||||
branch_labels: str | Sequence[str] | None = None
|
||||
depends_on: str | Sequence[str] | None = None
|
||||
|
||||
|
||||
def _inspector() -> sa.Inspector:
|
||||
return sa.inspect(op.get_bind())
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
"""Remove schema parity changes."""
|
||||
inspector = _inspector()
|
||||
|
||||
# Remove link_type column from resource_links if it exists
|
||||
resource_link_columns = {
|
||||
column["name"] for column in inspector.get_columns("resource_links")
|
||||
}
|
||||
if "link_type" in resource_link_columns:
|
||||
check_constraints = inspector.get_check_constraints("resource_links")
|
||||
has_link_type_ck = any(
|
||||
ck.get("name") == "ck_resource_links_link_type"
|
||||
for ck in check_constraints
|
||||
)
|
||||
with op.batch_alter_table("resource_links") as batch_op:
|
||||
if has_link_type_ck:
|
||||
batch_op.drop_constraint(
|
||||
"ck_resource_links_link_type", type_="check"
|
||||
)
|
||||
batch_op.drop_column("link_type")
|
||||
|
||||
# Remove partial index from decisions if it exists
|
||||
decision_indexes = {
|
||||
index["name"] for index in inspector.get_indexes("decisions")
|
||||
}
|
||||
if "idx_decisions_superseded" in decision_indexes:
|
||||
op.drop_index("idx_decisions_superseded", table_name="decisions")
|
||||
|
||||
# Remove foreign key constraints from checkpoint_metadata if they exist
|
||||
checkpoint_fks = inspector.get_foreign_keys("checkpoint_metadata")
|
||||
fk_names = {fk.get("name") for fk in checkpoint_fks}
|
||||
if (
|
||||
"fk_checkpoint_metadata_decision" in fk_names
|
||||
or "fk_checkpoint_metadata_resource" in fk_names
|
||||
):
|
||||
with op.batch_alter_table("checkpoint_metadata") as batch_op:
|
||||
if "fk_checkpoint_metadata_decision" in fk_names:
|
||||
batch_op.drop_constraint(
|
||||
"fk_checkpoint_metadata_decision",
|
||||
type_="foreignkey",
|
||||
)
|
||||
if "fk_checkpoint_metadata_resource" in fk_names:
|
||||
batch_op.drop_constraint(
|
||||
"fk_checkpoint_metadata_resource",
|
||||
type_="foreignkey",
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
"""Restore schema parity changes."""
|
||||
inspector = _inspector()
|
||||
|
||||
# Restore link_type column to resource_links
|
||||
resource_link_columns = {
|
||||
column["name"] for column in inspector.get_columns("resource_links")
|
||||
}
|
||||
if "link_type" not in resource_link_columns:
|
||||
with op.batch_alter_table("resource_links") as batch_op:
|
||||
batch_op.add_column(
|
||||
sa.Column(
|
||||
"link_type",
|
||||
sa.Text(),
|
||||
nullable=False,
|
||||
server_default=sa.text("'contains'"),
|
||||
)
|
||||
)
|
||||
batch_op.create_check_constraint(
|
||||
"ck_resource_links_link_type",
|
||||
"link_type IN ('contains', 'references', 'derived_from')",
|
||||
)
|
||||
|
||||
# Restore partial index on decisions
|
||||
decision_indexes = {
|
||||
index["name"] for index in inspector.get_indexes("decisions")
|
||||
}
|
||||
if "idx_decisions_superseded" not in decision_indexes:
|
||||
op.create_index(
|
||||
"idx_decisions_superseded",
|
||||
"decisions",
|
||||
["superseded_by"],
|
||||
unique=False,
|
||||
postgresql_where=sa.text("superseded_by IS NOT NULL"),
|
||||
sqlite_where=sa.text("superseded_by IS NOT NULL"),
|
||||
)
|
||||
|
||||
# Restore foreign key constraints on checkpoint_metadata
|
||||
checkpoint_fks = inspector.get_foreign_keys("checkpoint_metadata")
|
||||
fk_signatures = {
|
||||
(
|
||||
tuple(fk.get("constrained_columns") or []),
|
||||
fk.get("referred_table"),
|
||||
tuple(fk.get("referred_columns") or []),
|
||||
)
|
||||
for fk in checkpoint_fks
|
||||
}
|
||||
|
||||
needs_decision_fk = (
|
||||
("decision_id",),
|
||||
"decisions",
|
||||
("decision_id",),
|
||||
) not in fk_signatures
|
||||
needs_resource_fk = (
|
||||
("resource_id",),
|
||||
"resources",
|
||||
("resource_id",),
|
||||
) not in fk_signatures
|
||||
|
||||
if needs_decision_fk or needs_resource_fk:
|
||||
with op.batch_alter_table("checkpoint_metadata") as batch_op:
|
||||
if needs_decision_fk:
|
||||
batch_op.create_foreign_key(
|
||||
"fk_checkpoint_metadata_decision",
|
||||
"decisions",
|
||||
["decision_id"],
|
||||
["decision_id"],
|
||||
ondelete="SET NULL",
|
||||
)
|
||||
if needs_resource_fk:
|
||||
batch_op.create_foreign_key(
|
||||
"fk_checkpoint_metadata_resource",
|
||||
"resources",
|
||||
["resource_id"],
|
||||
["resource_id"],
|
||||
ondelete="SET NULL",
|
||||
)
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
"""Merge schema parity removal and action invariants heads.
|
||||
|
||||
m8_003_remove_schema_parity_changes and a5_006_action_invariants_unique_constraint
|
||||
branched from different parents, creating two Alembic heads.
|
||||
This no-op merge migration resolves them into a single head.
|
||||
|
||||
Revision ID: m9_003_merge_schema_and_action_heads
|
||||
Revises: m8_003_remove_schema_parity_changes, a5_006_action_invariants_unique_constraint
|
||||
Create Date: 2026-04-22 00:00:00
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Sequence
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = "m9_003_merge_schema_and_action_heads"
|
||||
down_revision: str | Sequence[str] | None = (
|
||||
"m8_003_remove_schema_parity_changes",
|
||||
"a5_006_action_invariants_unique_constraint",
|
||||
)
|
||||
branch_labels: str | Sequence[str] | None = None
|
||||
depends_on: str | Sequence[str] | None = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
"""Upgrade schema."""
|
||||
pass
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
"""Downgrade schema."""
|
||||
pass
|
||||
Reference in New Issue
Block a user