SPB Git forge

spb/api-ka

Public

API-KA — plateforme centrale : collecte quotidienne des 8 services KA, historisation append-only et API publique sur www.api-ka.com

48commits 1branches 0releases
5.9 MBsize
maindefault branch
20 days agolast push
Python 60.9% HTML 21% TypeScript 7.3% JavaScript 5.2% CSS 4.8% Shell 0.8%
3.2 KB · 113 lines python
Raw Blame History
1# ============================================2# Projet   : API-KA3# Fichier  : src/database/db.py4# Node     : m3u96b5# Author   : Simon-Pierre Boucher6# Contact  : contact@spboucher.ai7# Date     : 2026-08-168# ============================================9"""Engine SQLAlchemy, sessions, initialisation du schéma et healthcheck DB."""1011from __future__ import annotations1213import argparse14from collections.abc import Iterator15from contextlib import contextmanager1617from sqlalchemy import Engine, create_engine, text18from sqlalchemy.orm import Session, sessionmaker1920from src.config import get_settings, verify_node21from src.database.models import Base2223_engine: Engine | None = None24_session_factory: sessionmaker[Session] | None = None252627def get_engine() -> Engine:28    """Retourne l'engine SQLAlchemy (créé paresseusement, pool_pre_ping actif)."""29    global _engine30    if _engine is None:31        settings = get_settings()32        kwargs: dict = {"pool_pre_ping": True}33        if settings.database_url.startswith("sqlite"):34            kwargs["connect_args"] = {"check_same_thread": False}35        _engine = create_engine(settings.database_url, **kwargs)36    return _engine373839def get_session_factory() -> sessionmaker[Session]:40    """Retourne la fabrique de sessions liée à l'engine courant."""41    global _session_factory42    if _session_factory is None:43        _session_factory = sessionmaker(bind=get_engine(), expire_on_commit=False)44    return _session_factory454647def reset_engine() -> None:48    """Réinitialise l'engine (utilisé par les tests après changement de config)."""49    global _engine, _session_factory50    if _engine is not None:51        _engine.dispose()52    _engine = None53    _session_factory = None545556@contextmanager57def session_scope() -> Iterator[Session]:58    """Session transactionnelle : commit en sortie, rollback sur exception."""59    session = get_session_factory()()60    try:61        yield session62        session.commit()63    except Exception:64        session.rollback()65        raise66    finally:67        session.close()686970def get_db() -> Iterator[Session]:71    """Dépendance FastAPI fournissant une session par requête."""72    session = get_session_factory()()73    try:74        yield session75    finally:76        session.close()777879def init_db() -> None:80    """Crée toutes les tables si elles n'existent pas (idempotent)."""81    Base.metadata.create_all(get_engine())828384def healthcheck() -> bool:85    """Vérifie que la base répond (SELECT 1)."""86    try:87        with get_engine().connect() as conn:88            conn.execute(text("SELECT 1"))89        return True90    except Exception:91        return False929394def main() -> None:95    """Point d'entrée CLI : ``python -m src.database.db --init``."""96    from src.utils.logger import get_logger9798    parser = argparse.ArgumentParser(description="Gestion de la base API-KA (m3u96b)")99    parser.add_argument("--init", action="store_true", help="Créer les tables")100    args = parser.parse_args()101102    verify_node()103    logger = get_logger("apika.db")104    if args.init:105        init_db()106        logger.info("Base initialisée", extra={"database_ok": healthcheck()})107    else:108        logger.info("Healthcheck base", extra={"database_ok": healthcheck()})109110111if __name__ == "__main__":112    main()113