fix: invalidate cache after PlayerService write operations (#32)
All checks were successful
Build Docker Image / build (pull_request) Successful in 2m10s
All checks were successful
Build Docker Image / build (pull_request) Successful in 2m10s
Add finally blocks to update_player, patch_player, create_players, and delete_player in PlayerService to call invalidate_related_cache() using the existing cache_patterns. Matches the pattern already used in TeamService. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
ddf5f77da4
commit
ea7c62c93f
@ -39,7 +39,7 @@ class PlayerService(BaseService):
|
|||||||
cache_patterns = ["players*", "players-search*", "player*", "team-roster*"]
|
cache_patterns = ["players*", "players-search*", "player*", "team-roster*"]
|
||||||
|
|
||||||
# Deprecated fields to exclude from player responses
|
# Deprecated fields to exclude from player responses
|
||||||
EXCLUDED_FIELDS = ['pitcher_injury']
|
EXCLUDED_FIELDS = ["pitcher_injury"]
|
||||||
|
|
||||||
# Class-level repository for dependency injection
|
# Class-level repository for dependency injection
|
||||||
_injected_repo: Optional[AbstractPlayerRepository] = None
|
_injected_repo: Optional[AbstractPlayerRepository] = None
|
||||||
@ -154,7 +154,7 @@ class PlayerService(BaseService):
|
|||||||
return {
|
return {
|
||||||
"count": len(players_data),
|
"count": len(players_data),
|
||||||
"total": total_count,
|
"total": total_count,
|
||||||
"players": players_data
|
"players": players_data,
|
||||||
}
|
}
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -204,9 +204,9 @@ class PlayerService(BaseService):
|
|||||||
p_list = [x.upper() for x in pos]
|
p_list = [x.upper() for x in pos]
|
||||||
|
|
||||||
# Expand generic "P" to match all pitcher positions
|
# Expand generic "P" to match all pitcher positions
|
||||||
pitcher_positions = ['SP', 'RP', 'CP']
|
pitcher_positions = ["SP", "RP", "CP"]
|
||||||
if 'P' in p_list:
|
if "P" in p_list:
|
||||||
p_list.remove('P')
|
p_list.remove("P")
|
||||||
p_list.extend(pitcher_positions)
|
p_list.extend(pitcher_positions)
|
||||||
|
|
||||||
pos_conditions = (
|
pos_conditions = (
|
||||||
@ -245,9 +245,9 @@ class PlayerService(BaseService):
|
|||||||
p_list = [p.upper() for p in pos]
|
p_list = [p.upper() for p in pos]
|
||||||
|
|
||||||
# Expand generic "P" to match all pitcher positions
|
# Expand generic "P" to match all pitcher positions
|
||||||
pitcher_positions = ['SP', 'RP', 'CP']
|
pitcher_positions = ["SP", "RP", "CP"]
|
||||||
if 'P' in p_list:
|
if "P" in p_list:
|
||||||
p_list.remove('P')
|
p_list.remove("P")
|
||||||
p_list.extend(pitcher_positions)
|
p_list.extend(pitcher_positions)
|
||||||
|
|
||||||
player_pos = [
|
player_pos = [
|
||||||
@ -385,19 +385,23 @@ class PlayerService(BaseService):
|
|||||||
# This filters at the database level instead of loading all players
|
# This filters at the database level instead of loading all players
|
||||||
if search_all_seasons:
|
if search_all_seasons:
|
||||||
# Search all seasons, order by season DESC (newest first)
|
# Search all seasons, order by season DESC (newest first)
|
||||||
query = (Player.select()
|
query = (
|
||||||
.where(fn.Lower(Player.name).contains(query_lower))
|
Player.select()
|
||||||
.order_by(Player.season.desc(), Player.name)
|
.where(fn.Lower(Player.name).contains(query_lower))
|
||||||
.limit(limit * 2)) # Get extra for exact match sorting
|
.order_by(Player.season.desc(), Player.name)
|
||||||
|
.limit(limit * 2)
|
||||||
|
) # Get extra for exact match sorting
|
||||||
else:
|
else:
|
||||||
# Search specific season
|
# Search specific season
|
||||||
query = (Player.select()
|
query = (
|
||||||
.where(
|
Player.select()
|
||||||
(Player.season == season) &
|
.where(
|
||||||
(fn.Lower(Player.name).contains(query_lower))
|
(Player.season == season)
|
||||||
)
|
& (fn.Lower(Player.name).contains(query_lower))
|
||||||
.order_by(Player.name)
|
)
|
||||||
.limit(limit * 2)) # Get extra for exact match sorting
|
.order_by(Player.name)
|
||||||
|
.limit(limit * 2)
|
||||||
|
) # Get extra for exact match sorting
|
||||||
|
|
||||||
# Execute query and convert limited results to dicts
|
# Execute query and convert limited results to dicts
|
||||||
players = list(query)
|
players = list(query)
|
||||||
@ -468,19 +472,29 @@ class PlayerService(BaseService):
|
|||||||
# Use backrefs=False to avoid circular reference issues
|
# Use backrefs=False to avoid circular reference issues
|
||||||
player_dict = model_to_dict(player, recurse=recurse, backrefs=False)
|
player_dict = model_to_dict(player, recurse=recurse, backrefs=False)
|
||||||
# Filter out excluded fields
|
# Filter out excluded fields
|
||||||
return {k: v for k, v in player_dict.items() if k not in cls.EXCLUDED_FIELDS}
|
return {
|
||||||
|
k: v for k, v in player_dict.items() if k not in cls.EXCLUDED_FIELDS
|
||||||
|
}
|
||||||
except (ImportError, AttributeError, TypeError) as e:
|
except (ImportError, AttributeError, TypeError) as e:
|
||||||
# Log the error and fall back to non-recursive serialization
|
# Log the error and fall back to non-recursive serialization
|
||||||
logger.warning(f"Error in recursive player serialization: {e}, falling back to non-recursive")
|
logger.warning(
|
||||||
|
f"Error in recursive player serialization: {e}, falling back to non-recursive"
|
||||||
|
)
|
||||||
try:
|
try:
|
||||||
# Fallback to non-recursive serialization
|
# Fallback to non-recursive serialization
|
||||||
player_dict = model_to_dict(player, recurse=False)
|
player_dict = model_to_dict(player, recurse=False)
|
||||||
return {k: v for k, v in player_dict.items() if k not in cls.EXCLUDED_FIELDS}
|
return {
|
||||||
|
k: v for k, v in player_dict.items() if k not in cls.EXCLUDED_FIELDS
|
||||||
|
}
|
||||||
except Exception as fallback_error:
|
except Exception as fallback_error:
|
||||||
# Final fallback to basic dict conversion
|
# Final fallback to basic dict conversion
|
||||||
logger.error(f"Error in non-recursive serialization: {fallback_error}, using basic dict")
|
logger.error(
|
||||||
|
f"Error in non-recursive serialization: {fallback_error}, using basic dict"
|
||||||
|
)
|
||||||
player_dict = dict(player)
|
player_dict = dict(player)
|
||||||
return {k: v for k, v in player_dict.items() if k not in cls.EXCLUDED_FIELDS}
|
return {
|
||||||
|
k: v for k, v in player_dict.items() if k not in cls.EXCLUDED_FIELDS
|
||||||
|
}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def update_player(
|
def update_player(
|
||||||
@ -508,6 +522,8 @@ class PlayerService(BaseService):
|
|||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=500, detail=f"Error updating player {player_id}: {str(e)}"
|
status_code=500, detail=f"Error updating player {player_id}: {str(e)}"
|
||||||
)
|
)
|
||||||
|
finally:
|
||||||
|
temp_service.invalidate_related_cache(cls.cache_patterns)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def patch_player(
|
def patch_player(
|
||||||
@ -535,6 +551,8 @@ class PlayerService(BaseService):
|
|||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=500, detail=f"Error patching player {player_id}: {str(e)}"
|
status_code=500, detail=f"Error patching player {player_id}: {str(e)}"
|
||||||
)
|
)
|
||||||
|
finally:
|
||||||
|
temp_service.invalidate_related_cache(cls.cache_patterns)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create_players(
|
def create_players(
|
||||||
@ -567,6 +585,8 @@ class PlayerService(BaseService):
|
|||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=500, detail=f"Error creating players: {str(e)}"
|
status_code=500, detail=f"Error creating players: {str(e)}"
|
||||||
)
|
)
|
||||||
|
finally:
|
||||||
|
temp_service.invalidate_related_cache(cls.cache_patterns)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def delete_player(cls, player_id: int, token: str) -> Dict[str, str]:
|
def delete_player(cls, player_id: int, token: str) -> Dict[str, str]:
|
||||||
@ -590,6 +610,8 @@ class PlayerService(BaseService):
|
|||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=500, detail=f"Error deleting player {player_id}: {str(e)}"
|
status_code=500, detail=f"Error deleting player {player_id}: {str(e)}"
|
||||||
)
|
)
|
||||||
|
finally:
|
||||||
|
temp_service.invalidate_related_cache(cls.cache_patterns)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _format_player_csv(cls, players: List[Dict]) -> str:
|
def _format_player_csv(cls, players: List[Dict]) -> str:
|
||||||
@ -603,12 +625,12 @@ class PlayerService(BaseService):
|
|||||||
flat_player = player.copy()
|
flat_player = player.copy()
|
||||||
|
|
||||||
# Flatten team object to just abbreviation
|
# Flatten team object to just abbreviation
|
||||||
if isinstance(flat_player.get('team'), dict):
|
if isinstance(flat_player.get("team"), dict):
|
||||||
flat_player['team'] = flat_player['team'].get('abbrev', '')
|
flat_player["team"] = flat_player["team"].get("abbrev", "")
|
||||||
|
|
||||||
# Flatten sbaplayer object to just ID
|
# Flatten sbaplayer object to just ID
|
||||||
if isinstance(flat_player.get('sbaplayer'), dict):
|
if isinstance(flat_player.get("sbaplayer"), dict):
|
||||||
flat_player['sbaplayer'] = flat_player['sbaplayer'].get('id', '')
|
flat_player["sbaplayer"] = flat_player["sbaplayer"].get("id", "")
|
||||||
|
|
||||||
flattened_players.append(flat_player)
|
flattened_players.append(flat_player)
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user