# [DEF:backend.src.core.database:Module] # # @SEMANTICS: database, postgresql, sqlalchemy, session, persistence # @PURPOSE: Configures database connection and session management (PostgreSQL-first). # @LAYER: Core # @RELATION: DEPENDS_ON -> sqlalchemy # @RELATION: USES -> backend.src.models.mapping # @RELATION: USES -> backend.src.core.auth.config # # @INVARIANT: A single engine instance is used for the entire application. # [SECTION: IMPORTS] from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from ..models.mapping import Base # Import models to ensure they're registered with Base from ..models import task as _task_models # noqa: F401 from ..models import auth as _auth_models # noqa: F401 from ..models import config as _config_models # noqa: F401 from ..models import llm as _llm_models # noqa: F401 from .logger import belief_scope from .auth.config import auth_config import os from pathlib import Path # [/SECTION] # [DEF:BASE_DIR:Variable] # @PURPOSE: Base directory for the backend. BASE_DIR = Path(__file__).resolve().parent.parent.parent # [/DEF:BASE_DIR:Variable] # [DEF:DATABASE_URL:Constant] # @PURPOSE: URL for the main application database. DEFAULT_POSTGRES_URL = os.getenv( "POSTGRES_URL", "postgresql+psycopg2://postgres:postgres@localhost:5432/ss_tools", ) DATABASE_URL = os.getenv("DATABASE_URL", DEFAULT_POSTGRES_URL) # [/DEF:DATABASE_URL:Constant] # [DEF:TASKS_DATABASE_URL:Constant] # @PURPOSE: URL for the tasks execution database. # Defaults to DATABASE_URL to keep task logs in the same PostgreSQL instance. TASKS_DATABASE_URL = os.getenv("TASKS_DATABASE_URL", DATABASE_URL) # [/DEF:TASKS_DATABASE_URL:Constant] # [DEF:AUTH_DATABASE_URL:Constant] # @PURPOSE: URL for the authentication database. AUTH_DATABASE_URL = os.getenv("AUTH_DATABASE_URL", auth_config.AUTH_DATABASE_URL) # [/DEF:AUTH_DATABASE_URL:Constant] # [DEF:engine:Variable] def _build_engine(db_url: str): with belief_scope("_build_engine"): if db_url.startswith("sqlite"): return create_engine(db_url, connect_args={"check_same_thread": False}) return create_engine(db_url, pool_pre_ping=True) # @PURPOSE: SQLAlchemy engine for mappings database. engine = _build_engine(DATABASE_URL) # [/DEF:engine:Variable] # [DEF:tasks_engine:Variable] # @PURPOSE: SQLAlchemy engine for tasks database. tasks_engine = _build_engine(TASKS_DATABASE_URL) # [/DEF:tasks_engine:Variable] # [DEF:auth_engine:Variable] # @PURPOSE: SQLAlchemy engine for authentication database. auth_engine = _build_engine(AUTH_DATABASE_URL) # [/DEF:auth_engine:Variable] # [DEF:SessionLocal:Class] # @PURPOSE: A session factory for the main mappings database. # @PRE: engine is initialized. SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) # [/DEF:SessionLocal:Class] # [DEF:TasksSessionLocal:Class] # @PURPOSE: A session factory for the tasks execution database. # @PRE: tasks_engine is initialized. TasksSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=tasks_engine) # [/DEF:TasksSessionLocal:Class] # [DEF:AuthSessionLocal:Class] # @PURPOSE: A session factory for the authentication database. # @PRE: auth_engine is initialized. AuthSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=auth_engine) # [/DEF:AuthSessionLocal:Class] # [DEF:init_db:Function] # @PURPOSE: Initializes the database by creating all tables. # @PRE: engine, tasks_engine and auth_engine are initialized. # @POST: Database tables created in all databases. # @SIDE_EFFECT: Creates physical database files if they don't exist. def init_db(): with belief_scope("init_db"): Base.metadata.create_all(bind=engine) Base.metadata.create_all(bind=tasks_engine) Base.metadata.create_all(bind=auth_engine) # [/DEF:init_db:Function] # [DEF:get_db:Function] # @PURPOSE: Dependency for getting a database session. # @PRE: SessionLocal is initialized. # @POST: Session is closed after use. # @RETURN: Generator[Session, None, None] def get_db(): with belief_scope("get_db"): db = SessionLocal() try: yield db finally: db.close() # [/DEF:get_db:Function] # [DEF:get_tasks_db:Function] # @PURPOSE: Dependency for getting a tasks database session. # @PRE: TasksSessionLocal is initialized. # @POST: Session is closed after use. # @RETURN: Generator[Session, None, None] def get_tasks_db(): with belief_scope("get_tasks_db"): db = TasksSessionLocal() try: yield db finally: db.close() # [/DEF:get_tasks_db:Function] # [DEF:get_auth_db:Function] # @PURPOSE: Dependency for getting an authentication database session. # @PRE: AuthSessionLocal is initialized. # @POST: Session is closed after use. # @RETURN: Generator[Session, None, None] def get_auth_db(): with belief_scope("get_auth_db"): db = AuthSessionLocal() try: yield db finally: db.close() # [/DEF:get_auth_db:Function] # [/DEF:backend.src.core.database:Module]