Skip to main content

mlb_api/requests/schedule/postseason/
series.rs

1use crate::Copyright;
2use crate::meta::GameType;
3use crate::request::RequestURL;
4use crate::schedule::{ScheduleGame, ScheduleHydrations};
5use crate::season::SeasonId;
6use crate::sport::SportId;
7use crate::team::TeamId;
8use bon::Builder;
9use itertools::Itertools;
10use serde::de::Error;
11use serde::{Deserialize, Deserializer};
12use std::fmt::{Display, Formatter};
13use std::marker::PhantomData;
14
15#[derive(Debug, Deserialize, PartialEq, Clone)]
16#[serde(rename_all = "camelCase", bound = "H: ScheduleHydrations")]
17pub struct SchedulePostseasonSeriesResponse<H: ScheduleHydrations> {
18	pub copyright: Copyright,
19	pub series: Vec<ScheduleSeries<H>>,
20}
21
22#[derive(Debug, Deserialize, PartialEq, Clone)]
23#[serde(rename_all = "camelCase", bound = "H: ScheduleHydrations")]
24pub struct ScheduleSeries<H: ScheduleHydrations> {
25	pub games: Vec<ScheduleGame<H>>,
26	#[serde(rename = "series")]
27	pub data: SeriesData,
28}
29
30#[derive(Debug, Deserialize, PartialEq, Clone)]
31#[serde(rename_all = "camelCase")]
32pub struct SeriesData {
33	#[serde(rename = "id", deserialize_with = "series_number_from_id")]
34	pub series_number: u32,
35	pub is_default: bool,
36	pub game_type: GameType,
37}
38
39/// # Errors
40/// 1. Cannot deserialize into string
41/// 2. Not in format `{game_type}_{series_number}`
42/// 3. Not a valid `u32`
43pub fn series_number_from_id<'de, D: Deserializer<'de>>(deserializer: D) -> Result<u32, D::Error> {
44	let str = String::deserialize(deserializer)?;
45	let (_game_type, series_number) = str.split_once('_').ok_or_else(|| D::Error::custom("Malformed id, expected format '{game_type}_{series_number}'"))?;
46	let series_number: u32 = series_number.parse().map_err(D::Error::custom)?;
47	Ok(series_number)
48}
49
50#[derive(Builder)]
51#[builder(derive(Into))]
52pub struct SchedulePostseasonSeriesRequest<H: ScheduleHydrations> {
53	#[builder(into)]
54	season: SeasonId,
55	#[builder(into)]
56	sport_id: Option<SportId>,
57	#[builder(into)]
58	team_id: Option<TeamId>,
59	game_types: Option<Vec<GameType>>,
60	series_number: Option<u32>,
61	#[builder(skip)]
62	_marker: PhantomData<H>,
63}
64
65impl<H: ScheduleHydrations, S: schedule_postseason_series_request_builder::State + schedule_postseason_series_request_builder::IsComplete> crate::request::RequestURLBuilderExt for SchedulePostseasonSeriesRequestBuilder<H, S> {
66	type Built = SchedulePostseasonSeriesRequest<H>;
67}
68
69impl<H: ScheduleHydrations> Display for SchedulePostseasonSeriesRequest<H> {
70	fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
71		let hydrations = Some(H::hydration_text(&())).filter(|s| !s.is_empty());
72
73		write!(
74			f,
75			"http://statsapi.mlb.com/api/v1/schedule/postseason/series{params}",
76			params = gen_params! {
77				"season": self.season,
78				"sportId"?: self.sport_id,
79				"teamId"?: self.team_id,
80				"gameTypes"?: self.game_types.as_ref().map(|x| x.iter().map(|x| format!("{x:?}")).join(",")),
81				"seriesNumber"?: self.series_number,
82				"hydrate"?: hydrations,
83			}
84		)
85	}
86}
87
88impl<H: ScheduleHydrations> RequestURL for SchedulePostseasonSeriesRequest<H> {
89	type Response = SchedulePostseasonSeriesResponse<H>;
90}