Sheetly / app /db.py
nvikou's picture
initial commit
da6ee5e verified
Raw History Blame Contribute Delete
1.91 kB
"""Database session and init helpers."""
from __future__ import annotations
from collections.abc import AsyncGenerator
from sqlalchemy.ext.asyncio import (
AsyncEngine,
AsyncSession,
async_sessionmaker,
create_async_engine,
)
from app.config import get_settings
from app.models import Base
engine: AsyncEngine | None = None
SessionLocal: async_sessionmaker[AsyncSession] | None = None
def configure_engine(url: str | None = None) -> None:
"""
Create the async engine.
Call dispose_engine() first when replacing an existing engine.
"""
global engine, SessionLocal
if engine is not None:
raise RuntimeError(
"Engine already configured; await dispose_engine() first"
)
settings = get_settings()
db_url = url or settings.database_url
engine = create_async_engine(db_url, echo=False)
SessionLocal = async_sessionmaker(
engine,
class_=AsyncSession,
expire_on_commit=False,
)
def get_session_factory() -> async_sessionmaker[AsyncSession]:
"""Return the active session factory."""
if SessionLocal is None:
configure_engine()
assert SessionLocal is not None
return SessionLocal
configure_engine()
async def dispose_engine() -> None:
"""Dispose current engine (release file locks)."""
global engine, SessionLocal
if engine is not None:
await engine.dispose()
engine = None
SessionLocal = None
async def init_db() -> None:
"""Create tables if they do not exist."""
if engine is None:
configure_engine()
assert engine is not None
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
async def get_session() -> AsyncGenerator[AsyncSession, None]:
"""Yield an async DB session."""
factory = get_session_factory()
async with factory() as session:
yield session