from collections.abc import AsyncIterator from typing import Annotated from fastapi import Depends from sqlalchemy.engine import make_url from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine from app.config import settings def normalize_async_url(url: str) -> str: """Translate libpq's `sslmode=` into the `ssl=` asyncpg understands. Hosted Postgres (Neon, Supabase) hands out sslmode= URLs, which asyncpg rejects outright. """ parsed = make_url(url) if "asyncpg" not in parsed.drivername or "sslmode" not in parsed.query: return url query = dict(parsed.query) query["ssl"] = query.pop("sslmode") return parsed.set(query=query).render_as_string(hide_password=False) engine = create_async_engine(normalize_async_url(settings.database_url), pool_pre_ping=True) SessionLocal = async_sessionmaker(engine, expire_on_commit=False) async def get_session() -> AsyncIterator[AsyncSession]: async with SessionLocal() as session: yield session SessionDep = Annotated[AsyncSession, Depends(get_session)]