"""add ai processing audit fields Revision ID: add_ai_processing_audit_fields Revises: add_inbox_structured_fields Create Date: 2026-03-08 """ from __future__ import annotations from alembic import op import sqlalchemy as sa revision = "add_ai_processing_audit_fields" down_revision = "add_inbox_structured_fields" branch_labels = None depends_on = None def _table_exists(bind, table_name: str) -> bool: return sa.inspect(bind).has_table(table_name) def _column_exists(bind, table_name: str, column_name: str) -> bool: inspector = sa.inspect(bind) if not inspector.has_table(table_name): return False columns = inspector.get_columns(table_name) return any(col.get("name") == column_name for col in columns) def _index_exists(bind, table_name: str, index_name: str) -> bool: inspector = sa.inspect(bind) if not inspector.has_table(table_name): return False return any(idx.get("name") == index_name for idx in inspector.get_indexes(table_name)) def _add_column_if_missing(bind, table_name: str, column: sa.Column) -> None: if not _column_exists(bind, table_name, str(column.name)): op.add_column(table_name, column) def _create_index_if_missing(bind, table_name: str, index_name: str, columns: list[str]) -> None: if not _index_exists(bind, table_name, index_name): op.create_index(index_name, table_name, columns) def upgrade() -> None: bind = op.get_bind() if not _table_exists(bind, "ai_processing_logs"): return _add_column_if_missing(bind, "ai_processing_logs", sa.Column("normalized_text", sa.Text(), nullable=True)) _add_column_if_missing(bind, "ai_processing_logs", sa.Column("route", sa.String(length=80), nullable=True)) _add_column_if_missing(bind, "ai_processing_logs", sa.Column("intent", sa.String(length=40), nullable=True)) _add_column_if_missing(bind, "ai_processing_logs", sa.Column("executor", sa.String(length=40), nullable=True)) _add_column_if_missing(bind, "ai_processing_logs", sa.Column("operation_code", sa.String(length=80), nullable=True)) _add_column_if_missing(bind, "ai_processing_logs", sa.Column("operation_result", sa.JSON(), nullable=True)) _add_column_if_missing(bind, "ai_processing_logs", sa.Column("reply_source", sa.String(length=40), nullable=True)) _create_index_if_missing(bind, "ai_processing_logs", "ix_ai_processing_logs_route", ["route"]) _create_index_if_missing(bind, "ai_processing_logs", "ix_ai_processing_logs_intent", ["intent"]) _create_index_if_missing(bind, "ai_processing_logs", "ix_ai_processing_logs_operation_code", ["operation_code"]) def downgrade() -> None: bind = op.get_bind() if not _table_exists(bind, "ai_processing_logs"): return for index_name in ( "ix_ai_processing_logs_operation_code", "ix_ai_processing_logs_intent", "ix_ai_processing_logs_route", ): if _index_exists(bind, "ai_processing_logs", index_name): op.drop_index(index_name, table_name="ai_processing_logs") for column_name in ( "reply_source", "operation_result", "operation_code", "executor", "intent", "route", "normalized_text", ): if _column_exists(bind, "ai_processing_logs", column_name): op.drop_column("ai_processing_logs", column_name)