# ============================================== # 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