Files
konstruct/packages/shared/shared/db.py
Adolfo Delorenzo 5714acf741 feat(01-foundation-01): monorepo scaffolding, Docker Compose, and shared data models
- pyproject.toml: uv workspace with 5 member packages (shared, gateway, router, orchestrator, llm-pool)
- docker-compose.yml: PostgreSQL 16 + Redis 7 + Ollama services on konstruct-net
- .env.example: all required env vars documented, konstruct_app role (not superuser)
- scripts/init-db.sh: creates konstruct_app role at DB init time
- packages/shared/shared/config.py: Pydantic Settings loading all env vars
- packages/shared/shared/models/message.py: KonstructMessage, ChannelType, SenderInfo, MessageContent
- packages/shared/shared/models/tenant.py: Tenant, Agent, ChannelConnection SQLAlchemy 2.0 models
- packages/shared/shared/models/auth.py: PortalUser model for admin portal auth
- packages/shared/shared/db.py: async SQLAlchemy engine, session factory, get_session dependency
- packages/shared/shared/rls.py: current_tenant_id ContextVar and configure_rls_hook with parameterized SET LOCAL
- packages/shared/shared/redis_keys.py: tenant-namespaced key constructors (rate_limit, idempotency, session, engaged_thread)
2026-03-23 09:49:28 -06:00

57 lines
1.7 KiB
Python

"""
Async SQLAlchemy engine and session factory.
Usage in FastAPI:
async def route(session: AsyncSession = Depends(get_session)):
...
Usage in tests:
async with async_session_factory() as session:
...
"""
from __future__ import annotations
from collections.abc import AsyncGenerator
from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession, async_sessionmaker, create_async_engine
from shared.config import settings
# ---------------------------------------------------------------------------
# Engine — one per process; shared across all requests
# ---------------------------------------------------------------------------
engine: AsyncEngine = create_async_engine(
settings.database_url,
echo=settings.debug,
pool_pre_ping=True,
pool_size=10,
max_overflow=20,
)
# ---------------------------------------------------------------------------
# Session factory
# ---------------------------------------------------------------------------
async_session_factory: async_sessionmaker[AsyncSession] = async_sessionmaker(
engine,
class_=AsyncSession,
expire_on_commit=False,
)
async def get_session() -> AsyncGenerator[AsyncSession, None]:
"""
FastAPI dependency that yields an async database session.
The session is automatically closed (and the connection returned to the
pool) when the request context exits, even if an exception is raised.
Example:
@router.get("/agents")
async def list_agents(session: AsyncSession = Depends(get_session)):
result = await session.execute(select(Agent))
return result.scalars().all()
"""
async with async_session_factory() as session:
yield session