All checks were successful
Build Docker Image / build (pull_request) Successful in 2m32s
Enables career-total aggregation by real-world player identity (SbaPlayer) across all seasons. JOINs StratPlay → Player to access Player.sbaplayer FK, groups by that FK, and excludes players with null sbaplayer. Also refactors stratplay router from single file into package and adds integration tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
107 lines
2.4 KiB
Python
107 lines
2.4 KiB
Python
from typing import List, Literal
|
|
|
|
from pydantic import BaseModel, validator
|
|
|
|
POS_LIST = Literal[
|
|
"C", "1B", "2B", "3B", "SS", "LF", "CF", "RF", "P", "DH", "PH", "PR", "GHOST"
|
|
]
|
|
|
|
|
|
class PlayModel(BaseModel):
|
|
game_id: int
|
|
play_num: int
|
|
batter_id: int = None
|
|
batter_team_id: int = None
|
|
pitcher_id: int
|
|
pitcher_team_id: int = None
|
|
on_base_code: str
|
|
inning_half: Literal["top", "bot", "Top", "Bot"]
|
|
inning_num: int
|
|
batting_order: int
|
|
starting_outs: int
|
|
away_score: int
|
|
home_score: int
|
|
batter_pos: POS_LIST = None
|
|
|
|
on_first_id: int = None
|
|
on_first_final: int = None
|
|
on_second_id: int = None
|
|
on_second_final: int = None
|
|
on_third_id: int = None
|
|
on_third_final: int = None
|
|
batter_final: int = None
|
|
|
|
pa: int = 0
|
|
ab: int = 0
|
|
e_run: int = 0
|
|
run: int = 0
|
|
hit: int = 0
|
|
rbi: int = 0
|
|
double: int = 0
|
|
triple: int = 0
|
|
homerun: int = 0
|
|
bb: int = 0
|
|
so: int = 0
|
|
hbp: int = 0
|
|
sac: int = 0
|
|
ibb: int = 0
|
|
gidp: int = 0
|
|
bphr: int = 0
|
|
bpfo: int = 0
|
|
bp1b: int = 0
|
|
bplo: int = 0
|
|
sb: int = 0
|
|
cs: int = 0
|
|
outs: int = 0
|
|
wpa: float = 0
|
|
|
|
catcher_id: int = None
|
|
catcher_team_id: int = None
|
|
defender_id: int = None
|
|
defender_team_id: int = None
|
|
runner_id: int = None
|
|
runner_team_id: int = None
|
|
|
|
check_pos: POS_LIST = None
|
|
error: int = 0
|
|
wild_pitch: int = 0
|
|
passed_ball: int = 0
|
|
pick_off: int = 0
|
|
balk: int = 0
|
|
is_go_ahead: bool = False
|
|
is_tied: bool = False
|
|
is_new_inning: bool = False
|
|
|
|
hand_batting: str = None
|
|
hand_pitching: str = None
|
|
re24_primary: float = None
|
|
re24_running: float = None
|
|
|
|
@validator("on_first_final")
|
|
def no_final_if_no_runner_one(cls, v, values):
|
|
if values["on_first_id"] is None:
|
|
return None
|
|
return v
|
|
|
|
@validator("on_second_final")
|
|
def no_final_if_no_runner_two(cls, v, values):
|
|
if values["on_second_id"] is None:
|
|
return None
|
|
return v
|
|
|
|
@validator("on_third_final")
|
|
def no_final_if_no_runner_three(cls, v, values):
|
|
if values["on_third_id"] is None:
|
|
return None
|
|
return v
|
|
|
|
@validator("batter_final")
|
|
def no_final_if_no_batter(cls, v, values):
|
|
if values["batter_id"] is None:
|
|
return None
|
|
return v
|
|
|
|
|
|
class PlayList(BaseModel):
|
|
plays: List[PlayModel]
|