Initial commit: WealthWise financial analytics platform
This commit is contained in:
123
backend/app/core/db.py
Normal file
123
backend/app/core/db.py
Normal file
@@ -0,0 +1,123 @@
|
||||
"""WealthWise database configuration and session management.
|
||||
|
||||
This module provides:
|
||||
- Async SQLAlchemy engine with connection pooling
|
||||
- Async session factory for database operations
|
||||
- FastAPI dependency for session injection
|
||||
- Connection health checking utilities
|
||||
"""
|
||||
|
||||
from typing import AsyncGenerator
|
||||
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
from sqlalchemy.ext.asyncio import (
|
||||
AsyncEngine,
|
||||
AsyncSession,
|
||||
async_sessionmaker,
|
||||
create_async_engine,
|
||||
)
|
||||
from sqlalchemy.pool import NullPool
|
||||
from sqlmodel.ext.asyncio.session import AsyncSession as SQLModelAsyncSession
|
||||
|
||||
from app.core.config import get_settings
|
||||
|
||||
settings = get_settings()
|
||||
|
||||
|
||||
# Create async engine with connection pooling
|
||||
# Supabase Transaction Pooler (port 6543) supports high concurrency
|
||||
engine: AsyncEngine = create_async_engine(
|
||||
settings.DATABASE_URL,
|
||||
echo=settings.DB_ECHO,
|
||||
pool_size=settings.DB_POOL_SIZE,
|
||||
max_overflow=settings.DB_MAX_OVERFLOW,
|
||||
pool_pre_ping=settings.DB_POOL_PRE_PING,
|
||||
# Connection pool settings for production
|
||||
pool_recycle=3600, # Recycle connections after 1 hour
|
||||
pool_timeout=30, # Wait up to 30 seconds for available connection
|
||||
# Async-specific settings
|
||||
future=True,
|
||||
)
|
||||
|
||||
# Create async session factory
|
||||
# expire_on_commit=False allows accessing attributes after session closes
|
||||
AsyncSessionLocal = async_sessionmaker(
|
||||
engine,
|
||||
class_=SQLModelAsyncSession,
|
||||
expire_on_commit=False,
|
||||
autoflush=False,
|
||||
autocommit=False,
|
||||
)
|
||||
|
||||
|
||||
async def get_session() -> AsyncGenerator[SQLModelAsyncSession, None]:
|
||||
"""FastAPI dependency that provides an async database session.
|
||||
|
||||
This generator yields a database session for use in API endpoints.
|
||||
It automatically handles transaction rollback on errors and ensures
|
||||
proper session cleanup.
|
||||
|
||||
Usage:
|
||||
@app.get("/items")
|
||||
async def get_items(session: AsyncSession = Depends(get_session)):
|
||||
result = await session.execute(select(Item))
|
||||
return result.scalars().all()
|
||||
|
||||
Yields:
|
||||
AsyncSession: Database session instance
|
||||
|
||||
Raises:
|
||||
SQLAlchemyError: Re-raised after rollback if database error occurs
|
||||
"""
|
||||
session: SQLModelAsyncSession = AsyncSessionLocal()
|
||||
try:
|
||||
yield session
|
||||
await session.commit()
|
||||
except SQLAlchemyError as e:
|
||||
await session.rollback()
|
||||
raise e
|
||||
finally:
|
||||
await session.close()
|
||||
|
||||
|
||||
async def close_engine() -> None:
|
||||
"""Close all database connections.
|
||||
|
||||
Call this during application shutdown to properly release
|
||||
all database connections in the pool.
|
||||
"""
|
||||
await engine.dispose()
|
||||
|
||||
|
||||
async def check_db_connection() -> bool:
|
||||
"""Verify database connectivity by executing a simple query.
|
||||
|
||||
Returns:
|
||||
True if database is accessible, False otherwise
|
||||
"""
|
||||
try:
|
||||
async with AsyncSessionLocal() as session:
|
||||
result = await session.execute("SELECT 1")
|
||||
return result.scalar() == 1
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
# For Alembic migrations (sync operations)
|
||||
def create_sync_engine():
|
||||
"""Create synchronous engine for Alembic migrations.
|
||||
|
||||
Returns:
|
||||
SyncEngine: Synchronous SQLAlchemy engine
|
||||
"""
|
||||
from sqlalchemy import create_engine
|
||||
|
||||
# Convert async URL to sync URL
|
||||
sync_url = settings.DATABASE_URL.replace(
|
||||
"postgresql+asyncpg://", "postgresql://"
|
||||
)
|
||||
|
||||
return create_engine(
|
||||
sync_url,
|
||||
echo=settings.DB_ECHO,
|
||||
)
|
||||
Reference in New Issue
Block a user