"""Datenbank-Anbindung (SQLite). SQLite braucht ein paar PRAGMAs, damit es sich unter FastAPIs Thread-Pool vernünftig verhält: WAL für gleichzeitige Leser, ``foreign_keys=ON`` (sonst greifen die ON-DELETE-Regeln nicht), und ein Busy-Timeout, damit kurze Schreibsperren nicht sofort krachen. """ import os from collections.abc import Generator from sqlalchemy import create_engine, event from sqlalchemy.orm import DeclarativeBase, Session, sessionmaker from .config import get_settings settings = get_settings() _url = settings.effective_database_url # Für die SQLite-Datei das Datenverzeichnis sicherstellen. if _url.startswith("sqlite:///"): _path = _url.replace("sqlite:///", "", 1) _dir = os.path.dirname(_path) if _dir: os.makedirs(_dir, exist_ok=True) connect_args = {"check_same_thread": False} if _url.startswith("sqlite") else {} engine = create_engine( _url, connect_args=connect_args, pool_pre_ping=True, future=True, ) @event.listens_for(engine, "connect") def _sqlite_pragmas(dbapi_connection, _record): """Bei jeder neuen SQLite-Verbindung sinnvolle Voreinstellungen setzen.""" if not _url.startswith("sqlite"): return cur = dbapi_connection.cursor() cur.execute("PRAGMA journal_mode=WAL") cur.execute("PRAGMA foreign_keys=ON") cur.execute("PRAGMA busy_timeout=5000") cur.close() SessionLocal = sessionmaker(bind=engine, autoflush=False, autocommit=False, future=True) class Base(DeclarativeBase): pass def get_db() -> Generator[Session, None, None]: db = SessionLocal() try: yield db finally: db.close()