mlb_api/endpoints/awards/
mod.rs1use crate::endpoints::StatsAPIUrl;
2use crate::endpoints::league::{League, LeagueId};
3use crate::endpoints::sports::{Sport, SportId};
4use crate::{gen_params, rwlock_const_new, RwLock};
5use crate::types::Copyright;
6use derive_more::{Deref, DerefMut, Display, From};
7use serde::Deserialize;
8use std::fmt::{Display, Formatter};
9use std::ops::Deref;
10use strum::EnumTryAs;
11use crate::cache::{HydratedCacheTable, EndpointEntryCache};
12
13#[derive(Debug, Deserialize, PartialEq, Eq, Clone)]
14pub struct AwardsResponse {
15 pub copyright: Copyright,
16 pub awards: Vec<Award>,
17}
18
19#[derive(Debug, Deserialize, Deref, DerefMut, PartialEq, Eq, Clone)]
20pub struct HydratedAward {
21 pub name: String,
22 pub description: Option<String>,
23 pub sport: Option<Sport>,
24 pub league: Option<League>,
25 pub notes: Option<String>,
26
27 #[deref]
28 #[deref_mut]
29 #[serde(flatten)]
30 inner: IdentifiableAward,
31}
32
33#[derive(Debug, Deserialize, PartialEq, Eq, Clone)]
34pub struct IdentifiableAward {
35 pub id: AwardId,
36}
37
38#[repr(transparent)]
39#[derive(Debug, Deserialize, Deref, Display, PartialEq, Eq, Clone, Hash)]
40pub struct AwardId(String);
41
42#[derive(Debug, Deserialize, Eq, Clone, From, EnumTryAs)]
43#[serde(untagged)]
44pub enum Award {
45 Hydrated(HydratedAward),
46 Identifiable(IdentifiableAward),
47}
48
49impl PartialEq for Award {
50 fn eq(&self, other: &Self) -> bool {
51 self.id == other.id
52 }
53}
54
55impl Deref for Award {
56 type Target = IdentifiableAward;
57
58 fn deref(&self) -> &Self::Target {
59 match self {
60 Self::Hydrated(inner) => inner,
61 Self::Identifiable(inner) => inner,
62 }
63 }
64}
65
66#[derive(Default)]
67pub struct AwardEndpointUrl {
68 pub award_id: Option<AwardId>,
69 pub sport_id: Option<SportId>,
70 pub league_id: Option<LeagueId>,
71 pub season: Option<u16>,
72}
73
74impl Display for AwardEndpointUrl {
75 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
76 write!(
77 f,
78 "http://statsapi.mlb.com/api/v1/awards{}",
79 gen_params! { "awardId"?: self.award_id.as_ref(), "sportId"?: self.sport_id, "leagueId"?: self.league_id, "season"?: self.season }
80 )
81 }
82}
83
84impl StatsAPIUrl for AwardEndpointUrl {
85 type Response = AwardsResponse;
86}
87
88static CACHE: RwLock<HydratedCacheTable<Award>> = rwlock_const_new(HydratedCacheTable::new());
89
90impl EndpointEntryCache for Award {
91 type HydratedVariant = HydratedAward;
92 type Identifier = AwardId;
93 type URL = AwardEndpointUrl;
94
95 fn into_hydrated_variant(self) -> Option<Self::HydratedVariant> {
96 self.try_as_hydrated()
97 }
98
99 fn id(&self) -> &Self::Identifier {
100 &self.id
101 }
102
103 fn url_for_id(id: &Self::Identifier) -> Self::URL {
104 AwardEndpointUrl {
105 award_id: Some(id.clone()),
106 sport_id: None,
107 league_id: None,
108 season: None,
109 }
110 }
111
112 fn get_entries(response: <Self::URL as StatsAPIUrl>::Response) -> impl IntoIterator<Item=Self>
113 where
114 Self: Sized
115 {
116 response.awards
117 }
118
119 fn get_hydrated_cache_table() -> &'static RwLock<HydratedCacheTable<Self>>
120 where
121 Self: Sized
122 {
123 &CACHE
124 }
125}
126
127#[cfg(test)]
128mod tests {
129 use crate::endpoints::StatsAPIUrl;
130 use crate::endpoints::awards::AwardEndpointUrl;
131
132 #[tokio::test]
133 async fn parse_this_season() {
134 let _response = AwardEndpointUrl::default().get().await.unwrap();
135 }
136}