"""数据库基础:命名约定、异步引擎与会话。 索引/约束命名按 AGENTS.md 8.6(pk_/uk_/idx_/fk_ + 表名); 主库统一 PostgreSQL(ADR-024),不提供 SQLite 档。 """ from collections.abc import AsyncIterator from sqlalchemy import MetaData from sqlalchemy.ext.asyncio import ( AsyncEngine, AsyncSession, async_sessionmaker, create_async_engine, ) from sqlalchemy.orm import DeclarativeBase from app.core.config import get_settings naming_convention = { "ix": "ix_%(column_0_label)s", "uq": "uq_%(table_name)s_%(column_0_name)s", "ck": "ck_%(table_name)s_%(constraint_name)s", "fk": "fk_%(table_name)s_%(referred_table_name)s", "pk": "pk_%(table_name)s", } class Base(DeclarativeBase): metadata = MetaData(naming_convention=naming_convention) def create_engine() -> AsyncEngine: return create_async_engine(get_settings().database_url, pool_pre_ping=True) def create_session_factory(engine: AsyncEngine) -> async_sessionmaker[AsyncSession]: return async_sessionmaker(engine, expire_on_commit=False) async def session_scope( factory: async_sessionmaker[AsyncSession], ) -> AsyncIterator[AsyncSession]: """事务作用域:成功提交、异常回滚(权威状态与 Outbox 同事务,契约第 4.4 节)。""" async with factory() as session: try: yield session await session.commit() except Exception: await session.rollback() raise