""" Database configuration and session management for async PostgreSQL. Uses SQLAlchemy 2.0 async ORM with asyncpg driver. """ from typing import AsyncGenerator from sqlalchemy.ext.asyncio import ( AsyncSession, async_sessionmaker, create_async_engine, ) from sqlalchemy.orm import DeclarativeBase from app.core.config import get_settings settings = get_settings() # Create async engine with connection pooling engine = create_async_engine( settings.DATABASE_URL, echo=settings.ENVIRONMENT == "development", # Log SQL in development pool_pre_ping=True, # Verify connections before using pool_size=10, # Number of connections to maintain max_overflow=20, # Max additional connections beyond pool_size pool_recycle=3600, # Recycle connections after 1 hour ) # Create async session factory AsyncSessionLocal = async_sessionmaker( engine, class_=AsyncSession, expire_on_commit=False, # Prevent attributes from being expired after commit autocommit=False, autoflush=False, ) class Base(DeclarativeBase): """Base class for all database models.""" pass async def get_db() -> AsyncGenerator[AsyncSession, None]: """ Dependency for getting async database session. Yields: AsyncSession: Database session Example: ```python @app.get("/items/") async def get_items(db: AsyncSession = Depends(get_db)): result = await db.execute(select(Item)) return result.scalars().all() ``` """ async with AsyncSessionLocal() as session: try: yield session await session.commit() except Exception: await session.rollback() raise finally: await session.close() async def init_db() -> None: """ Initialize database - create all tables. Note: In production, use Alembic migrations instead. This is useful for development and testing. """ async with engine.begin() as conn: await conn.run_sync(Base.metadata.create_all) async def close_db() -> None: """Close database connections.""" await engine.dispose()