""" Ghost Node — Database Engine Supports SQLite (default, zero-config) and PostgreSQL (production scale). To switch to PostgreSQL, set the DATABASE_URL environment variable: Linux/Mac: export DATABASE_URL="postgresql://user:password@localhost:5432/ghostnode" Windows: set DATABASE_URL=postgresql://user:password@localhost:5432/ghostnode Heroku/Railway/Render auto-set DATABASE_URL — Ghost Node detects it automatically. SQLite remains the default for local/single-machine use. """ import os from sqlalchemy import create_engine, event from sqlalchemy.orm import sessionmaker, declarative_base # ── Resolve DATABASE_URL ─────────────────────────────────────────────────────── _raw_url = os.environ.get("DATABASE_URL", "").strip() if not _raw_url: DATABASE_URL = "sqlite:///./sniper.db" elif _raw_url.startswith("postgres://"): # Heroku uses "postgres://" — SQLAlchemy 1.4+ requires "postgresql://" DATABASE_URL = _raw_url.replace("postgres://", "postgresql://", 1) else: DATABASE_URL = _raw_url _is_sqlite = DATABASE_URL.startswith("sqlite") _is_postgresql = DATABASE_URL.startswith("postgresql") # ── Engine ───────────────────────────────────────────────────────────────────── if _is_sqlite: engine = create_engine( DATABASE_URL, connect_args={"check_same_thread": False, "timeout": 30}, pool_pre_ping=True, echo=False, ) @event.listens_for(engine, "connect") def _set_sqlite_pragmas(dbapi_conn, _record): cur = dbapi_conn.cursor() cur.execute("PRAGMA journal_mode=WAL") cur.execute("PRAGMA synchronous=NORMAL") cur.execute("PRAGMA cache_size=10000") cur.execute("PRAGMA temp_store=MEMORY") cur.close() else: # PostgreSQL — connection pooling for multi-thread FastAPI engine = create_engine( DATABASE_URL, pool_size=10, max_overflow=20, pool_pre_ping=True, pool_recycle=1800, echo=False, ) print( f"[DB] {'SQLite' if _is_sqlite else 'PostgreSQL'} -> " f"{DATABASE_URL[:60]}{'...' if len(DATABASE_URL) > 60 else ''}" ) SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) Base = declarative_base() def get_db(): """FastAPI dependency — yields a DB session, always closes after use.""" db = SessionLocal() try: yield db finally: db.close()