Skip to main content

mlb_api/requests/person/
stats.rs

1//! Gets the stats of a player for a single game.
2
3use std::borrow::Cow;
4use crate::game::GameId;
5use crate::person::PersonId;
6use crate::Copyright;
7use crate::season::SeasonId;
8use bon::Builder;
9use serde::Deserialize;
10use std::fmt::{Display, Formatter};
11use serde::de::{Deserializer, Error};
12use crate::__stats__request_data;
13use crate::hydrations::Hydrations;
14use crate::stats::PlayStat;
15use crate::request::RequestURL;
16use crate::meta::StatGroup;
17use crate::stats::parse::{__ParsedStats, make_stat_split};
18use crate::stats::raw::{fielding, hitting, pitching};
19use crate::stats::wrappers::{AccumulatedVsPlayerMatchup, WithNone};
20
21#[derive(Debug, Deserialize, PartialEq, Clone)]
22pub struct PersonSingleGameStatsResponse {
23	pub copyright: Copyright,
24	#[serde(flatten)]
25	pub stats: SingleGameStats,
26}
27
28#[derive(Builder)]
29#[builder(derive(Into))]
30pub struct PersonSingleGameStatsRequest {
31	#[builder(into)]
32	person_id: PersonId,
33	#[builder(into)]
34	game_id: GameId,
35	#[builder(into)]
36	season: SeasonId,
37	#[builder(into)]
38	#[builder(default)]
39	hydrations: SingleGameStatsRequestData,
40}
41
42impl<S: person_single_game_stats_request_builder::State + person_single_game_stats_request_builder::IsComplete> crate::request::RequestURLBuilderExt for PersonSingleGameStatsRequestBuilder<S> {
43	type Built = PersonSingleGameStatsRequest;
44}
45
46impl Display for PersonSingleGameStatsRequest {
47	fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
48		write!(f, "http://statsapi.mlb.com/api/v1/people/{}/stats/game/{}?season={}&hydrate={}", self.person_id, self.game_id, self.season, self.hydrations)
49	}
50}
51
52impl RequestURL for PersonSingleGameStatsRequest {
53	type Response = PersonSingleGameStatsResponse;
54}
55
56#[cfg(test)]
57mod tests {
58	use crate::person::stats::PersonSingleGameStatsRequest;
59	use crate::request::RequestURLBuilderExt;
60	use crate::TEST_YEAR;
61
62	#[tokio::test]
63	async fn single_sample() {
64		let _ = PersonSingleGameStatsRequest::builder()
65			.person_id(660_271)
66			.game_id(776_562)
67			.season(TEST_YEAR)
68			.build_and_get()
69			.await
70			.unwrap();
71	}
72}
73
74#[derive(Debug, PartialEq, Clone)]
75pub struct SingleGameStats {
76	pub game_log: SingleGameStatsSimplifiedGameLogSplit,
77	pub vs_player5_y: SingleGameStatsVsPlayer5YSplit,
78	pub play_log: SingleGameStatsSimplifiedPlayLogSplit,
79}
80
81#[derive(Debug, PartialEq, Clone)]
82pub struct SingleGameStatsSimplifiedGameLogSplit {
83	pub hitting: Box<WithNone<hitting::__SimplifiedGameLogStatsData>>,
84	pub pitching: Box<WithNone<pitching::__SimplifiedGameLogStatsData>>,
85	pub fielding: Box<WithNone<fielding::__SimplifiedGameLogStatsData>>,
86}
87
88#[derive(Debug, PartialEq, Clone)]
89pub struct SingleGameStatsVsPlayer5YSplit {
90	pub hitting: Box<AccumulatedVsPlayerMatchup<hitting::__VsPlayerStatsData>>,
91	pub pitching: Box<AccumulatedVsPlayerMatchup<pitching::__VsPlayerStatsData>>,
92}
93
94#[derive(Debug, PartialEq, Clone)]
95pub struct SingleGameStatsSimplifiedPlayLogSplit {
96	pub hitting: Box<Vec<WithNone<PlayStat>>>,
97}
98
99impl<'de> Deserialize<'de> for SingleGameStats {
100	fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error>
101	where
102		Self: Sized,
103	{
104		let mut parsed_stats: __ParsedStats = <__ParsedStats as Deserialize>::deserialize(deserializer)?;
105
106		Ok(Self {
107			game_log: SingleGameStatsSimplifiedGameLogSplit {
108				hitting: Box::new(
109					make_stat_split::<WithNone<hitting::__SimplifiedGameLogStatsData>>(
110						&mut parsed_stats, "gameLog", StatGroup::Hitting,
111					).map_err(D::Error::custom)?
112				),
113				pitching: Box::new(
114					make_stat_split::<WithNone<pitching::__SimplifiedGameLogStatsData>>(
115						&mut parsed_stats, "gameLog", StatGroup::Pitching,
116					).map_err(D::Error::custom)?
117				),
118				fielding: Box::new(
119					make_stat_split::<WithNone<fielding::__SimplifiedGameLogStatsData>>(
120						&mut parsed_stats, "gameLog", StatGroup::Fielding,
121					).map_err(D::Error::custom)?
122				),
123			},
124			vs_player5_y: SingleGameStatsVsPlayer5YSplit {
125				hitting: Box::new(
126					make_stat_split::<AccumulatedVsPlayerMatchup<hitting::__VsPlayerStatsData>>(
127						&mut parsed_stats, "vsPlayer5Y", StatGroup::Hitting,
128					).map_err(D::Error::custom)?
129				),
130				pitching: Box::new(
131					make_stat_split::<AccumulatedVsPlayerMatchup<pitching::__VsPlayerStatsData>>(
132						&mut parsed_stats, "vsPlayer5Y", StatGroup::Pitching,
133					).map_err(D::Error::custom)?
134				),
135			},
136			play_log: SingleGameStatsSimplifiedPlayLogSplit {
137				hitting: Box::new(
138					make_stat_split::<Vec<WithNone<PlayStat>>>(
139						&mut parsed_stats, "playLog", StatGroup::Hitting,
140					).map_err(D::Error::custom)?
141				),
142			},
143		})
144	}
145}
146
147__stats__request_data!(pub SingleGameStats [Season]);
148
149impl Hydrations for SingleGameStats {
150	type RequestData = SingleGameStatsRequestData;
151
152	fn hydration_text(_: &Self::RequestData) -> Cow<'static, str> {
153		panic!("Hydrations::hydration_text() called on SingleGameStats. Must use `PersonSingleGameStatsRequest` instead.")
154	}
155}