import os from sqlalchemy import create_engine, event from sqlalchemy.orm import sessionmaker, DeclarativeBase from . import config, mode def _sqlite_unicode_lower(conn, _): # встроенный lower() в SQLite не знает кириллицу — подменяем, чтобы поиск не зависел от регистра conn.create_function("lower", 1, lambda s: s.lower() if isinstance(s, str) else s) def make_engine(url: str): if url.startswith("sqlite"): os.makedirs(config.DATA_DIR, exist_ok=True) e = create_engine(url, connect_args={"check_same_thread": False}) event.listen(e, "connect", _sqlite_unicode_lower) return e return create_engine(url, pool_pre_ping=True) real_engine = make_engine(config.DATABASE_URL) # боевая БД — с ней работают все, кто не в демо engine = real_engine SessionLocal = sessionmaker(bind=real_engine, autoflush=False, expire_on_commit=False) # всегда боевая БД # демо-БД (персональный демо-режим): открывается только для запросов с демо-токеном demo_engine = None DemoSession = sessionmaker(autoflush=False, expire_on_commit=False) def set_demo_engine(e): global demo_engine old, demo_engine = demo_engine, e if e is not None: DemoSession.configure(bind=e) return old def session_for(demo: bool): s = DemoSession() if demo and demo_engine is not None else SessionLocal() s.info["demo"] = bool(demo and demo_engine is not None) return s class Base(DeclarativeBase): pass def get_db(): db = session_for(mode.is_demo_request()) try: yield db finally: db.close()