mlb_api/endpoints/teams/team/leaders/
mod.rs1use crate::endpoints::league::League;
2use crate::endpoints::person::Person;
3use crate::endpoints::sports::Sport;
4use crate::endpoints::teams::team::{Team, TeamId};
5use crate::endpoints::{BaseballStat, BaseballStatId, GameType, IdentifiableBaseballStat, StatGroup, StatsAPIUrl};
6use crate::gen_params;
7use crate::types::{Copyright, IntegerOrFloat, PlayerPool};
8use itertools::Itertools;
9use serde::Deserialize;
10use serde_with::DisplayFromStr;
11use serde_with::serde_as;
12use std::fmt::{Display, Formatter};
13use std::str::FromStr;
14
15#[derive(Debug, Deserialize, PartialEq, Eq, Clone)]
16#[serde(rename_all = "camelCase")]
17pub struct TeamStatLeadersResponse {
18 pub copyright: Copyright,
19 pub team_leaders: Vec<TeamStatLeaders>,
20}
21
22#[derive(Debug, Deserialize, PartialEq, Eq, Clone)]
23#[serde(try_from = "__TeamStatLeadersStruct")]
24pub struct TeamStatLeaders {
25 pub category: BaseballStat,
26 pub season: u16,
27 pub game_type: GameType,
28 pub leaders: Vec<TeamStatLeader>,
29 pub stat_group: StatGroup,
30 pub total_splits: u32,
31}
32
33#[serde_as]
34#[derive(Deserialize)]
35#[serde(rename_all = "camelCase")]
36struct __TeamStatLeadersStruct {
37 leader_category: String,
38 #[serde_as(as = "DisplayFromStr")]
39 season: u16,
40 game_type: GameType,
41 leaders: Vec<TeamStatLeader>,
42 stat_group: String,
43 total_splits: u32,
44}
45
46impl TryFrom<__TeamStatLeadersStruct> for TeamStatLeaders {
47 type Error = <StatGroup as FromStr>::Err;
48
49 fn try_from(value: __TeamStatLeadersStruct) -> Result<Self, Self::Error> {
50 Ok(TeamStatLeaders {
51 category: BaseballStat::Identifiable(IdentifiableBaseballStat {
52 id: BaseballStatId::new(value.leader_category),
53 }),
54 season: value.season,
55 game_type: value.game_type,
56 leaders: value.leaders,
57 stat_group: StatGroup::from_str(&value.stat_group)?,
58 total_splits: value.total_splits,
59 })
60 }
61}
62
63#[serde_as]
64#[derive(Debug, Deserialize, PartialEq, Eq, Clone)]
65#[serde(rename_all = "camelCase")]
66pub struct TeamStatLeader {
67 pub rank: u32,
68 pub value: IntegerOrFloat,
69 pub team: Team,
70 pub league: League,
71 pub person: Person,
72 pub sport: Sport,
73 #[serde_as(as = "DisplayFromStr")]
74 pub season: u16,
75}
76
77pub struct TeamStatLeadersEndpointUrl {
79 pub team_id: TeamId,
80 pub stats: Vec<BaseballStat>,
81 pub season: Option<u16>,
82 pub pool: PlayerPool,
83
84 pub game_types: Option<Vec<GameType>>,
86}
87
88impl Display for TeamStatLeadersEndpointUrl {
89 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
90 write!(
91 f,
92 "http://statsapi.mlb.com/api/v1/teams/{}/leaders{params}",
93 self.team_id,
94 params = gen_params! {
95 "leaderCategories": self.stats.iter().map(|stat| &stat.id).join(","),
96 "season"?: self.season,
97 "pool": self.pool,
98 "game_types"?: self.game_types.as_ref().map(|x| x.iter().join(",")),
99 }
100 )
101 }
102}
103
104impl StatsAPIUrl for TeamStatLeadersEndpointUrl {
105 type Response = TeamStatLeadersResponse;
106}
107
108#[cfg(test)]
109mod tests {
110 use crate::endpoints::{BaseballStat, StatsAPIUrl};
111 use crate::endpoints::meta::MetaEndpointUrl;
112 use crate::endpoints::sports::SportId;
113 use crate::endpoints::teams::TeamsEndpointUrl;
114 use crate::endpoints::teams::team::leaders::TeamStatLeadersEndpointUrl;
115
116 #[tokio::test]
117 async fn test_all_mlb_teams_all_stats() {
118 let all_categories = MetaEndpointUrl::<BaseballStat>::new().get().await.unwrap().entries;
119
120 for team in (TeamsEndpointUrl { sport_id: Some(SportId::MLB), season: None }).get().await.unwrap().teams {
121 let _all_stats = TeamStatLeadersEndpointUrl {
122 team_id: team.id,
123 stats: all_categories.clone(),
124 season: None,
125 pool: Default::default(),
126 game_types: None,
127 }
128 .get()
129 .await
130 .unwrap();
131 }
132 }
133}