Skip to main content

mlb_api/requests/team/
uniforms.rs

1//! Returns a list of uniform assets. No image sadly, just item names.
2
3use crate::cache::{Requestable, RequestableEntrypoint};
4use crate::season::SeasonId;
5use crate::team::TeamId;
6use crate::Copyright;
7use crate::request::RequestURL;
8use bon::Builder;
9use itertools::Itertools;
10use serde::Deserialize;
11use std::fmt::{Display, Formatter};
12
13#[cfg(feature = "cache")]
14use crate::{rwlock_const_new, RwLock, cache::CacheTable};
15
16/// A [`Vec`] of [`TeamUniformAssets`]s
17///
18/// Split by Team
19#[derive(Debug, Deserialize, PartialEq, Clone)]
20pub struct UniformsResponse {
21    pub copyright: Copyright,
22    #[serde(rename = "uniforms")] pub teams: Vec<TeamUniformAssets>,
23}
24
25id!(UniformAssetId { uniformAssetId: u32 });
26id!(UniformAssetCategoryId { uniformAssetTypeId: u32 });
27
28/// A [`Vec`] of a team's [`UniformAsset`]s
29#[derive(Debug, Deserialize, PartialEq, Clone)]
30#[serde(rename_all = "camelCase")]
31pub struct TeamUniformAssets {
32    pub team_id: TeamId,
33    pub uniform_assets: Vec<UniformAsset>,
34}
35
36/// A uniform asset, like a Blue Jays Canada Day Hat.
37#[derive(Debug, Deserialize, Clone)]
38pub struct UniformAsset {
39    #[serde(rename = "uniformAssetText")] pub name: String,
40    #[serde(rename = "uniformAssetType")] pub category: UniformAssetCategory,
41    #[serde(rename = "uniformAssetCode")] pub code: String,
42    #[serde(flatten)]
43    pub id: UniformAssetId,
44}
45
46/// Category; Hat, Shirt, etc.
47#[derive(Debug, Deserialize, Clone)]
48pub struct UniformAssetCategory {
49    #[serde(rename = "uniformAssetTypeText")] pub name: String,
50    #[serde(rename = "uniformAssetTypeCode")] pub code: String,
51    #[serde(rename = "uniformAssetTypeDesc")] pub description: String,
52    #[serde(rename = "uniformAssetTypeId")] pub id: UniformAssetCategoryId,
53}
54
55id_only_eq_impl!(UniformAsset, id);
56id_only_eq_impl!(UniformAssetCategory, id);
57
58/// Returns a [`UniformsResponse`]
59#[derive(Builder)]
60#[builder(derive(Into))]
61pub struct UniformsRequest {
62    teams: Vec<TeamId>,
63    #[builder(into)]
64    season: Option<SeasonId>,
65}
66
67impl<S: uniforms_request_builder::State + uniforms_request_builder::IsComplete> crate::request::RequestURLBuilderExt for UniformsRequestBuilder<S> {
68    type Built = UniformsRequest;
69}
70
71impl Display for UniformsRequest {
72    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
73        write!(f, "http://statsapi.mlb.com/api/v1/uniforms/team{}", gen_params! { "teamIds": self.teams.iter().copied().join(","), "season"?: self.season })
74    }
75}
76
77impl RequestURL for UniformsRequest {
78    type Response = UniformsResponse;
79}
80
81#[cfg(feature = "cache")]
82static CACHE: RwLock<CacheTable<UniformAsset>> = rwlock_const_new(CacheTable::new());
83
84impl Requestable for UniformAsset {
85    type Identifier = String;
86    type URL = UniformsRequest;
87
88    fn id(&self) -> &Self::Identifier {
89        &self.code
90    }
91
92    fn url_for_id(id: &Self::Identifier) -> Self::URL {
93        UniformsRequest::builder()
94            .teams(vec![TeamId::new(id.split_once('_').and_then(|(num, _)| num.parse().ok()).unwrap_or(0))])
95            .build()
96    }
97
98    fn get_entries(response: <Self::URL as RequestURL>::Response) -> impl IntoIterator<Item=Self>
99    where
100        Self: Sized
101    {
102        response.teams.into_iter().flat_map(|team| team.uniform_assets)
103    }
104
105    #[cfg(feature = "cache")]
106    fn get_cache_table() -> &'static RwLock<CacheTable<Self>>
107    where
108        Self: Sized
109    {
110        &CACHE
111    }
112}
113
114impl RequestableEntrypoint for UniformAsset {
115    type Complete = Self;
116
117    fn id(&self) -> &<<Self as RequestableEntrypoint>::Complete as Requestable>::Identifier {
118        &self.code
119    }
120}
121
122#[cfg(test)]
123mod tests {
124    use crate::team::uniforms::UniformsRequest;
125    use crate::team::TeamsRequest;
126    use crate::request::RequestURLBuilderExt;
127
128    #[tokio::test]
129    async fn parse_all_mlb_teams_this_season() {
130        let mlb_teams = TeamsRequest::mlb_teams().build_and_get().await.unwrap();
131        let team_ids = mlb_teams.teams.into_iter().map(|team| team.id).collect::<Vec<_>>();
132        let _ = UniformsRequest::builder().teams(team_ids).build_and_get().await.unwrap();
133    }
134}