Major reduction in CLAUDE.md file sizes to follow concise documentation standard: | File | Before | After | Reduction | |------|--------|-------|-----------| | backend/CLAUDE.md | 2,467 | 123 | 95% | | models/CLAUDE.md | 1,586 | 102 | 94% | | websocket/CLAUDE.md | 2,094 | 119 | 94% | | config/CLAUDE.md | 1,017 | 126 | 88% | | database/CLAUDE.md | 946 | 130 | 86% | | api/CLAUDE.md | 906 | 140 | 85% | Total: 9,016 -> 740 lines (92% reduction) All files now under 150 lines with: - Essential patterns and usage - Cross-references to related docs - Quick-start examples - Updated timestamps 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
3.2 KiB
3.2 KiB
Database Module - Async PostgreSQL Persistence
Purpose
Async PostgreSQL persistence layer using SQLAlchemy 2.0. Handles all database operations with connection pooling and proper transaction management.
Structure
app/database/
├── __init__.py # Package exports
├── session.py # Async session management, Base declarative
└── operations.py # DatabaseOperations class
Session Management
Async Session Pattern
from app.database.session import get_session
async def some_function():
async with get_session() as session:
result = await session.execute(query)
# Auto-commits on success, rolls back on exception
Connection Pool
- Driver: asyncpg
- Pool: SQLAlchemy async pool
- Configurable pool size via env vars
DatabaseOperations
Singleton class with all database operations.
Game Operations
from app.database.operations import DatabaseOperations
db_ops = DatabaseOperations()
await db_ops.create_game(game_id, league_id, home_team_id, away_team_id, ...)
await db_ops.update_game_state(game_id, inning, half, home_score, away_score)
game_data = await db_ops.load_game_state(game_id)
Play Operations
play_id = await db_ops.save_play(game_id, play_data, stats_data)
plays = await db_ops.get_plays(game_id, limit=100)
Lineup Operations
lineup_id = await db_ops.add_pd_lineup_card(game_id, team_id, card_id, position, batting_order)
lineup_id = await db_ops.add_sba_lineup_player(game_id, team_id, player_id, position, batting_order)
lineup = await db_ops.get_active_lineup(game_id, team_id)
await db_ops.deactivate_lineup_player(lineup_id)
Roster Operations
await db_ops.add_pd_roster_card(game_id, card_id, team_id)
await db_ops.add_sba_roster_player(game_id, player_id, team_id)
roster = await db_ops.get_pd_roster(game_id, team_id)
Session Operations
await db_ops.create_game_session(game_id)
await db_ops.update_session_snapshot(game_id, state_snapshot)
Common Patterns
Transaction Handling
async with AsyncSessionLocal() as session:
try:
# Multiple operations
await session.commit()
except Exception:
await session.rollback()
raise
Efficient Queries
# Use joinedload for relationships needed immediately
from sqlalchemy.orm import joinedload
query = select(Play).options(
joinedload(Play.batter),
joinedload(Play.pitcher)
)
Direct UPDATE
# More efficient than SELECT + modify + commit
stmt = update(Game).where(Game.id == game_id).values(inning=5)
await session.execute(stmt)
Database Schema
See ../models/CLAUDE.md for model details.
| Table | Purpose |
|---|---|
| games | Game container, scores, status |
| plays | At-bat records with 25+ stats |
| lineups | Player assignments, substitutions |
| game_sessions | WebSocket state |
| roster_links | Eligible cards/players |
Environment
DATABASE_URL=postgresql+asyncpg://user:pass@10.10.0.42:5432/paperdynasty_dev
References
- Models: See
../models/CLAUDE.md - State Recovery: See
../core/state_manager.py
Tests: tests/integration/database/ | Updated: 2025-01-19