- Created backend/.claude/DATABASE_SCHEMA.md with full table details - Updated database/CLAUDE.md to reference the new schema doc - Preserves valuable reference material while keeping CLAUDE.md concise 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
132 lines
3.3 KiB
Markdown
132 lines
3.3 KiB
Markdown
# 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
|
|
```python
|
|
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
|
|
```python
|
|
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
|
|
```python
|
|
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
|
|
```python
|
|
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
|
|
```python
|
|
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
|
|
```python
|
|
await db_ops.create_game_session(game_id)
|
|
await db_ops.update_session_snapshot(game_id, state_snapshot)
|
|
```
|
|
|
|
## Common Patterns
|
|
|
|
### Transaction Handling
|
|
```python
|
|
async with AsyncSessionLocal() as session:
|
|
try:
|
|
# Multiple operations
|
|
await session.commit()
|
|
except Exception:
|
|
await session.rollback()
|
|
raise
|
|
```
|
|
|
|
### Efficient Queries
|
|
```python
|
|
# Use joinedload for relationships needed immediately
|
|
from sqlalchemy.orm import joinedload
|
|
|
|
query = select(Play).options(
|
|
joinedload(Play.batter),
|
|
joinedload(Play.pitcher)
|
|
)
|
|
```
|
|
|
|
### Direct UPDATE
|
|
```python
|
|
# 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
|
|
|
|
```bash
|
|
DATABASE_URL=postgresql+asyncpg://user:pass@10.10.0.42:5432/paperdynasty_dev
|
|
```
|
|
|
|
## References
|
|
|
|
- **Database Schema**: See `../../.claude/DATABASE_SCHEMA.md` for complete table details
|
|
- **Models**: See `../models/CLAUDE.md`
|
|
- **State Recovery**: See `../core/state_manager.py`
|
|
|
|
---
|
|
|
|
**Tests**: `tests/integration/database/` | **Updated**: 2025-01-19
|