1pub mod alumni; pub mod coaches; pub mod leaders;
4pub mod personnel; pub mod roster; pub mod stats;
7pub mod uniforms; use crate::endpoints::divisions::NamedDivision;
10use crate::endpoints::league::NamedLeague;
11use crate::endpoints::sports::NamedSport;
12use crate::endpoints::venue::NamedVenue;
13use derive_more::{Deref, DerefMut, Display, From};
14use serde::Deserialize;
15use serde_with::DefaultOnError;
16use serde_with::serde_as;
17use std::ops::{Deref, DerefMut};
18use strum::EnumTryAs;
19
20#[serde_as]
21#[derive(Deserialize)]
22#[serde(rename_all = "camelCase")]
23struct RegularTeamRaw {
24 #[serde(deserialize_with = "crate::types::from_yes_no")]
25 #[serde(default)]
26 all_star_status: bool,
27 active: bool,
28 season: u16,
29 #[serde_as(deserialize_as = "DefaultOnError")]
30 #[serde(default)]
31 venue: NamedVenue,
32 #[serde(flatten)]
33 name: TeamNameRaw,
34 location_name: Option<String>,
35 #[serde(default, deserialize_with = "crate::types::try_from_str")]
36 first_year_of_play: Option<u16>,
37 #[serde_as(deserialize_as = "DefaultOnError")]
38 #[serde(default)]
39 league: NamedLeague,
40 division: Option<NamedDivision>,
41 sport: NamedSport,
42 #[serde(flatten)]
43 parent_organization: Option<Organization>,
44 #[serde(flatten)]
45 inner: NamedTeam,
46}
47
48#[derive(Debug, Deserialize, Deref, DerefMut, PartialEq, Eq, Clone)]
49#[serde(from = "RegularTeamRaw")]
50pub struct RegularTeam {
51 pub all_star_status: bool,
52 pub active: bool,
53 pub season: u16,
54 pub venue: NamedVenue,
55 pub name: TeamName,
56 pub location_name: Option<String>,
57 pub first_year_of_play: u16,
58 pub league: NamedLeague,
59 pub division: Option<NamedDivision>,
60 pub sport: NamedSport,
61 pub parent_organization: Option<Organization>,
62
63 #[deref]
64 #[deref_mut]
65 #[serde(flatten)]
66 inner: NamedTeam,
67}
68
69impl From<RegularTeamRaw> for RegularTeam {
70 fn from(value: RegularTeamRaw) -> Self {
71 let RegularTeamRaw {
72 all_star_status,
73 active,
74 season,
75 venue,
76 name,
77 location_name,
78 first_year_of_play,
79 league,
80 division,
81 sport,
82 parent_organization,
83 inner,
84 } = value;
85
86 RegularTeam {
87 all_star_status,
88 active,
89 season,
90 venue,
91 name: name.initialize(inner.id),
92 location_name,
93 first_year_of_play: first_year_of_play.unwrap_or(season),
94 league,
95 division,
96 sport,
97 parent_organization,
98 inner,
99 }
100 }
101}
102
103#[derive(Debug, Deserialize, Deref, DerefMut, PartialEq, Eq, Clone)]
104#[serde(rename_all = "camelCase")]
105pub struct MLBTeam {
106 pub spring_venue: NamedVenue,
107 pub spring_league: NamedLeague,
108
109 #[deref]
110 #[deref_mut]
111 #[serde(flatten)]
112 pub inner: RegularTeam,
113}
114
115#[derive(Deserialize)]
116struct NamedTeamRaw {
117 #[serde(flatten)]
118 name: TeamNameRaw,
119
120 #[serde(flatten)]
121 inner: IdentifiableTeam,
122}
123
124impl From<NamedTeamRaw> for NamedTeam {
125 fn from(value: NamedTeamRaw) -> Self {
126 let NamedTeamRaw { name, inner } = value;
127 Self { name: name.initialize(inner.id), inner }
128 }
129}
130
131#[derive(Debug, Deserialize, Deref, DerefMut, PartialEq, Eq, Clone)]
132#[serde(from = "NamedTeamRaw")]
133pub struct NamedTeam {
134 pub name: TeamName,
135
136 #[deref]
137 #[deref_mut]
138 inner: IdentifiableTeam,
139}
140
141#[derive(Debug, Deserialize, PartialEq, Eq, Clone)]
142pub struct IdentifiableTeam {
143 pub id: TeamId,
144}
145
146#[derive(Debug, Deserialize, Eq, Clone, From, EnumTryAs)]
147#[serde(untagged)]
148pub enum Team {
149 MLB(MLBTeam),
150 Regular(RegularTeam),
151 Named(NamedTeam),
152 Identifiable(IdentifiableTeam),
153}
154
155impl Team {
156 #[must_use]
157 pub(crate) const fn unknown_team() -> Self {
158 Self::Identifiable(IdentifiableTeam { id: TeamId::new(0) })
159 }
160}
161
162impl PartialEq for Team {
163 fn eq(&self, other: &Self) -> bool {
164 self.id == other.id
165 }
166}
167
168impl Deref for Team {
169 type Target = IdentifiableTeam;
170
171 fn deref(&self) -> &Self::Target {
172 match self {
173 Self::MLB(inner) => inner,
174 Self::Regular(inner) => inner,
175 Self::Named(inner) => inner,
176 Self::Identifiable(inner) => inner,
177 }
178 }
179}
180
181impl DerefMut for Team {
182 fn deref_mut(&mut self) -> &mut Self::Target {
183 match self {
184 Self::MLB(inner) => inner,
185 Self::Regular(inner) => inner,
186 Self::Named(inner) => inner,
187 Self::Identifiable(inner) => inner,
188 }
189 }
190}
191
192#[derive(Deserialize)]
193#[serde(rename_all = "camelCase")]
194struct TeamNameRaw {
195 pub name: String,
196 pub team_code: Option<String>,
197 pub file_code: Option<String>,
198 pub abbreviation: Option<String>,
199 pub team_name: Option<String>,
200 pub short_name: Option<String>,
201 pub franchise_name: Option<String>,
202 pub club_name: Option<String>,
203}
204
205#[derive(Debug, Eq, Clone, From)]
206pub enum TeamName {
207 Hydrated(HydratedTeamName),
208 Unhydrated(UnhydratedTeamName),
209}
210
211impl PartialEq for TeamName {
212 fn eq(&self, other: &Self) -> bool {
213 self.name == other.name
214 }
215}
216
217impl Deref for TeamName {
218 type Target = UnhydratedTeamName;
219
220 fn deref(&self) -> &Self::Target {
221 match self {
222 Self::Hydrated(inner) => inner,
223 Self::Unhydrated(inner) => inner,
224 }
225 }
226}
227
228impl DerefMut for TeamName {
229 fn deref_mut(&mut self) -> &mut Self::Target {
230 match self {
231 Self::Hydrated(inner) => inner,
232 Self::Unhydrated(inner) => inner,
233 }
234 }
235}
236
237#[derive(Debug, Deref, DerefMut, PartialEq, Eq, Clone)]
238pub struct UnhydratedTeamName {
239 pub name: String,
240}
241
242#[derive(Debug, Deref, DerefMut, PartialEq, Eq, Clone)]
243pub struct HydratedTeamName {
244 #[deref]
245 #[deref_mut]
246 inner: UnhydratedTeamName,
247
248 pub team_code: String,
249 pub file_code: String,
250 pub abbreviation: String,
251 pub team_name: String,
252 pub short_name: String,
253 pub franchise_name: String,
254 pub club_name: String,
255}
256
257impl TeamNameRaw {
258 fn initialize(self, id: TeamId) -> TeamName {
259 let Self {
260 name,
261 team_code,
262 file_code,
263 abbreviation,
264 team_name,
265 short_name,
266 franchise_name,
267 club_name,
268 } = self;
269
270 let inner = UnhydratedTeamName { name };
271 if let Some(team_code) = team_code
272 && let Some(abbreviation) = abbreviation
273 && let Some(team_name) = team_name
274 && let Some(short_name) = short_name
275 {
276 TeamName::Hydrated(HydratedTeamName {
277 file_code: file_code.unwrap_or_else(|| format!("t{id}")),
278 franchise_name: franchise_name.unwrap_or_else(|| short_name.clone()),
279 club_name: club_name.unwrap_or_else(|| team_name.clone()),
280 team_code,
281 abbreviation,
282 team_name,
283 short_name,
284 inner,
285 })
286 } else {
287 TeamName::Unhydrated(inner)
288 }
289 }
290}
291
292#[repr(transparent)]
293#[derive(Debug, Deserialize, Deref, Display, PartialEq, Eq, Copy, Clone, Hash)]
294pub struct TeamId(u32);
295
296impl TeamId {
297 #[must_use]
298 pub const fn new(id: u32) -> Self {
299 Self(id)
300 }
301}
302
303#[derive(Debug, Deserialize, PartialEq, Eq, Clone)]
304#[serde(rename_all = "camelCase")]
305pub struct NamedOrganization {
306 #[serde(rename = "parentOrgName")]
307 pub name: String,
308 #[serde(rename = "parentOrgId")]
309 pub id: OrganizationId,
310}
311
312#[repr(transparent)]
313#[derive(Debug, Deserialize, Deref, Display, PartialEq, Eq, Copy, Clone, Hash)]
314pub struct OrganizationId(u16);
315
316#[derive(Debug, Deserialize, Eq, Clone, From, EnumTryAs)]
317#[serde(untagged)]
318pub enum Organization {
319 NamedOrganization(NamedOrganization),
320}
321
322impl PartialEq for Organization {
323 fn eq(&self, other: &Self) -> bool {
324 self.id == other.id
325 }
326}
327
328impl Deref for Organization {
329 type Target = NamedOrganization;
330
331 fn deref(&self) -> &Self::Target {
332 match self {
333 Self::NamedOrganization(inner) => inner,
334 }
335 }
336}
337
338impl DerefMut for Organization {
339 fn deref_mut(&mut self) -> &mut Self::Target {
340 match self {
341 Organization::NamedOrganization(inner) => inner,
342 }
343 }
344}