""" TuneVid.com — Database Connection & Session Management """ import os from contextlib import asynccontextmanager from typing import AsyncGenerator from sqlalchemy.ext.asyncio import ( AsyncSession, async_sessionmaker, create_async_engine, ) from sqlalchemy.orm import DeclarativeBase from dotenv import load_dotenv load_dotenv() def _ensure_asyncpg_url(raw_url: str) -> str: """Normalize Postgres SQLAlchemy URL for asyncio engine.""" if raw_url.startswith("postgresql+psycopg2://"): return raw_url.replace("postgresql+psycopg2://", "postgresql+asyncpg://", 1) if raw_url.startswith("postgresql://"): return raw_url.replace("postgresql://", "postgresql+asyncpg://", 1) if raw_url.startswith("postgres://"): return raw_url.replace("postgres://", "postgresql+asyncpg://", 1) return raw_url DATABASE_URL = _ensure_asyncpg_url( os.getenv( "DATABASE_URL", "postgresql+asyncpg://postgres:postgres@localhost:5432/tunevid", ) ) engine = create_async_engine( DATABASE_URL, echo=False, pool_size=20, max_overflow=10, pool_pre_ping=True, ) async_session_factory = async_sessionmaker( engine, class_=AsyncSession, expire_on_commit=False, ) class Base(DeclarativeBase): pass async def get_db() -> AsyncGenerator[AsyncSession, None]: """FastAPI dependency that yields an async DB session.""" async with async_session_factory() as session: try: yield session await session.commit() except Exception: await session.rollback() raise finally: await session.close() async def init_db(): """Create all tables (dev only — use Alembic in production).""" async with engine.begin() as conn: await conn.run_sync(Base.metadata.create_all) async def close_db(): """Dispose engine on shutdown.""" await engine.dispose()