arm-core/api/src/db/db.py
Andrey Epifancev 9e53fc64be Схема БД конфигурируемая: настройка DB_SCHEMA вместо зашитой dkb (#38)
DB_SCHEMA (по умолчанию dkb, валидация идентификатора) читают models/base.py (SCHEMA), db/db.py (search_path),
alembic/env.py и миграции 0001-0005 (SCHEMA и строковые FK f"{SCHEMA}.x.id" вместо литералов). В контуре -
OPENBAO__APP__DB_SCHEMA. Офлайн-SQL `alembic upgrade head --sql` при значении по умолчанию совпадает побайтно.
Тесты: валидация настройки, миграции и сессия приложения в схеме dkb_alt; .env.example/.env.test/README/CLAUDE.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EAKRDNzXtRrwmWz9z6PZu3
2026-10-07 19:26:37 +04:00

36 lines
1.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from collections.abc import AsyncIterator
from contextlib import asynccontextmanager
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
# from fastapi_users.db import SQLAlchemyUserDatabase, SQLAlchemyBaseUserTableUUID
from src.core.config import settings
from src.models.base import SCHEMA
engine = create_async_engine(
settings.OPENBAO.DATABASE.DATABASE_URL, connect_args={"server_settings": {"search_path": SCHEMA}}
)
async_session_maker = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
async def get_async_session() -> AsyncIterator[AsyncSession]:
"""Сессия запроса = одна транзакция: commit при успешном ответе, rollback при любом исключении (R-1, design #12).
В маршрутах объявляется только через `src.api.dependencies.db.SessionDep` (`scope="function"`): тогда commit
выполняется до отправки ответа, а все зависимости запроса получают одну и ту же сессию.
"""
async with async_session_maker() as session, session.begin():
yield session
@asynccontextmanager
async def session_transaction(
maker: async_sessionmaker[AsyncSession] | None = None,
) -> AsyncIterator[AsyncSession]:
"""Отдельная короткая транзакция вне сессии запроса (аудит входа): commit на выходе, rollback при исключении.
`maker` по умолчанию — `async_session_maker` приложения (читается при вызове: тесты его подменяют).
"""
async with (maker or async_session_maker)() as session, session.begin():
yield session