feat: flatten PlayerProfileResponse with top-level parent/team/coach fields #291
No reviewers
Labels
No labels
domain:backend
domain:devops
domain:frontend
status:approved
status:in-progress
status:needs-fix
status:qa
type:bug
type:devops
type:feature
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
forgejo_admin/basketball-api!291
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "280-flatten-player-profile"
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
Adds
parent_name,parent_phone,parent_email,team_name,team_id, andcoach_nameas top-level convenience fields onPlayerProfileResponse. This is additive -- nestedparentandteamobjects remain unchanged.Changes
src/basketball_api/routes/players.py-- Added 6Optionalfields toPlayerProfileResponsemodel and populated them from existing relationships in_player_profile_response()tests/test_players.py-- AddedTestFlattenedProfileFieldsclass with 2 tests: one verifying populated fields (player with team+coach), one verifying null fields (player without team)Test Plan
ruff formatandruff checkcleanReview Checklist
ruff formatandruff checkcleanRelated Notes
None.
Related
PR #291 Review
DOMAIN REVIEW
Stack: Python / FastAPI / SQLAlchemy / Pydantic v2
Schema design: The additive approach is correct -- 6 new
Optionalfields onPlayerProfileResponsewith defaults ofNone, so existing consumers are unaffected. No migration needed since these are computed fields on the Pydantic model, not DB columns.Refactor of
_player_profile_response(): The extraction ofparent_obj = player.parentandteam_obj = player.teamis a clean local-variable refactoring. TheParentInfoconstruction correctly moved fromplayer.parent.Xtoparent_obj.X.Relationship loading:
player.parentis backed by a non-nullable FK (parent_id: Mapped[int]), so it is always populated.player.teamis a@propertyreturningself.teams[0] if self.teams else None. Both are already eagerly loaded viajoinedloadin_get_player_or_404(). No N+1 risk.Pydantic compliance:
model_config = {"from_attributes": True}is present. Union syntaxstr | Noneis PEP 604 compliant. Field defaults are properly set with= None.Ruff: PR body claims
ruff formatandruff checkclean.BLOCKERS
None.
NITS
Unnecessary defensive guard on
parent_obj: The flattened parent fields useparent_obj.name if parent_obj else None, butparent_idis a non-nullable FK, meaningplayer.parentis neverNone. TheParentInfoconstruction on the line above accessesparent_obj.idunconditionally (no guard), which would crash first anyway if parent were somehow null. The guards are harmless but inconsistent. Consider removing them for consistency, or adding a guard toParentInfoas well if the intent is belt-and-suspenders.File:
src/basketball_api/routes/players.py, flattened parent fields block.PR body missing Related plan slug: The Related section references issue #280 and spike #278 but does not reference a plan slug. If there is no governing plan for this spike work, this is fine, but the SOP template calls for it.
SOP COMPLIANCE
280-flatten-player-profilematches #280)PROCESS OBSERVATIONS
VERDICT: APPROVED