SERG4NT's picture
Upload folder using huggingface_hub
c1dcc23 verified
Raw History Blame Contribute Delete
2.21 kB
"""Database engine, session factory, and the FastAPI `get_db` dependency.
Sync SQLAlchemy 2.0. Postgres in production (docker-compose), SQLite for tests.
The dependency converts connectivity failures into a clean 503 so the API
degrades gracefully instead of leaking stack traces (Part C requirement).
"""
from __future__ import annotations
from collections.abc import Iterator
from sqlalchemy import create_engine
from sqlalchemy.exc import OperationalError, SQLAlchemyError
from sqlalchemy.orm import DeclarativeBase, Session, sessionmaker
from app.core.config import get_settings
class Base(DeclarativeBase):
pass
class DatabaseUnavailable(Exception):
"""Raised when the database cannot be reached; mapped to HTTP 503."""
_settings = get_settings()
_connect_args = {}
_engine_kwargs: dict = {"pool_pre_ping": True, "future": True}
if _settings.database_url.startswith("sqlite"):
# in-memory sqlite for tests needs a shared connection across threads
_connect_args = {"check_same_thread": False}
from sqlalchemy.pool import StaticPool
_engine_kwargs = {"connect_args": _connect_args, "poolclass": StaticPool, "future": True}
engine = create_engine(_settings.database_url, **_engine_kwargs)
SessionLocal = sessionmaker(bind=engine, autoflush=False, expire_on_commit=False, class_=Session)
def init_db() -> None:
"""Create tables. Import models first so they register on Base.metadata."""
from app import models # noqa: F401
Base.metadata.create_all(bind=engine)
def get_db() -> Iterator[Session]:
"""Yield a session; commit on success, rollback on error, always close.
Connectivity errors become DatabaseUnavailable -> 503 (see main.py handler).
"""
try:
db = SessionLocal()
except OperationalError as exc: # pragma: no cover - hard to hit in tests
raise DatabaseUnavailable(str(exc)) from exc
try:
yield db
db.commit()
except DatabaseUnavailable:
db.rollback()
raise
except OperationalError as exc:
db.rollback()
raise DatabaseUnavailable(str(exc)) from exc
except SQLAlchemyError:
db.rollback()
raise
finally:
db.close()