""" Data Consistency Validator Compares refactored service layer output with expected router output. """ # ============================================================================ # DATA STRUCTURE COMPARISON # ============================================================================ """ EXPECTED OUTPUT STRUCTURES (from router definition): =================================================== GET /api/v3/players ------------------ Response: { "count": int, "players": [ { "id": int, "name": str, "wara": float, "image": str, "image2": str | None, "team_id": int, "season": int, "pitcher_injury": str | None, "pos_1": str, "pos_2": str | None, ... "team": { "id": int, "abbrev": str, "sname": str, ... } | int # if short_output } ] } GET /api/v3/players/{player_id} ------------------------------- Response: Player dict or null GET /api/v3/players/search -------------------------- Response: { "count": int, "total_matches": int, "all_seasons": bool, "players": [Player dicts] } GET /api/v3/teams ------------------ Response: { "count": int, "teams": [ { "id": int, "abbrev": str, "sname": str, "lname": str, "gmid": int | None, "gmid2": int | None, "manager1_id": int | None, "manager2_id": int | None, "division_id": int | None, "stadium": str | None, "thumbnail": str | None, "color": str | None, "dice_color": str | None, "season": int } ] } GET /api/v3/teams/{team_id} ---------------------------- Response: Team dict or null EXPECTED BEHAVIOR DIFFERENCES (Issues Found): ============================================= 1. STATIC VS INSTANCE METHOD MISMATCH ├─ PlayerService.get_players() - Called as static in router │ └─ ISSUE: Method has `self` parameter - will fail! └─ TeamService.get_teams() - Correctly uses @classmethod └─ OK: Uses cls instead of self 2. FILTER FIELD INCONSISTENCY ├─ Router: name=str (exact match filter) └─ Service: name.lower() comparison └─ ISSUE: Different behavior! 3. POSITION FILTER INCOMPLETE ├─ Router: pos=[list of positions] └─ Service: Only checks pos_1 through pos_8 └─ OK: Actually correct implementation 4. CSV OUTPUT DIFFERENCE ├─ Router: csv=bool, returns Response with content └─ Service: as_csv=bool, returns CSV string └─ OK: Just parameter name difference 5. INJURED FILTER SEMANTICS ├─ Router: is_injured=True → show injured players └─ Service: is_injured is not None → filter il_return IS NOT NULL └─ OK: Same behavior 6. SORT PARAMETER MAPPING ├─ Router: sort="name-asc" | "cost-desc" | etc └─ Service: Maps to Player.name.asc(), Player.wara.desc() └─ OK: Correct mapping 7. DEPENDENCY INJECTION INCOMPLETE ├─ Service imports: from ..db_engine import Player, Team │ └─ ISSUE: Still uses direct model imports for filtering! ├─ Service uses: Player.team_id << team_id (Peewee query) │ └─ ISSUE: This won't work with MockPlayerRepository! └─ Service uses: peewee_fn.lower(Player.strat_code) └─ ISSUE: This won't work with MockPlayerRepository! └─ ISSUE: MockPlayerRepository doesn't support peewee_fn! 8. RESPONSE FIELD DIFFERENCES ├─ get_players: count + players [✓ match] ├─ get_one_player: returns dict or null [✓ match] ├─ search_players: count + players + all_seasons [✓ match] ├─ get_teams: count + teams [✓ match] └─ get_one_team: returns dict or null [✓ match] """ # ============================================================================ # RECOMMENDED FIXES # ============================================================================ """ To make refactored code return EXACT SAME data: 1. FIX PLAYERSERVICE METHOD SIGNATURE Current: def get_players(self, season, team_id, pos, strat_code, name, ...): Fix: Add @classmethod decorator def get_players(cls, season, team_id, pos, strat_code, name, ...): - Use cls instead of self - Use Team.select() instead of self.team_repo 2. STANDARDIZE PARAMETER NAMES Rename: - as_csv → csv (to match router) - short_output stays (both use same) 3. IMPLEMENT REPO-AGNOSTIC FILTERING Current (broken): query.where(Player.team_id << team_id) Fix for Mock: def _apply_filters(query, team_id, pos, strat_code, name, is_injured): result = [] for item in query: if team_id and item.get('team_id') not in team_id: continue if strat_code and item.get('strat_code', '').lower() not in [s.lower() for s in strat_code]: continue result.append(item) return result 4. REMOVE DEPENDENCY ON peewee_fn IN SERVICE LAYER Current: query.where(peewee_fn.lower(Player.name) == name.lower()) Fix: Do string comparison in Python for player in query: if name and player.name.lower() != name.lower(): continue 5. REMOVE UNNECESSARY IMPORTS Current in player_service.py: from peewee import fn as peewee_fn from ..db_engine import Player These imports break the dependency injection pattern. The service should ONLY use the repo interface. """ print(__doc__)