2026-05-06 17:43:47 +08:00
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
from sqlalchemy import create_engine
|
|
|
|
|
from sqlalchemy.engine import Engine
|
|
|
|
|
from sqlalchemy.orm import Session, sessionmaker
|
|
|
|
|
|
|
|
|
|
from app.core.config import get_settings
|
|
|
|
|
|
|
|
|
|
_engine: Engine | None = None
|
|
|
|
|
_session_factory: sessionmaker[Session] | None = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def configure_session_factory() -> None:
|
|
|
|
|
global _engine, _session_factory
|
|
|
|
|
|
|
|
|
|
settings = get_settings()
|
|
|
|
|
|
|
|
|
|
if _engine is not None:
|
|
|
|
|
_engine.dispose()
|
|
|
|
|
|
2026-06-06 17:19:07 +08:00
|
|
|
engine_kwargs = {
|
|
|
|
|
"echo": settings.sqlalchemy_echo,
|
|
|
|
|
"pool_pre_ping": True,
|
|
|
|
|
}
|
|
|
|
|
if not settings.resolved_database_url.startswith("sqlite"):
|
|
|
|
|
engine_kwargs.update(
|
|
|
|
|
{
|
|
|
|
|
"pool_size": max(1, int(settings.sqlalchemy_pool_size or 10)),
|
|
|
|
|
"max_overflow": max(0, int(settings.sqlalchemy_max_overflow or 20)),
|
|
|
|
|
"pool_timeout": max(1, int(settings.sqlalchemy_pool_timeout or 30)),
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
_engine = create_engine(settings.resolved_database_url, **engine_kwargs)
|
2026-05-06 17:43:47 +08:00
|
|
|
_session_factory = sessionmaker(bind=_engine, autoflush=False, autocommit=False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_engine() -> Engine:
|
|
|
|
|
global _engine
|
|
|
|
|
|
|
|
|
|
if _engine is None:
|
|
|
|
|
configure_session_factory()
|
|
|
|
|
|
|
|
|
|
return _engine
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_session_factory() -> sessionmaker[Session]:
|
|
|
|
|
global _session_factory
|
|
|
|
|
|
|
|
|
|
if _session_factory is None:
|
|
|
|
|
configure_session_factory()
|
|
|
|
|
|
|
|
|
|
return _session_factory
|