from pathlib import Path from typing import Dict, Iterable, Optional import yaml from app.game.models.races import Race class RaceRepository: def __init__(self): self.root = Path() / "app" / "game" / "templates" / "races" self._by_id: Dict[str, Race] = {} self.load() @staticmethod def _iter_yaml_files(root: Path) -> Iterable[Path]: # Recursively find *.yaml under the root yield from root.rglob("*.yaml") def load(self) -> None: for path in self._iter_yaml_files(self.root): with path.open("r", encoding="utf-8") as f: data = yaml.safe_load(f) or {} race = Race.from_yaml(data) if race.id in self._by_id: raise ValueError(f"Duplicate Race id '{race.id}' in {path}") self._by_id.update({race.id:race}) # ----- Queries ----- def get(self, race_id: str) -> Optional[Race]: return self._by_id.get(race_id) def list_all(self) -> list[Race]: return list(self._by_id.values()) def list_playable(self) -> list[Race]: return [r for r in self._by_id.values() if r.is_playable] def list_non_playable(self) -> list[Race]: return [r for r in self._by_id.values() if not r.is_playable] def list_by_tag(self, tag: str) -> list[Race]: return [r for r in self._by_id.values() if tag in r.tags] def list_by_any_tags(self, tags: set[str]) -> list[Race]: return [r for r in self._by_id.values() if r.tags & tags]