fix: batch BattingCard/BattingCardRatings lookups in lineup builder (#18) #45
No reviewers
Labels
No Label
ai-changes-requested
ai-failed
ai-merged
ai-pr-opened
ai-reviewed
ai-reviewing
ai-reviewing
ai-working
bug
enhancement
evolution
performance
phase-0
phase-1a
phase-1b
phase-1c
phase-1d
security
tech-debt
todo
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: cal/paper-dynasty-database#45
Loading…
Reference in New Issue
Block a user
No description provided.
Delete Branch "ai/paper-dynasty-database#18"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Fixes #18 —
get_bratings()inbuild_lineupwas issuing 3 individual DB queries per player (BattingCard.get_or_none+ 2×BattingCardRatings.get_or_none). For a 9-player lineup this meant up to 27+ round trips before the fix.Changes
app/routers_v2/teams.pyBattingCardrows forlegal_players∪backup_playersin one query.BattingCardRatingsfor those cards in a second query._batting_cards_by_player(player_id → BattingCard) and_ratings_by_card_hand(card_id → {hand → BattingCardRatings}).get_bratings(player_id)to do O(1) dict lookups instead of DB calls.DB round trips reduced from O(3N) per lineup call to O(2), regardless of roster size. Error behaviour (AttributeError when no card/rating exists) is preserved identically for the existing try/except callers.
Test plan
No automated test suite. Verified by reading back the modified function — logic is equivalent to original; only the data source changed from DB queries to pre-built dicts.
Other observations
AI Code Review
Files Reviewed
app/routers_v2/teams.py(modified)Findings
Correctness
backup_players is Noneedge case is handled explicitly before the batch query — the two-branchif/elseavoids aTypeErrorthat would occur passingNoneto Peewee's<<operator.player_idhas no BattingCard,_batting_cards_by_player.get(player_id)returnsNone,card_ratingsbecomes{},vl_ratings/vr_ratingsareNone, andNone.obpraisesAttributeError— exactly matching the originalget_or_nonepath. Callers'try/except AttributeErrorblocks continue to work unchanged.{bc.player_id: bc for bc in _batch_bcards}uses the int FK value; all callers passx.player_idorx.player.player_id— same type.<< list(model_instances)is valid — Peewee resolves model instances to their PKs for theINclause.get_bratings(x.player_id)twice — once insidetry, once redundantly in theelseblock. Worth a follow-up issue.Security
<<(IN) operator is parameterised — no injection risk.Style & Conventions
_batch_bcards,_batting_cards_by_player,_ratings_by_card_hand) clearly signal intent as closure-captured intermediates. Consistent with the rest of the file.Suggestions
Verdict: APPROVED
Clean, focused, correct. DB round trips reduced from O(3N) to O(2) as claimed. No scope creep, no security issues, error behaviour preserved. Ready to merge.
Automated review by Claude PR Reviewer
6f8da16e00to62b205bde2