session.py 1.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041
  1. """Async SQLAlchemy engine and session factory.
  2. The engine is created lazily so that importing the FastAPI app (e.g. to export
  3. the OpenAPI schema) never requires a live database connection.
  4. """
  5. from __future__ import annotations
  6. from functools import lru_cache
  7. from sqlalchemy.ext.asyncio import (
  8. AsyncEngine,
  9. AsyncSession,
  10. async_sessionmaker,
  11. create_async_engine,
  12. )
  13. from app.config import get_settings
  14. @lru_cache
  15. def get_engine() -> AsyncEngine:
  16. """Return a lazily-created, cached async engine.
  17. The real funnel tables live in the ``ads`` schema; the ORM models are
  18. schema-less, so we point every connection's ``search_path`` at the
  19. configured schema (asyncpg ``server_settings``). Skipped when blank.
  20. """
  21. settings = get_settings()
  22. connect_args: dict = {}
  23. if settings.db_schema:
  24. connect_args["server_settings"] = {"search_path": settings.db_schema}
  25. return create_async_engine(
  26. settings.database_url, pool_pre_ping=True, connect_args=connect_args
  27. )
  28. @lru_cache
  29. def get_sessionmaker() -> async_sessionmaker[AsyncSession]:
  30. """Return a cached async session factory bound to the engine."""
  31. return async_sessionmaker(get_engine(), expire_on_commit=False)