diff --git a/app/migrations/env.py b/app/migrations/env.py index 21b45ab..6a9ac98 100644 --- a/app/migrations/env.py +++ b/app/migrations/env.py @@ -69,8 +69,12 @@ def run_migrations_online() -> None: ) with connectable.connect() as connection: + # Enable batch mode for SQLite to support ALTER TABLE operations + # like DROP COLUMN which SQLite doesn't natively support context.configure( - connection=connection, target_metadata=target_metadata + connection=connection, + target_metadata=target_metadata, + render_as_batch=True ) with context.begin_transaction(): diff --git a/app/migrations/versions/009_remove_cidrs.py b/app/migrations/versions/009_remove_cidrs.py index 3f2bef3..42eb203 100644 --- a/app/migrations/versions/009_remove_cidrs.py +++ b/app/migrations/versions/009_remove_cidrs.py @@ -119,12 +119,15 @@ def upgrade(): print(" ⚠ Table site_cidrs not found or already dropped\n") # Step 5: Drop site_cidr_id column from site_ips + # Use batch mode for SQLite compatibility (SQLite doesn't support DROP COLUMN directly) print("Step 5: Dropping site_cidr_id column from site_ips...") site_ips_columns = [col['name'] for col in inspector.get_columns('site_ips')] if 'site_cidr_id' in site_ips_columns: try: - op.drop_column('site_ips', 'site_cidr_id') + # Use batch_alter_table for SQLite compatibility + with op.batch_alter_table('site_ips', schema=None) as batch_op: + batch_op.drop_column('site_cidr_id') print(" ✓ Dropped site_cidr_id column from site_ips\n") except Exception as e: print(f" ⚠ Could not drop column: {e}\n") diff --git a/app/migrations/versions/013_repair_site_ips_schema.py b/app/migrations/versions/013_repair_site_ips_schema.py new file mode 100644 index 0000000..6ae856a --- /dev/null +++ b/app/migrations/versions/013_repair_site_ips_schema.py @@ -0,0 +1,59 @@ +"""Repair site_ips schema - remove site_cidr_id if still present + +Revision ID: 013 +Revises: 012 +Create Date: 2025-12-24 + +This migration repairs databases where migration 009 failed to drop the +site_cidr_id column due to SQLite limitations. It uses batch mode which +properly handles SQLite's lack of ALTER TABLE DROP COLUMN support. +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic +revision = '013' +down_revision = '012' +branch_labels = None +depends_on = None + + +def upgrade(): + """ + Remove site_cidr_id column if it still exists (repair for failed 009). + """ + connection = op.get_bind() + inspector = sa.inspect(connection) + + print("\n=== Migration 013: Repair site_ips Schema ===\n") + + # Check if site_cidr_id column still exists + site_ips_columns = [col['name'] for col in inspector.get_columns('site_ips')] + + if 'site_cidr_id' in site_ips_columns: + print("Found orphaned site_cidr_id column - repairing...") + + # Use batch mode for SQLite compatibility + with op.batch_alter_table('site_ips', schema=None) as batch_op: + batch_op.drop_column('site_cidr_id') + + print(" ✓ Dropped site_cidr_id column from site_ips") + print("\n✓ Schema repair complete!") + else: + print("Schema is correct - site_cidr_id column not present.") + print("No repair needed.\n") + + +def downgrade(): + """ + Re-add site_cidr_id column (nullable, since we can't restore data). + """ + print("\n=== Downgrade 013: Re-add site_cidr_id ===\n") + + with op.batch_alter_table('site_ips', schema=None) as batch_op: + batch_op.add_column( + sa.Column('site_cidr_id', sa.Integer(), nullable=True) + ) + + print(" ✓ Re-added site_cidr_id column (nullable)")