60 lines
2.2 KiB
Python
60 lines
2.2 KiB
Python
"""Подключение к Postgres. Асинхронный движок, одна фабрика сессий на процесс."""
|
||
|
||
from collections.abc import AsyncIterator
|
||
|
||
from fastapi import HTTPException
|
||
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
|
||
from sqlalchemy.orm import DeclarativeBase
|
||
|
||
from app.config import get_settings
|
||
|
||
|
||
class Base(DeclarativeBase):
|
||
"""Общая база моделей. Alembic сравнивает миграции с `Base.metadata`."""
|
||
|
||
|
||
_engine = None
|
||
_sessionmaker: async_sessionmaker[AsyncSession] | None = None
|
||
|
||
|
||
def get_engine():
|
||
global _engine
|
||
if _engine is None:
|
||
settings = get_settings()
|
||
_engine = create_async_engine(
|
||
settings.database_url,
|
||
pool_pre_ping=True,
|
||
pool_size=settings.db_pool_size,
|
||
max_overflow=settings.db_pool_max_overflow,
|
||
# SQLAlchemy exceptions/logs must not echo bound user/report values.
|
||
hide_parameters=True,
|
||
)
|
||
return _engine
|
||
|
||
|
||
def get_sessionmaker() -> async_sessionmaker[AsyncSession]:
|
||
global _sessionmaker
|
||
if _sessionmaker is None:
|
||
_sessionmaker = async_sessionmaker(get_engine(), expire_on_commit=False)
|
||
return _sessionmaker
|
||
|
||
|
||
def reset() -> None:
|
||
"""Забыть движок и фабрику.
|
||
|
||
Нужно тестам: каждый `TestClient` поднимает свой событийный цикл, а пул
|
||
соединений привязан к тому, в котором создан. Переиспользование даёт
|
||
«Future attached to a different loop» — причём не сразу, а на втором
|
||
обращении к базе, и выглядит это как случайно падающий тест.
|
||
"""
|
||
global _engine, _sessionmaker
|
||
_engine = None
|
||
_sessionmaker = None
|
||
|
||
|
||
async def get_session() -> AsyncIterator[AsyncSession]:
|
||
"""Зависимость FastAPI: сессия на запрос, коммит явный."""
|
||
if get_settings().demo_no_db:
|
||
raise HTTPException(status_code=503, detail="database_disabled_demo")
|
||
async with get_sessionmaker()() as session:
|
||
yield session
|