# [DEF:backend.src.core.database:Module] # # @SEMANTICS: database, sqlite, sqlalchemy, session, persistence # @PURPOSE: Configures the SQLite database connection and session management. # @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 .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 (where .db files should reside). BASE_DIR = Path(__file__).resolve().parent.parent.parent # [/DEF:BASE_DIR:Variable] # [DEF:DATABASE_URL:Constant] # @PURPOSE: URL for the main mappings database. DATABASE_URL = os.getenv("DATABASE_URL", f"sqlite:///{BASE_DIR}/mappings.db") # [/DEF:DATABASE_URL:Constant] # [DEF:TASKS_DATABASE_URL:Constant] # @PURPOSE: URL for the tasks execution database. TASKS_DATABASE_URL = os.getenv("TASKS_DATABASE_URL", f"sqlite:///{BASE_DIR}/tasks.db") # [/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) # If it's a relative sqlite path starting with ./backend/, fix it to be absolute or relative to BASE_DIR if AUTH_DATABASE_URL.startswith("sqlite:///./backend/"): AUTH_DATABASE_URL = AUTH_DATABASE_URL.replace("sqlite:///./backend/", f"sqlite:///{BASE_DIR}/") elif AUTH_DATABASE_URL.startswith("sqlite:///./") and not AUTH_DATABASE_URL.startswith("sqlite:///./backend/"): # If it's just ./ but we are in backend, it's fine, but let's make it absolute for robustness AUTH_DATABASE_URL = AUTH_DATABASE_URL.replace("sqlite:///./", f"sqlite:///{BASE_DIR}/") # [/DEF:AUTH_DATABASE_URL:Constant] # [DEF:engine:Variable] # @PURPOSE: SQLAlchemy engine for mappings database. engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False}) # [/DEF:engine:Variable] # [DEF:tasks_engine:Variable] # @PURPOSE: SQLAlchemy engine for tasks database. tasks_engine = create_engine(TASKS_DATABASE_URL, connect_args={"check_same_thread": False}) # [/DEF:tasks_engine:Variable] # [DEF:auth_engine:Variable] # @PURPOSE: SQLAlchemy engine for authentication database. auth_engine = create_engine(AUTH_DATABASE_URL, connect_args={"check_same_thread": False}) # [/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]