Skip to main content

mlb_api/requests/team/
roster.rs

1use crate::person::NamedPerson;
2use crate::season::SeasonId;
3use crate::team::TeamId;
4use crate::types::{Copyright, MLB_API_DATE_FORMAT};
5use bon::Builder;
6use chrono::NaiveDate;
7use serde::Deserialize;
8use std::fmt::{Display, Formatter};
9use crate::positions::NamedPosition;
10use crate::request::RequestURL;
11use crate::roster_types::RosterType;
12use crate::team::NamedTeam;
13
14#[derive(Debug, Deserialize, PartialEq, Eq, Clone)]
15#[serde(rename_all = "camelCase")]
16pub struct RosterResponse {
17    pub copyright: Copyright,
18    #[serde(default)]
19    pub roster: Vec<RosterPlayer>,
20    pub team_id: TeamId,
21    pub roster_type: RosterType,
22}
23
24#[derive(Debug, Deserialize, PartialEq, Eq, Clone)]
25#[serde(rename_all = "camelCase")]
26pub struct RosterPlayer {
27    pub person: NamedPerson,
28    #[serde(deserialize_with = "crate::types::try_from_str")]
29    pub jersey_number: Option<u8>,
30    pub position: NamedPosition,
31    pub status: RosterStatus,
32    pub parent_team_id: Option<TeamId>,
33}
34
35#[derive(Debug, Deserialize, PartialEq, Eq, Copy, Clone)]
36#[serde(try_from = "__RosterStatusStruct")]
37pub enum RosterStatus {
38    Active,
39    Claimed,
40    ReassignedToMinors,
41    Released,
42    MinorLeagueContract,
43    InjuryLeave7Day,
44    InjuryLeave10Day,
45    InjuryLeave15Day,
46    InjuryLeave60Day,
47    Traded,
48    DesignatedForAssignment,
49    FreeAgent,
50    RestrictedList,
51    AssignedToNewTeam,
52    RehabAssignment,
53    NonRosterInvitee,
54    Waived,
55    Deceased,
56    VoluntarilyRetired,
57}
58
59#[derive(Deserialize)]
60#[doc(hidden)]
61struct __RosterStatusStruct {
62    code: String,
63    description: String,
64}
65
66impl TryFrom<__RosterStatusStruct> for RosterStatus {
67    type Error = String;
68
69    fn try_from(value: __RosterStatusStruct) -> Result<Self, Self::Error> {
70        Ok(match &*value.code {
71            "A" => Self::Active,
72            "CL" => Self::Claimed,
73            "RM" => Self::ReassignedToMinors,
74            "RL" => Self::Released,
75            "MIN" => Self::MinorLeagueContract,
76            "D7" => Self::InjuryLeave7Day,
77            "D10" => Self::InjuryLeave10Day,
78            "D15" => Self::InjuryLeave15Day,
79            "D60" => Self::InjuryLeave60Day,
80            "TR" => Self::Traded,
81            "DES" => Self::DesignatedForAssignment,
82            "FA" => Self::FreeAgent,
83            "RST" => Self::RestrictedList,
84            "ASG" => Self::AssignedToNewTeam,
85            "RA" => Self::RehabAssignment,
86            "NRI" => Self::NonRosterInvitee,
87            "WA" => Self::Waived,
88            "DEC" => Self::Deceased,
89            "RET" => Self::VoluntarilyRetired,
90            code => return Err(format!("Invalid code '{code}' (desc: {})", value.description)),
91        })
92    }
93}
94
95#[derive(Builder)]
96#[builder(derive(Into))]
97pub struct RosterRequest {
98    #[builder(into)]
99    team_id: TeamId,
100    #[builder(into)]
101    season: Option<SeasonId>,
102    date: Option<NaiveDate>,
103    #[builder(into)]
104    roster_type: RosterType,
105}
106
107impl<S: roster_request_builder::State + roster_request_builder::IsComplete> crate::request::RequestURLBuilderExt for RosterRequestBuilder<S> {
108    type Built = RosterRequest;
109}
110
111impl Display for RosterRequest {
112    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
113        write!(f, "http://statsapi.mlb.com/api/v1/teams/{}/roster{}", self.team_id, gen_params! { "season"?: self.season, "date"?: self.date.as_ref().map(|date| date.format(MLB_API_DATE_FORMAT)), "rosterType": &self.roster_type })
114    }
115}
116
117impl RequestURL for RosterRequest {
118    type Response = RosterResponse;
119}
120
121#[derive(Debug, Deserialize, PartialEq, Eq, Clone)]
122#[serde(rename_all = "camelCase")]
123pub struct RosterEntry {
124    pub position: NamedPosition,
125    pub status: RosterStatus,
126    pub team: NamedTeam,
127    pub is_active: bool,
128    pub is_active_forty_man: bool,
129    pub start_date: NaiveDate,
130    pub end_date: Option<NaiveDate>,
131    pub status_date: NaiveDate,
132}
133
134#[cfg(test)]
135mod tests {
136	use crate::meta::MetaRequest;
137    use crate::request::{RequestURL, RequestURLBuilderExt};
138    use crate::roster_types::RosterType;
139    use crate::team::roster::RosterRequest;
140	use crate::team::teams::TeamsRequest;
141    use crate::TEST_YEAR;
142
143    #[tokio::test]
144    #[cfg_attr(not(feature = "_heavy_tests"), ignore)]
145    async fn test_this_year_all_mlb_teams_all_roster_types() {
146        let season = TEST_YEAR;
147        let teams = TeamsRequest::mlb_teams().season(season).build_and_get().await.unwrap().teams;
148        let roster_types = MetaRequest::<RosterType>::new().get().await.unwrap().entries;
149        for team in teams {
150            for roster_type in &roster_types {
151                let _ = RosterRequest::builder().team_id(team.id).season(season).roster_type(*roster_type).build_and_get().await.unwrap();
152            }
153        }
154    }
155}
156