Datavision / backend /app /database /session.py
DataVision CI/CD Bot
release: clean production build for HuggingFace Space
09801ca
Raw
History Blame Contribute Delete
2.1 kB
"""
Database Session Module — Async engine and session factory.
"""
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
from app.core.config import get_settings
def _create_engine():
"""Create the async SQLAlchemy engine from settings."""
settings = get_settings()
url = settings.DATABASE_URL
if url.startswith("postgres://"):
url = url.replace("postgres://", "postgresql+asyncpg://", 1)
elif url.startswith("postgresql://") and not url.startswith("postgresql+asyncpg://"):
url = url.replace("postgresql://", "postgresql+asyncpg://", 1)
return create_async_engine(
url,
pool_size=settings.DB_POOL_SIZE,
max_overflow=settings.DB_MAX_OVERFLOW,
pool_pre_ping=settings.DB_POOL_PRE_PING,
pool_recycle=settings.DB_POOL_RECYCLE,
echo=settings.DB_ECHO,
)
_engine = None
_session_factory = None
def get_engine():
"""Get or create the global engine singleton."""
global _engine
if _engine is None:
_engine = _create_engine()
return _engine
def get_session_factory() -> async_sessionmaker[AsyncSession]:
"""Get or create the global session factory."""
global _session_factory
if _session_factory is None:
_session_factory = async_sessionmaker(
bind=get_engine(),
class_=AsyncSession,
expire_on_commit=False,
)
return _session_factory
async def get_db() -> AsyncSession:
"""
FastAPI dependency — yields an async database session.
Usage:
@router.get("/users")
async def list_users(db: AsyncSession = Depends(get_db)):
...
"""
factory = get_session_factory()
async with factory() as session:
try:
yield session
except Exception:
await session.rollback()
raise
finally:
await session.close()
async def dispose_engine():
"""Dispose the engine on shutdown."""
global _engine
if _engine:
await _engine.dispose()
_engine = None