"""Creation du moteur SQLAlchemy et de la session de requete.""" from __future__ import annotations import logging from collections.abc import Generator from pathlib import Path from sqlalchemy import Engine, create_engine, event from sqlalchemy.orm import Session, sessionmaker from app.config import get_settings logger = logging.getLogger(__name__) _SQLITE_FILE_PREFIX = "sqlite:///" def _ensure_sqlite_directory(database_url: str) -> None: """Cree le dossier parent du fichier SQLite s'il n'existe pas encore.""" if not database_url.startswith(_SQLITE_FILE_PREFIX): return raw_path = database_url[len(_SQLITE_FILE_PREFIX) :] if not raw_path or raw_path == ":memory:": return path = Path(raw_path) if path.parent and str(path.parent) not in ("", "."): path.parent.mkdir(parents=True, exist_ok=True) def create_db_engine(database_url: str | None = None) -> Engine: settings = get_settings() url = database_url or settings.database_url _ensure_sqlite_directory(url) connect_args = {"check_same_thread": False} if url.startswith("sqlite") else {} engine = create_engine(url, connect_args=connect_args, future=True, echo=False) if url.startswith("sqlite"): @event.listens_for(engine, "connect") def _set_sqlite_pragma(dbapi_connection, _connection_record): # type: ignore[no-untyped-def] cursor = dbapi_connection.cursor() # WAL : meilleure resistance aux arrets brutaux du conteneur. cursor.execute("PRAGMA journal_mode=WAL") cursor.execute("PRAGMA foreign_keys=ON") cursor.close() return engine engine: Engine = create_db_engine() SessionLocal = sessionmaker(bind=engine, autoflush=False, autocommit=False, future=True) def get_db() -> Generator[Session, None, None]: """Dependance FastAPI : ouvre une session et la referme systematiquement.""" session = SessionLocal() try: yield session finally: session.close()