1pub mod ability;
2pub mod ancient_trait;
3pub mod attack;
4pub mod cardmarket;
5pub mod image;
6pub mod legality;
7pub mod resistance;
8pub mod tcgplayer;
9pub mod weakness;
10
11use std::str::FromStr;
12
13use crate::{
14 client::{ApiResult, Client},
15 errors::ClientError,
16 set::Set,
17};
18use serde::{Deserialize, Serialize};
19
20use self::{
21 ability::Ability, ancient_trait::AncientTrait, attack::Attack, cardmarket::CardMarket,
22 image::Image, legality::Legality, resistance::Resistance, tcgplayer::TcgPlayer,
23 weakness::Weakness,
24};
25
26#[derive(Debug, Clone, Serialize, Deserialize)]
29#[cfg_attr(test, derive(Default))]
30pub struct Card {
31 pub id: String,
33 pub name: String,
35 pub supertype: String,
37 pub subtypes: Option<Vec<String>>,
39 pub level: Option<String>,
41 pub hp: Option<String>,
43 pub types: Option<Vec<String>>,
45 #[serde(alias = "evolvesFrom")]
47 pub evolves_from: Option<String>,
48 #[serde(alias = "evolvesTo")]
50 pub evolves_to: Option<Vec<String>>,
51 pub rules: Option<Vec<String>>,
53 #[serde(alias = "ancientTrait")]
55 pub ancient_trait: Option<AncientTrait>,
56 pub abilities: Option<Vec<Ability>>,
58 pub attacks: Option<Vec<Attack>>,
60 pub weaknesses: Option<Vec<Weakness>>,
62 pub resistances: Option<Vec<Resistance>>,
64 #[serde(alias = "retreatCost")]
66 pub retreat_cost: Option<Vec<String>>,
67 #[serde(alias = "convertedRetreatCost")]
69 pub converted_retreat_cost: Option<usize>,
70 pub set: Set,
72 pub number: Option<String>,
74 pub artist: Option<String>,
76 pub rarity: Option<String>,
78 #[serde(alias = "flavorText")]
80 pub flavor_text: Option<String>,
81 #[serde(alias = "nationalPokedexNumbers")]
83 pub national_pokedex_numbers: Option<Vec<usize>>,
84 pub legalities: Option<Legality>,
86 #[serde(alias = "regulationMark")]
88 pub regulation_mark: Option<String>,
89 pub images: Option<Image>,
91 pub tcgplayer: Option<TcgPlayer>,
93 pub cardmarket: Option<CardMarket>,
95}
96
97pub struct GetCardRequest {
98 pub id: String,
99}
100
101impl GetCardRequest {
102 pub fn new(id: &str) -> Self {
103 GetCardRequest { id: id.into() }
104 }
105}
106
107pub struct SearchCardsRequest {
108 pub query: Option<String>,
110 pub page: Option<u16>,
112 pub page_size: Option<u8>,
114 pub order_by: Option<String>,
116}
117
118impl SearchCardsRequest {
119 pub fn new(query: &str) -> Self {
120 SearchCardsRequest {
121 query: Some(String::from_str(query).unwrap()),
122 page: None,
123 page_size: None,
124 order_by: None,
125 }
126 }
127}
128
129impl Client {
130 pub async fn get_card(&self, request: GetCardRequest) -> Result<Card, ClientError> {
134 let card = self
135 .http_client
136 .get(format!("{}/cards/{}", self.base_url, request.id))
137 .send()
138 .await?
139 .json::<ApiResult<Card>>()
140 .await?;
141
142 Client::parse_response(card)
143 }
144
145 pub async fn search_cards(
149 &self,
150 request: SearchCardsRequest,
151 ) -> Result<Vec<Card>, ClientError> {
152 let cards = self
153 .http_client
154 .get(format!("{}/cards", self.base_url))
155 .query(&[
156 ("q", request.query),
157 ("page", request.page.map(|p| p.to_string())),
158 ("pageSize", request.page_size.map(|p| p.to_string())),
159 ("orderBy", request.order_by),
160 ])
161 .send()
162 .await?
163 .json::<ApiResult<Vec<Card>>>()
164 .await?;
165
166 Client::parse_response(cards)
167 }
168
169 pub async fn get_all_cards(&self) -> Result<Vec<Card>, ClientError> {
171 let mut page = 1;
172 let page_size = 250;
173 let mut total_pages: usize = 0;
174 let mut cards: Vec<Card> = vec![];
175
176 loop {
177 let resp = self
178 .http_client
179 .get(format!("{}/cards", self.base_url))
180 .query(&[("page", page)])
181 .send()
182 .await?
183 .json::<ApiResult<Vec<Card>>>()
184 .await?;
185
186 let total_count = if let ApiResult::Ok(ev) = &resp {
187 ev.total_count
188 } else {
189 None
190 };
191
192 match Client::parse_response(resp) {
193 Ok(mut cv) => {
194 cards.append(&mut cv);
195 if let Some(tc) = total_count {
196 total_pages = ((tc / page_size) as f64).ceil() as usize;
197 }
198
199 if page > total_pages {
200 break;
201 }
202
203 page += 1;
204 }
205 Err(e) => {
206 return Err(e);
207 }
208 };
209 }
210
211 Ok(cards)
212 }
213}