grip / app /core /database.py
github-actions
Deploy to Hugging Face
ee2e133
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession, async_sessionmaker
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.pool import NullPool
from app.core.config import get_settings
import ssl
settings = get_settings()
# Handle missing DATABASE_URL
db_url = settings.ASYNC_DATABASE_URL
if not db_url:
print("WARNING: DATABASE_URL not set. Using in-memory SQLite.")
db_url = "sqlite+aiosqlite:///:memory:"
# Initialize engine
engine = None
try:
connect_args = {}
poolclass = None
if "sqlite" in db_url:
connect_args = {"check_same_thread": False}
else:
# PostgreSQL configuration
connect_args = {
"statement_cache_size": 0, # Required for Supabase pooler
"server_settings": {"application_name": "grip_backend"},
"timeout": 20,
"command_timeout": 20
}
# Supabase-specific configuration
if "supabase" in db_url.lower():
# Use NullPool for Supabase Transaction Pooler (port 6543)
if ":6543" in db_url:
poolclass = NullPool
# Permissive SSL context for Supabase
ssl_context = ssl.create_default_context()
ssl_context.check_hostname = False
ssl_context.verify_mode = ssl.CERT_NONE
connect_args["ssl"] = ssl_context
# Create engine
engine_kwargs = {"echo": False, "connect_args": connect_args}
if poolclass is NullPool:
engine_kwargs["poolclass"] = NullPool
else:
engine_kwargs.update({
"pool_pre_ping": True,
"pool_recycle": 300,
"pool_size": 10,
"max_overflow": 20,
})
engine = create_async_engine(db_url, **engine_kwargs)
except Exception as e:
print(f"CRITICAL: Failed to create database engine: {e}")
import traceback
traceback.print_exc()
# Fallback to SQLite
engine = create_async_engine("sqlite+aiosqlite:///:memory:", poolclass=NullPool)
# Session factory
AsyncSessionLocal = async_sessionmaker(
bind=engine,
class_=AsyncSession,
expire_on_commit=False,
autoflush=False
)
# Base model
class Base(DeclarativeBase):
pass
# Dependency
async def get_db():
async with AsyncSessionLocal() as session:
yield session