from __future__ import annotations from collections.abc import Generator from pathlib import Path from sqlalchemy import create_engine from sqlalchemy.orm import DeclarativeBase, Session, sessionmaker from sqlalchemy.pool import StaticPool from .config import get_settings class Base(DeclarativeBase): pass def _connect_args(database_url: str) -> dict[str, object]: if database_url.startswith("sqlite"): return {"check_same_thread": False} return {} def _engine_kwargs(database_url: str) -> dict[str, object]: if database_url in {"sqlite://", "sqlite:///:memory:"}: return {"poolclass": StaticPool} return {} def _ensure_sqlite_parent(database_url: str) -> None: if not database_url.startswith("sqlite:///"): return db_path = database_url.replace("sqlite:///", "", 1) if db_path not in (":memory:", ""): Path(db_path).parent.mkdir(parents=True, exist_ok=True) settings = get_settings() _ensure_sqlite_parent(settings.database_url) engine = create_engine( settings.database_url, connect_args=_connect_args(settings.database_url), **_engine_kwargs(settings.database_url), ) SessionLocal = sessionmaker(bind=engine, autoflush=False, autocommit=False, expire_on_commit=False) def init_db() -> None: from . import models # noqa: F401 Base.metadata.create_all(bind=engine) def get_session() -> Generator[Session, None, None]: session = SessionLocal() try: yield session finally: session.close()