From e3e30f01e912321871f47d8418f1f02efff5c575 Mon Sep 17 00:00:00 2001 From: Nguyen HP Laptop Date: Sat, 25 Apr 2026 12:47:28 -0400 Subject: [PATCH] 04/25 fix phase12 --- .../versions/phase12_performance_indexes.py | 85 +++++++++---------- 1 file changed, 40 insertions(+), 45 deletions(-) diff --git a/migrations/versions/phase12_performance_indexes.py b/migrations/versions/phase12_performance_indexes.py index 4c9b362..0af70df 100644 --- a/migrations/versions/phase12_performance_indexes.py +++ b/migrations/versions/phase12_performance_indexes.py @@ -21,10 +21,24 @@ DB index, causing full table scans as row counts grow: - assigned_to — filtered for inspector-scoped views - reported_at — used for ordering -All indexes are created with IF NOT EXISTS so the migration is safe to re-run. +Existence checks use information_schema so the migration is safe to re-run +on any MySQL version (compatible back to 5.7). """ from alembic import op +from sqlalchemy import text + + +def _index_exists(conn, table: str, index_name: str) -> bool: + """Return True if the named index already exists on the given table.""" + result = conn.execute(text( + "SELECT COUNT(*) FROM information_schema.statistics " + "WHERE table_schema = DATABASE() " + " AND table_name = :table " + " AND index_name = :index" + ), {'table': table, 'index': index_name}) + return result.scalar() > 0 + revision = 'phase12_performance_indexes' down_revision = 'phase11_director_role' @@ -32,51 +46,32 @@ branch_labels = None depends_on = None -def upgrade(): - # ── inspections ────────────────────────────────────────────────────────── - op.execute( - "CREATE INDEX IF NOT EXISTS ix_inspections_status " - "ON inspections (status)" - ) - op.execute( - "CREATE INDEX IF NOT EXISTS ix_inspections_facility_id " - "ON inspections (facility_id)" - ) - op.execute( - "CREATE INDEX IF NOT EXISTS ix_inspections_inspector_id " - "ON inspections (inspector_id)" - ) - op.execute( - "CREATE INDEX IF NOT EXISTS ix_inspections_inspection_date " - "ON inspections (inspection_date)" - ) +# (table, index_name, column) +INDEXES = [ + ('inspections', 'ix_inspections_status', 'status'), + ('inspections', 'ix_inspections_facility_id', 'facility_id'), + ('inspections', 'ix_inspections_inspector_id', 'inspector_id'), + ('inspections', 'ix_inspections_inspection_date', 'inspection_date'), + ('issues', 'ix_issues_status', 'status'), + ('issues', 'ix_issues_severity', 'severity'), + ('issues', 'ix_issues_assigned_to', 'assigned_to'), + ('issues', 'ix_issues_reported_at', 'reported_at'), +] - # ── issues ─────────────────────────────────────────────────────────────── - op.execute( - "CREATE INDEX IF NOT EXISTS ix_issues_status " - "ON issues (status)" - ) - op.execute( - "CREATE INDEX IF NOT EXISTS ix_issues_severity " - "ON issues (severity)" - ) - op.execute( - "CREATE INDEX IF NOT EXISTS ix_issues_assigned_to " - "ON issues (assigned_to)" - ) - op.execute( - "CREATE INDEX IF NOT EXISTS ix_issues_reported_at " - "ON issues (reported_at)" - ) + +def upgrade(): + conn = op.get_bind() + for table, index_name, column in INDEXES: + if not _index_exists(conn, table, index_name): + op.execute(text( + f'CREATE INDEX {index_name} ON {table} ({column})' + )) def downgrade(): - op.execute("DROP INDEX IF EXISTS ix_inspections_status ON inspections") - op.execute("DROP INDEX IF EXISTS ix_inspections_facility_id ON inspections") - op.execute("DROP INDEX IF EXISTS ix_inspections_inspector_id ON inspections") - op.execute("DROP INDEX IF EXISTS ix_inspections_inspection_date ON inspections") - - op.execute("DROP INDEX IF EXISTS ix_issues_status ON issues") - op.execute("DROP INDEX IF EXISTS ix_issues_severity ON issues") - op.execute("DROP INDEX IF EXISTS ix_issues_assigned_to ON issues") - op.execute("DROP INDEX IF EXISTS ix_issues_reported_at ON issues") + conn = op.get_bind() + for table, index_name, _column in INDEXES: + if _index_exists(conn, table, index_name): + op.execute(text( + f'DROP INDEX {index_name} ON {table}' + )) \ No newline at end of file