import logging import threading from importlib.util import find_spec from pathlib import Path from private_gpt.paths import resolve_data_path from private_gpt.settings.settings import Settings if find_spec("sqlalchemy") is None: raise ImportError("SQLAlchemy dependency not found") from sqlalchemy import create_engine from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine from sqlalchemy.orm import Session, sessionmaker logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) class SQLiteClient: def __init__(self, local_path: str, database: str) -> None: self._local_path = resolve_data_path(local_path) / f"{database}.db" Path(self._local_path).parent.mkdir(parents=True, exist_ok=True) self._sync_engine = create_engine(f"sqlite:///{self._local_path}") self._sync_engine = self._sync_engine.execution_options( schema_translate_map={"app": None} ) self._async_engine = create_async_engine( f"sqlite+aiosqlite:///{self._local_path}" ) self._async_engine = self._async_engine.execution_options( schema_translate_map={"app": None} ) self.sync_session = self.new_sync_session() self.async_session = self.new_async_session() def new_sync_session(self) -> sessionmaker[Session]: return sessionmaker(self._sync_engine) def new_async_session(self) -> async_sessionmaker[AsyncSession]: return async_sessionmaker(self._async_engine, class_=AsyncSession) def close(self) -> None: self._sync_engine.dispose() self._async_engine.sync_engine.dispose() logger.debug("SQLite client engines disposed") class LazySQLiteFactory: """Lazy factory for SQLiteClient singleton.""" _instance: SQLiteClient | None = None _lock = threading.Lock() @classmethod def get_instance(cls, settings: Settings) -> SQLiteClient: """Get the singleton instance of SQLiteClient.""" if cls._instance is None: with cls._lock: if cls._instance is None: cls._instance = SQLiteClient( local_path=settings.database.local_path, database=settings.database.database, ) return cls._instance @classmethod def close_instance(cls) -> None: """Close and reset the singleton instance.""" with cls._lock: if cls._instance is not None: cls._instance.close() cls._instance = None logger.debug("SQLiteClient instance closed")