backend-lehrer (10 files): - game/database.py (785 → 5), correction_api.py (683 → 4) - classroom_engine/antizipation.py (676 → 5) - llm_gateway schools/edu_search already done in prior batch klausur-service (12 files): - orientation_crop_api.py (694 → 5), pdf_export.py (677 → 4) - zeugnis_crawler.py (676 → 5), grid_editor_api.py (671 → 5) - eh_templates.py (658 → 5), mail/api.py (651 → 5) - qdrant_service.py (638 → 5), training_api.py (625 → 4) website (6 pages): - middleware (696 → 8), mail (733 → 6), consent (628 → 8) - compliance/risks (622 → 5), export (502 → 5), brandbook (629 → 7) studio-v2 (3 components): - B2BMigrationWizard (848 → 3), CleanupPanel (765 → 2) - dashboard-experimental (739 → 2) admin-lehrer (4 files): - uebersetzungen (769 → 4), manager (670 → 2) - ChunkBrowserQA (675 → 6), dsfa/page (674 → 5) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
84 lines
2.2 KiB
Python
84 lines
2.2 KiB
Python
# ==============================================
|
|
# Breakpilot Drive - Game Database
|
|
# ==============================================
|
|
# Async PostgreSQL database access for game sessions
|
|
# and student learning state.
|
|
#
|
|
# Barrel re-export: all public symbols are importable from here.
|
|
|
|
import logging
|
|
from typing import Optional
|
|
|
|
from .database_models import (
|
|
GAME_DB_URL,
|
|
LearningLevel,
|
|
StudentLearningState,
|
|
GameSessionRecord,
|
|
GameQuizAnswer,
|
|
Achievement,
|
|
ACHIEVEMENTS,
|
|
)
|
|
from .database_learning import LearningStateMixin
|
|
from .database_sessions import SessionsMixin
|
|
from .database_extras import ExtrasMixin
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class GameDatabase(LearningStateMixin, SessionsMixin, ExtrasMixin):
|
|
"""
|
|
Async database access for Breakpilot Drive game data.
|
|
|
|
Uses asyncpg for PostgreSQL access with connection pooling.
|
|
"""
|
|
|
|
def __init__(self, database_url: Optional[str] = None):
|
|
self.database_url = database_url or GAME_DB_URL
|
|
self._pool = None
|
|
self._connected = False
|
|
|
|
async def connect(self):
|
|
"""Initialize connection pool."""
|
|
if self._connected:
|
|
return
|
|
|
|
try:
|
|
import asyncpg
|
|
self._pool = await asyncpg.create_pool(
|
|
self.database_url,
|
|
min_size=2,
|
|
max_size=10,
|
|
)
|
|
self._connected = True
|
|
logger.info("Game database connected")
|
|
except ImportError:
|
|
logger.warning("asyncpg not installed, database features disabled")
|
|
except Exception as e:
|
|
logger.error(f"Game database connection failed: {e}")
|
|
|
|
async def close(self):
|
|
"""Close connection pool."""
|
|
if self._pool:
|
|
await self._pool.close()
|
|
self._connected = False
|
|
|
|
async def _ensure_connected(self):
|
|
"""Ensure database is connected."""
|
|
if not self._connected:
|
|
await self.connect()
|
|
|
|
|
|
# Global database instance
|
|
_game_db: Optional[GameDatabase] = None
|
|
|
|
|
|
async def get_game_db() -> GameDatabase:
|
|
"""Get or create the global game database instance."""
|
|
global _game_db
|
|
|
|
if _game_db is None:
|
|
_game_db = GameDatabase()
|
|
await _game_db.connect()
|
|
|
|
return _game_db
|