"""SQLAlchemy engine for the warehouse. Per-connection defaults (search_path, statement_timeout) are baked into the engine via libpq's `options` connect_arg so we never SET them at the SQL layer. Read-only mode for query execution is requested via SQLAlchemy's `execution_options(postgresql_readonly=True)`. """ from __future__ import annotations from functools import lru_cache from sqlalchemy import create_engine from sqlalchemy.engine import Engine from api.config import get_settings SCHEMA = "financial" DEFAULT_STATEMENT_TIMEOUT_MS = 10_000 @lru_cache(maxsize=1) def get_engine() -> Engine: url = get_settings().database_url if url.startswith("postgresql://"): url = url.replace("postgresql://", "postgresql+psycopg://", 1) return create_engine( url, pool_pre_ping=True, future=True, # libpq -c options run before any SQL the app issues — no need to # SET search_path / statement_timeout at execution time. connect_args={ "options": ( f"-c search_path={SCHEMA},public " f"-c statement_timeout={DEFAULT_STATEMENT_TIMEOUT_MS}" ), }, )