from pathlib import Path from sqlalchemy import create_engine, text from sqlalchemy.orm import DeclarativeBase, sessionmaker from .config import settings Path(settings.database_path).parent.mkdir(parents=True, exist_ok=True) engine = create_engine( f"sqlite:///{settings.database_path}", connect_args={"check_same_thread": False}, ) SessionLocal = sessionmaker(bind=engine, autoflush=False, autocommit=False) class Base(DeclarativeBase): pass # Columns added to existing tables after their first release. create_all() # only creates missing *tables*, so an upgrade on an existing SQLite file # needs these added by hand — a lightweight alternative to a full migration # framework, appropriate for this project's scale. Add a new (table, column, # ddl-type-and-default) tuple here whenever a model gains a field. _COLUMN_MIGRATIONS = [ ("market_spikes", "top_keywords_json", "TEXT DEFAULT '[]'"), ] def _run_column_migrations() -> None: with engine.connect() as conn: for table, column, ddl in _COLUMN_MIGRATIONS: existing = {row[1] for row in conn.execute(text(f"PRAGMA table_info({table})"))} if column not in existing: conn.execute(text(f"ALTER TABLE {table} ADD COLUMN {column} {ddl}")) conn.commit() def init_db() -> None: from . import models # noqa: F401 (registers tables on Base.metadata) Base.metadata.create_all(bind=engine) _run_column_migrations() def get_session(): session = SessionLocal() try: yield session finally: session.close()