from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker, DeclarativeBase from app.core.config import settings # Check for Turso remote connection is_turso = "turso.io" in settings.DATABASE_URL and settings.TURSO_AUTH_TOKEN if is_turso: # Extract hostname hostname = settings.DATABASE_URL if "://" in hostname: hostname = hostname.split("://")[1] if "?" in hostname: hostname = hostname.split("?")[0] from sqlalchemy.pool import NullPool # Proxy to satisfy SQLAlchemy's requirement for create_function on SQLite connections class LibsqlConnectionProxy: def __init__(self, conn): # Use __dict__ to avoid infinite recursion with __setattr__ self.__dict__["_conn"] = conn def __getattr__(self, name): return getattr(self._conn, name) def __setattr__(self, name, value): if name == "_conn": self.__dict__["_conn"] = value else: setattr(self._conn, name, value) def create_function(self, *args, **kwargs): # libsql doesn't support create_function over HTTP, but SQLAlchemy expects it return None # Force HTTPS for stability on HF Spaces (avoids 505/WebSocket handshake errors) def create_libsql_connection(): import libsql url = f"https://{hostname}" print(f">>> [DB] Establishing SECURE HTTP connection to Turso: {hostname}") conn = libsql.connect(url, auth_token=settings.TURSO_AUTH_TOKEN) return LibsqlConnectionProxy(conn) # Use NullPool for Turso HTTPS to avoid "detached connection fairy" errors in multi-thread env engine = create_engine( "sqlite+libsql://", creator=create_libsql_connection, poolclass=NullPool, echo=False, ) else: # Standard local SQLite connect_args = {} if "sqlite" in settings.DATABASE_URL or "libsql" in settings.DATABASE_URL: connect_args["check_same_thread"] = False engine = create_engine( settings.DATABASE_URL, pool_size=20, max_overflow=max(10, 20), # Allow some overflow during peak pool_timeout=30, pool_recycle=1800, connect_args=connect_args, echo=False, ) SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) class Base(DeclarativeBase): pass def get_db(): db = SessionLocal() try: yield db finally: db.close()