147 lines
5.0 KiB
Python
147 lines
5.0 KiB
Python
# [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]
|