"""add_composite_indexes Additional composite indexes for scoring, heatmap, metrics, reports, MTTD/MTTR calculations, and notification queries. Revision ID: b019composite Revises: b018perfidx Create Date: 2026-02-17 14:00:00.000000 """ from typing import Sequence, Union from alembic import op # revision identifiers, used by Alembic. revision: str = "b019composite" down_revision: Union[str, None] = "b018perfidx" branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: # ── Tests ──────────────────────────────────────────────────────── # Used by scoring queries that filter by state + validation date op.create_index( "ix_tests_state_red_validated_at", "tests", ["state", "red_validated_at"], ) # Used by remediation dashboard and metrics op.create_index( "ix_tests_remediation_status", "tests", ["remediation_status"], ) # ── Audit logs ─────────────────────────────────────────────────── # Three-column index for MTTD/MTTR queries that filter by entity + action op.create_index( "ix_audit_logs_entity_type_entity_id_action", "audit_logs", ["entity_type", "entity_id", "action"], ) # Used for per-user audit trail queries op.create_index( "ix_audit_logs_user_id", "audit_logs", ["user_id"], ) # ── Notifications ──────────────────────────────────────────────── # Used by "unread notifications" badge and inbox queries op.create_index( "ix_notifications_user_id_read", "notifications", ["user_id", "read"], ) def downgrade() -> None: op.drop_index("ix_notifications_user_id_read", table_name="notifications") op.drop_index("ix_audit_logs_user_id", table_name="audit_logs") op.drop_index("ix_audit_logs_entity_type_entity_id_action", table_name="audit_logs") op.drop_index("ix_tests_remediation_status", table_name="tests") op.drop_index("ix_tests_state_red_validated_at", table_name="tests")