GOXY / app /db /base.py
lasagnakanada
Deploy GOXY ML Service to HuggingFace Space
3d6cc8a
"""
SQLAlchemy base classes and database configuration.
This module provides the declarative base and database engine setup.
"""
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
from sqlalchemy.orm import DeclarativeBase, sessionmaker
from app.config import get_settings
settings = get_settings()
# Lazily initialized engine and session factory to avoid heavy imports at module import time
engine = None # will be created on first use
AsyncSessionLocal = None # will be created on first use
def _ensure_engine_and_session():
"""Initialize engine and session factory if not already created.
This avoids importing async drivers (e.g., asyncpg) during module import,
which breaks tests that patch out DB dependencies.
"""
global engine, AsyncSessionLocal
if engine is None:
try:
engine = create_async_engine(
settings.database_url,
echo=settings.debug,
pool_size=settings.db_pool_size,
max_overflow=settings.db_max_overflow,
pool_pre_ping=True,
pool_recycle=3600,
)
AsyncSessionLocal = sessionmaker(
engine,
class_=AsyncSession,
expire_on_commit=False,
autocommit=False,
autoflush=False,
)
except ModuleNotFoundError as e:
# Provide a clearer error if async DB driver isn't installed
# during actual DB use. Importing this module alone should not fail.
if "asyncpg" in str(e):
raise RuntimeError(
"Database driver 'asyncpg' is not installed. This is expected in unit tests that patch get_db. "
"If you are running the app for real, install asyncpg or configure a supported driver."
) from e
raise
class Base(DeclarativeBase):
"""Base class for all SQLAlchemy models."""
pass
async def get_db() -> AsyncSession:
"""
Dependency that provides a database session.
Yields:
AsyncSession: Database session
Usage:
async def my_route(db: AsyncSession = Depends(get_db)):
# Use db session
pass
"""
# Ensure engine/session are initialized only when DB is actually used
_ensure_engine_and_session()
assert AsyncSessionLocal is not None
async with AsyncSessionLocal() as session:
try:
yield session
await session.commit()
except Exception:
await session.rollback()
raise
finally:
await session.close()