63 lines
1.7 KiB
Python
63 lines
1.7 KiB
Python
"""Database configuration and session management."""
|
|
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine, async_sessionmaker
|
|
from sqlalchemy.orm import DeclarativeBase
|
|
|
|
from app.config import get_settings
|
|
|
|
settings = get_settings()
|
|
|
|
# Create async engine
|
|
engine_kwargs = {
|
|
"echo": settings.debug,
|
|
"future": True,
|
|
}
|
|
# Production hardening: enable connection pooling for Postgres
|
|
if settings.database_url.startswith("postgresql"):
|
|
engine_kwargs.update(
|
|
{
|
|
"pool_size": settings.db_pool_size,
|
|
"max_overflow": settings.db_max_overflow,
|
|
"pool_timeout": settings.db_pool_timeout,
|
|
"pool_pre_ping": True,
|
|
}
|
|
)
|
|
|
|
engine = create_async_engine(settings.database_url, **engine_kwargs)
|
|
|
|
# Create async session factory
|
|
AsyncSessionLocal = async_sessionmaker(
|
|
engine,
|
|
class_=AsyncSession,
|
|
expire_on_commit=False,
|
|
autocommit=False,
|
|
autoflush=False,
|
|
)
|
|
|
|
|
|
class Base(DeclarativeBase):
|
|
"""Base class for all database models."""
|
|
pass
|
|
|
|
|
|
async def get_db() -> AsyncSession:
|
|
"""Dependency to get database session."""
|
|
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():
|
|
"""Initialize database tables."""
|
|
async with engine.begin() as conn:
|
|
await conn.run_sync(Base.metadata.create_all)
|
|
# Apply additive migrations (indexes / optional columns) for existing DBs
|
|
from app.db_migrations import apply_migrations
|
|
await apply_migrations(conn)
|
|
|