from datetime import date, datetime from decimal import Decimal from typing import Any from sqlalchemy.engine import RowMapping from app.modules.legacy_mysql.constants import LEGACY_SQL_TRAILING_TERMINATOR, LegacyQueryName FORBIDDEN_SQL_TOKENS = { "benchmark", "call", "insert", "update", "delete", "drop", "alter", "truncate", "create", "do", "dumpfile", "execute", "replace", "grant", "get_lock", "handler", "into", "load_file", "lock", "outfile", "release_lock", "revoke", "set", "sleep", } def _jsonable(value: Any) -> Any: """Convert database scalar values into JSON-friendly values.""" if isinstance(value, (datetime, date)): return value.isoformat() if isinstance(value, Decimal): return float(value) return value def _row_to_dict(row: RowMapping) -> dict[str, Any]: """Convert a SQLAlchemy row mapping to a serializable dictionary.""" return {key: _jsonable(value) for key, value in row.items()} def _normalize_sql(sql: str) -> str: return " ".join(sql.strip().rstrip(LEGACY_SQL_TRAILING_TERMINATOR).split()).lower() def _query_name_text(query_name: str | LegacyQueryName | None) -> str: if query_name is None: return LegacyQueryName.PROJECTS.value if isinstance(query_name, LegacyQueryName): return query_name.value return str(query_name)