major-domo-database/data_consistency_check.py
root b3f0786503 fix: Implement proper dependency injection for PlayerService
- Removed direct Player model imports from service methods
- Added InMemoryQueryResult for mock-compatible filtering/sorting
- Added RealPlayerRepository for real DB operations
- Service now accepts AbstractPlayerRepository via constructor
- Filtering and sorting work with both mocks and real DB
- Tests can inject MockPlayerRepository for full test coverage

This enables true unit testing without database dependencies.
2026-02-03 16:45:46 +00:00

186 lines
5.5 KiB
Python

"""
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__)