|
|
""" |
|
|
Database configuration and session management for Silver Table Assistant backend. |
|
|
Uses SQLModel with AsyncEngine for Supabase PostgreSQL with pgvector support. |
|
|
""" |
|
|
|
|
|
import os |
|
|
from typing import AsyncGenerator |
|
|
|
|
|
from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession, create_async_engine |
|
|
from sqlalchemy.orm import sessionmaker |
|
|
from sqlmodel import SQLModel |
|
|
|
|
|
|
|
|
SUPABASE_URL = os.getenv("SUPABASE_URL") |
|
|
SUPABASE_SERVICE_ROLE_KEY = os.getenv("SUPABASE_SERVICE_ROLE_KEY") |
|
|
DATABASE_URL = os.getenv("DATABASE_URL") |
|
|
|
|
|
|
|
|
if not SUPABASE_URL: |
|
|
raise ValueError("SUPABASE_URL environment variable is required") |
|
|
if not SUPABASE_SERVICE_ROLE_KEY: |
|
|
raise ValueError("SUPABASE_SERVICE_ROLE_KEY environment variable is required") |
|
|
|
|
|
|
|
|
|
|
|
if DATABASE_URL: |
|
|
|
|
|
ASYNC_DATABASE_URL = DATABASE_URL.replace("postgresql://", "postgresql+asyncpg://") |
|
|
else: |
|
|
|
|
|
|
|
|
base_url = SUPABASE_URL.replace("https://", "").replace("http://", "") |
|
|
project_ref = base_url.split(".")[0] |
|
|
ASYNC_DATABASE_URL = f"postgresql+asyncpg://postgres:{SUPABASE_SERVICE_ROLE_KEY}@db.{project_ref}.supabase.co:5432/postgres" |
|
|
|
|
|
from sqlalchemy.pool import NullPool |
|
|
|
|
|
|
|
|
|
|
|
engine: AsyncEngine = create_async_engine( |
|
|
ASYNC_DATABASE_URL, |
|
|
echo=False, |
|
|
poolclass=NullPool, |
|
|
|
|
|
connect_args={ |
|
|
"statement_cache_size": 0, |
|
|
"server_settings": { |
|
|
"jit": "off", |
|
|
} |
|
|
}, |
|
|
) |
|
|
|
|
|
|
|
|
SessionLocal = sessionmaker( |
|
|
bind=engine, |
|
|
class_=AsyncSession, |
|
|
expire_on_commit=False, |
|
|
autocommit=False, |
|
|
autoflush=False, |
|
|
) |
|
|
|
|
|
|
|
|
async def create_db_and_tables() -> None: |
|
|
"""Create database tables if they don't exist.""" |
|
|
async with engine.begin() as conn: |
|
|
await conn.run_sync(SQLModel.metadata.create_all) |
|
|
|
|
|
|
|
|
async def get_session() -> AsyncGenerator[AsyncSession, None]: |
|
|
""" |
|
|
Dependency function to get database session. |
|
|
Should be used with FastAPI's Depends() decorator. |
|
|
""" |
|
|
async with SessionLocal() as session: |
|
|
try: |
|
|
yield session |
|
|
finally: |
|
|
await session.close() |
|
|
|
|
|
|
|
|
def get_db_session() -> AsyncSession: |
|
|
""" |
|
|
Get a database session for use in functions. |
|
|
Remember to close the session after use. |
|
|
""" |
|
|
return SessionLocal() |
|
|
|
|
|
|
|
|
async def close_db_connections() -> None: |
|
|
"""Close all database connections.""" |
|
|
await engine.dispose() |