1use super::util::{self, Flag};
4use chrono::NaiveDate;
5use lazy_static::lazy_static;
6use serde::{Deserialize, Serialize};
7use serde_json;
8use url::Url;
9
10#[cfg(feature = "log")]
11use log::warn;
12
13lazy_static! {
14 pub static ref ENDPOINT: url::Url = Url::parse("https://brickset.com/api/v3.asmx/").unwrap();
15}
16
17#[derive(Debug)]
18pub enum Error {
19 UrlParseError(url::ParseError),
20 SerdeJson(serde_json::Error),
21 Message(String),
22 #[cfg(feature = "reqwest")]
23 Reqwest(reqwest::Error),
24}
25
26#[derive(Debug, Clone)]
27pub struct CheckKey<'s> {
28 api_key: &'s str,
29}
30
31#[derive(Debug, Clone)]
32pub struct Login<'s> {
33 api_key: &'s str,
34 username: &'s str,
35 password: &'s str,
36}
37
38#[derive(Debug, Clone)]
39pub struct CheckUserHash<'s> {
40 api_key: &'s str,
41 user_hash: &'s str,
42}
43
44#[derive(Debug, Clone)]
45pub struct GetKeyUsageStats<'s> {
46 api_key: &'s str,
47}
48
49#[derive(Debug, Clone)]
50pub struct GetSets<'s> {
51 api_key: &'s str,
52 user_hash: Option<&'s str>,
53 params: GetSetsParameters<'s>,
54}
55
56#[derive(Debug, Clone)]
57pub struct GetAdditionalImages<'s> {
58 api_key: &'s str,
59 set_id: u64,
60}
61
62#[derive(Debug, Clone)]
63pub struct GetInstructions<'s> {
64 api_key: &'s str,
65 set_id: u64,
66}
67
68#[derive(Debug, Clone)]
69pub struct GetInstructions2<'s> {
70 api_key: &'s str,
71 set_number: &'s str,
72}
73
74#[derive(Debug, Clone)]
75pub struct GetReviews<'s> {
76 api_key: &'s str,
77 set_id: u64,
78}
79
80#[derive(Debug, Clone)]
81pub struct GetThemes<'s> {
82 api_key: &'s str,
83}
84
85#[derive(Debug, Clone)]
86pub struct GetSubthemes<'s> {
87 api_key: &'s str,
88 theme: &'s str,
89}
90
91#[derive(Debug, Clone)]
92pub struct GetYears<'s> {
93 api_key: &'s str,
94 theme: &'s str,
95}
96
97#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
98pub enum OrderBy {
99 Number,
100 YearFrom,
101 Pieces,
102 Minifigs,
103 Rating,
104 USRetailPrice,
105 UKRetailPrice,
106 CARetailPrice,
107 DERetailPrice,
108 FRRetailPrice,
109 USPricePerPiece,
110 UKPricePerPiece,
111 CAPricePerPiece,
112 DEPricePerPiece,
113 FRPricePerPiece,
114 Theme,
115 Subtheme,
116 Name,
117 Random,
118 QtyOwned,
119 OwnCount,
120 WantCount,
121 UserRating,
122 CollectionID,
123 NumberDESC,
124 YearFromDESC,
125 PiecesDESC,
126 MinifigsDESC,
127 RatingDESC,
128 USRetailPriceDESC,
129 UKRetailPriceDESC,
130 CARetailPriceDESC,
131 DERetailPriceDESC,
132 FRRetailPriceDESC,
133 USPricePerPieceDESC,
134 UKPricePerPieceDESC,
135 CAPricePerPieceDESC,
136 DEPricePerPieceDESC,
137 FRPricePerPieceDESC,
138 ThemeDESC,
139 SubthemeDESC,
140 NameDESC,
141 RandomDESC,
142 QtyOwnedDESC,
143 OwnCountDESC,
144 WantCountDESC,
145 UserRatingDESC,
146 CollectionIDDESC,
147}
148
149#[derive(Serialize, Deserialize, Default, Debug, Clone)]
150#[serde(rename_all = "camelCase")]
151pub struct GetSetsParameters<'s> {
152 #[serde(skip_serializing_if = "Option::is_none")]
153 #[serde(default)]
154 set_id: Option<u64>,
155 #[serde(skip_serializing_if = "Option::is_none")]
156 #[serde(default)]
157 query: Option<&'s str>,
158 #[serde(skip_serializing_if = "Option::is_none")]
159 #[serde(default)]
160 theme: Option<&'s str>,
161 #[serde(skip_serializing_if = "Option::is_none")]
162 #[serde(default)]
163 subtheme: Option<&'s str>,
164 #[serde(skip_serializing_if = "Option::is_none")]
165 #[serde(default)]
166 #[serde(rename = "setNumber")]
167 full_set_number: Option<&'s str>,
168 #[serde(skip_serializing_if = "Vec::is_empty")]
169 #[serde(with = "util::int_vec_as_commastr")]
170 year: Vec<i32>,
171 #[serde(skip_serializing_if = "Option::is_none")]
172 #[serde(default)]
173 tag: Option<&'s str>,
174 #[serde(skip_serializing_if = "Option::is_none")]
175 #[serde(default)]
176 owned: Option<Flag>,
177 #[serde(skip_serializing_if = "Option::is_none")]
178 #[serde(default)]
179 wanted: Option<Flag>,
180 #[serde(skip_serializing_if = "Option::is_none")]
181 #[serde(with = "util::updated_since_format")]
182 #[serde(default)]
183 updated_since: Option<NaiveDate>,
184 #[serde(skip_serializing_if = "Option::is_none")]
185 #[serde(default)]
186 order_by: Option<OrderBy>,
187 #[serde(skip_serializing_if = "Option::is_none")]
188 #[serde(default)]
189 page_size: Option<usize>,
190 #[serde(skip_serializing_if = "Option::is_none")]
191 #[serde(default)]
192 page_number: Option<usize>,
193 #[serde(skip_serializing_if = "Option::is_none")]
194 #[serde(default)]
195 extended_data: Option<Flag>,
196}
197
198#[derive(Debug, Clone)]
199pub struct SetCollection<'s> {
200 api_key: &'s str,
201 user_hash: &'s str,
202 set_id: u64,
203 params: SetCollectionParameters<'s>,
204}
205
206#[derive(Serialize, Deserialize, Default, Debug, Clone)]
207#[serde(rename_all = "camelCase")]
208pub struct SetCollectionParameters<'s> {
209 #[serde(skip_serializing_if = "Option::is_none")]
210 own: Option<usize>,
211 #[serde(skip_serializing_if = "Option::is_none")]
212 want: Option<usize>,
213 #[serde(skip_serializing_if = "Option::is_none")]
214 qty_owned: Option<usize>,
215 #[serde(skip_serializing_if = "Option::is_none")]
216 notes: Option<&'s str>,
217 #[serde(skip_serializing_if = "Option::is_none")]
218 rating: Option<i32>,
219}
220
221#[derive(Debug, Clone)]
222pub struct GetUserNotes<'s> {
223 api_key: &'s str,
224 user_hash: &'s str,
225}
226
227#[derive(Debug, Clone)]
228pub struct GetMinifigCollection<'s> {
229 api_key: &'s str,
230 user_hash: &'s str,
231 params: GetMinifigCollectionParameters<'s>,
232}
233
234#[derive(Serialize, Deserialize, Default, Debug, Clone)]
235#[serde(rename_all = "camelCase")]
236pub struct GetMinifigCollectionParameters<'s> {
237 #[serde(skip_serializing_if = "Option::is_none")]
238 owned: Option<Flag>,
239 #[serde(skip_serializing_if = "Option::is_none")]
240 wanted: Option<Flag>,
241 #[serde(skip_serializing_if = "Option::is_none")]
242 query: Option<&'s str>,
243}
244
245#[derive(Debug, Clone)]
246pub struct SetMinifigCollection<'s> {
247 api_key: &'s str,
248 user_hash: &'s str,
249 minifig_number: &'s str,
250 params: SetMinifigCollectionParameters<'s>,
251}
252
253#[derive(Serialize, Deserialize, Default, Debug, Clone)]
254#[serde(rename_all = "camelCase")]
255pub struct SetMinifigCollectionParameters<'s> {
256 #[serde(skip_serializing_if = "Option::is_none")]
257 own: Option<usize>,
258 #[serde(skip_serializing_if = "Option::is_none")]
259 want: Option<usize>,
260 #[serde(skip_serializing_if = "Option::is_none")]
261 qty_owned: Option<usize>,
262 #[serde(skip_serializing_if = "Option::is_none")]
263 notes: Option<&'s str>,
264}
265
266#[derive(Debug, Clone)]
267pub struct GetUserMinifigNotes<'s> {
268 api_key: &'s str,
269 user_hash: &'s str
270}
271
272impl<'s> CheckKey<'s> {
273 pub fn new(api_key: &'s str) -> Self {
274 CheckKey { api_key }
275 }
276}
277
278impl<'s> Login<'s> {
279 pub fn new(api_key: &'s str, username: &'s str, password: &'s str) -> Self {
280 Login {
281 api_key,
282 username,
283 password,
284 }
285 }
286}
287
288impl<'s> CheckUserHash<'s> {
289 pub fn new(api_key: &'s str, user_hash: &'s str) -> Self {
290 CheckUserHash { api_key, user_hash }
291 }
292}
293
294impl<'s> GetKeyUsageStats<'s> {
295 pub fn new(api_key: &'s str) -> Self {
296 GetKeyUsageStats { api_key }
297 }
298}
299
300impl<'s> GetSets<'s> {
301 pub fn new(
302 api_key: &'s str,
303 user_hash: Option<&'s str>,
304 params: GetSetsParameters<'s>,
305 ) -> Self {
306 Self {
307 api_key,
308 user_hash,
309 params,
310 }
311 }
312}
313
314impl<'s> GetAdditionalImages<'s> {
315 pub fn new(api_key: &'s str, set_id: u64) -> Self {
316 Self { api_key, set_id }
317 }
318}
319
320impl<'s> GetInstructions<'s> {
321 pub fn new(api_key: &'s str, set_id: u64) -> Self {
322 Self { api_key, set_id }
323 }
324}
325
326impl<'s> GetInstructions2<'s> {
327 pub fn new(api_key: &'s str, set_number: &'s str) -> Self {
328 Self {
329 api_key,
330 set_number,
331 }
332 }
333}
334
335impl<'s> GetReviews<'s> {
336 pub fn new(api_key: &'s str, set_id: u64) -> Self {
337 Self { api_key, set_id }
338 }
339}
340
341impl<'s> GetThemes<'s> {
342 pub fn new(api_key: &'s str) -> Self {
343 Self { api_key }
344 }
345}
346
347impl<'s> GetSubthemes<'s> {
348 pub fn new(api_key: &'s str, theme: &'s str) -> Self {
349 Self { api_key, theme }
350 }
351}
352
353impl<'s> GetYears<'s> {
354 pub fn new(api_key: &'s str, theme: &'s str) -> Self {
355 Self { api_key, theme }
356 }
357}
358
359impl<'s> SetCollection<'s> {
360 pub fn new(
361 api_key: &'s str,
362 user_hash: &'s str,
363 set_id: u64,
364 params: SetCollectionParameters<'s>,
365 ) -> Self {
366 Self {
367 api_key,
368 user_hash,
369 set_id,
370 params,
371 }
372 }
373}
374
375impl<'s> GetSetsParameters<'s> {
376 #[inline]
377 pub fn new() -> Self {
378 Self::default()
379 }
380
381 #[inline]
383 pub fn set_id(mut self, set_id: u64) -> Self {
384 self.set_id = Some(set_id);
385 self
386 }
387
388 #[inline]
390 pub fn year(mut self, year: i32) -> Self {
391 self.year.clear();
392 self.year.push(year);
393 self
394 }
395
396 #[inline]
398 pub fn years(mut self, year: Vec<i32>) -> Self {
399 self.year = year;
400 self
401 }
402
403 #[inline]
405 pub fn query(mut self, query: &'s str) -> Self {
406 self.query = Some(query);
407 self
408 }
409
410 #[inline]
412 pub fn theme(mut self, theme: &'s str) -> Self {
413 self.theme = Some(theme);
414 self
415 }
416
417 #[inline]
419 pub fn subtheme(mut self, subtheme: &'s str) -> Self {
420 self.subtheme = Some(subtheme);
421 self
422 }
423
424 #[inline]
426 pub fn full_set_number(mut self, full_set_number: &'s str) -> Self {
427 self.full_set_number = Some(full_set_number);
428 self
429 }
430
431 #[inline]
433 pub fn tag(mut self, tag: &'s str) -> Self {
434 self.tag = Some(tag);
435 self
436 }
437
438 #[inline]
440 pub fn owned_by_user(mut self, owned: bool) -> Self {
441 self.owned = if owned { Some(Flag) } else { None };
442 self
443 }
444
445 #[inline]
447 pub fn wanted_by_user(mut self, wanted: bool) -> Self {
448 self.wanted = if wanted { Some(Flag) } else { None };
449 self
450 }
451
452 #[inline]
454 pub fn extended_data(mut self, extended_data: bool) -> Self {
455 self.extended_data = if extended_data { Some(Flag) } else { None };
456 self
457 }
458
459 #[inline]
461 pub fn updated_since<D: Into<NaiveDate>>(mut self, date: D) -> Self {
462 self.updated_since = Some(date.into());
463 self
464 }
465
466 #[inline]
468 pub fn order_by(mut self, order_by: OrderBy) -> Self {
469 self.order_by = Some(order_by);
470 self
471 }
472
473 #[inline]
475 pub fn page_size(mut self, page_size: usize) -> Self {
476 if page_size > 500 {
477 #[cfg(feature = "log")]
478 warn!("Given page_size was {page_size}, but the maximum is 500");
479 } else if page_size == 0 {
480 #[cfg(feature = "log")]
481 warn!("Zero page size is not valid");
482 }
483
484 self.page_size = Some(page_size);
485 self
486 }
487
488 #[inline]
491 pub fn page_number(mut self, page_number: usize) -> Self {
492 self.page_number = Some(page_number);
493 self
494 }
495}
496
497impl<'s> SetCollectionParameters<'s> {
498 pub fn new() -> Self {
505 Self::default()
506 }
507
508 pub fn owned(mut self, qty_owned: usize) -> Self {
511 if qty_owned == 0 {
512 self.own = None;
513 } else {
514 self.own = Some(1);
515 }
516 self.qty_owned = Some(qty_owned);
517 self
518 }
519
520 pub fn wanted(mut self, wanted: bool) -> Self {
522 if wanted {
523 self.want = Some(1);
524 } else {
525 self.want = Some(0);
526 }
527 self
528 }
529
530 pub fn notes(mut self, notes: &'s str) -> Self {
532 self.notes = Some(notes);
533 self
534 }
535
536 pub fn rating(mut self, rating: i32) -> Self {
538 self.rating = Some(rating);
539 self
540 }
541}
542
543impl<'s> GetUserNotes<'s> {
544 pub fn new(api_key: &'s str, user_hash: &'s str) -> Self {
545 Self { api_key, user_hash }
546 }
547}
548
549impl<'s> GetMinifigCollection<'s> {
550 pub fn new(api_key: &'s str, user_hash: &'s str, params: GetMinifigCollectionParameters<'s>) -> Self {
551 Self { api_key, user_hash, params }
552 }
553}
554
555impl<'s> GetMinifigCollectionParameters<'s> {
556 pub fn owned() -> Self {
558 Self { owned: Some(Flag), ..Default::default() }
559 }
560
561 pub fn wanted() -> Self {
563 Self { wanted: Some(Flag), ..Default::default() }
564 }
565
566 pub fn query(mut self, query: &'s str) -> Self {
568 self.query = Some(query);
569 self
570 }
571}
572
573impl<'s> SetMinifigCollection<'s> {
574 pub fn new(api_key: &'s str, user_hash: &'s str, minifig_number: &'s str, params: SetMinifigCollectionParameters<'s>) -> Self {
575 Self { api_key, user_hash, minifig_number, params }
576 }
577}
578
579impl<'s> SetMinifigCollectionParameters<'s> {
580 pub fn new() -> Self {
586 Self::default()
587 }
588
589 pub fn owned(mut self, qty_owned: usize) -> Self {
592 if qty_owned == 0 {
593 self.own = Some(0);
594 self.qty_owned = None;
595 } else {
596 self.own = None;
597 self.qty_owned = Some(qty_owned);
598 }
599 self
600 }
601
602 pub fn wanted(mut self, wanted: bool) -> Self {
604 if wanted {
605 self.want = Some(1);
606 } else {
607 self.want = Some(0);
608 }
609 self
610 }
611
612 pub fn notes(mut self, notes: &'s str) -> Self {
614 self.notes = Some(notes);
615 self
616 }
617}
618
619impl<'s> GetUserMinifigNotes<'s> {
620 pub fn new(api_key: &'s str, user_hash: &'s str) -> Self {
621 Self { api_key, user_hash }
622 }
623}
624
625impl OrderBy {
626 pub fn reversed(self) -> Self {
630 match self {
631 OrderBy::Number => OrderBy::NumberDESC,
632 OrderBy::YearFrom => OrderBy::YearFromDESC,
633 OrderBy::Pieces => OrderBy::PiecesDESC,
634 OrderBy::Minifigs => OrderBy::MinifigsDESC,
635 OrderBy::Rating => OrderBy::RatingDESC,
636 OrderBy::USRetailPrice => OrderBy::USRetailPriceDESC,
637 OrderBy::UKRetailPrice => OrderBy::UKRetailPriceDESC,
638 OrderBy::CARetailPrice => OrderBy::CARetailPriceDESC,
639 OrderBy::DERetailPrice => OrderBy::DERetailPriceDESC,
640 OrderBy::FRRetailPrice => OrderBy::FRRetailPriceDESC,
641 OrderBy::USPricePerPiece => OrderBy::USPricePerPieceDESC,
642 OrderBy::UKPricePerPiece => OrderBy::UKPricePerPieceDESC,
643 OrderBy::CAPricePerPiece => OrderBy::CAPricePerPieceDESC,
644 OrderBy::DEPricePerPiece => OrderBy::DEPricePerPieceDESC,
645 OrderBy::FRPricePerPiece => OrderBy::FRPricePerPieceDESC,
646 OrderBy::Theme => OrderBy::ThemeDESC,
647 OrderBy::Subtheme => OrderBy::SubthemeDESC,
648 OrderBy::Name => OrderBy::NameDESC,
649 OrderBy::Random => OrderBy::RandomDESC,
650 OrderBy::QtyOwned => OrderBy::QtyOwnedDESC,
651 OrderBy::OwnCount => OrderBy::OwnCountDESC,
652 OrderBy::WantCount => OrderBy::WantCountDESC,
653 OrderBy::UserRating => OrderBy::UserRatingDESC,
654 OrderBy::CollectionID => OrderBy::CollectionIDDESC,
655 OrderBy::NumberDESC => OrderBy::Number,
656 OrderBy::YearFromDESC => OrderBy::YearFrom,
657 OrderBy::PiecesDESC => OrderBy::Pieces,
658 OrderBy::MinifigsDESC => OrderBy::Minifigs,
659 OrderBy::RatingDESC => OrderBy::Rating,
660 OrderBy::USRetailPriceDESC => OrderBy::USRetailPrice,
661 OrderBy::UKRetailPriceDESC => OrderBy::UKRetailPrice,
662 OrderBy::CARetailPriceDESC => OrderBy::CARetailPrice,
663 OrderBy::DERetailPriceDESC => OrderBy::DERetailPrice,
664 OrderBy::FRRetailPriceDESC => OrderBy::FRRetailPrice,
665 OrderBy::USPricePerPieceDESC => OrderBy::USPricePerPiece,
666 OrderBy::UKPricePerPieceDESC => OrderBy::UKPricePerPiece,
667 OrderBy::CAPricePerPieceDESC => OrderBy::CAPricePerPiece,
668 OrderBy::DEPricePerPieceDESC => OrderBy::DEPricePerPiece,
669 OrderBy::FRPricePerPieceDESC => OrderBy::FRPricePerPiece,
670 OrderBy::ThemeDESC => OrderBy::Theme,
671 OrderBy::SubthemeDESC => OrderBy::Subtheme,
672 OrderBy::NameDESC => OrderBy::Name,
673 OrderBy::RandomDESC => OrderBy::Random,
674 OrderBy::QtyOwnedDESC => OrderBy::QtyOwned,
675 OrderBy::OwnCountDESC => OrderBy::OwnCount,
676 OrderBy::WantCountDESC => OrderBy::WantCount,
677 OrderBy::UserRatingDESC => OrderBy::UserRating,
678 OrderBy::CollectionIDDESC => OrderBy::CollectionID,
679 }
680 }
681}
682
683pub trait BricksetRequest {
688 fn encode_query<T>(&self, query: &mut url::form_urlencoded::Serializer<T>) -> Result<(), Error>
690 where
691 T: url::form_urlencoded::Target;
692
693 fn method_name(&self) -> &'static str;
695
696 fn to_request_url(&self) -> Result<Url, Error> {
701 let mut result = ENDPOINT.join(self.method_name())?;
702 self.encode_query(&mut result.query_pairs_mut())?;
703 Ok(result)
704 }
705
706 #[cfg(feature = "reqwest")]
710 fn to_reqwest(&self, client: &reqwest::Client) -> Result<reqwest::Request, Error> {
711 let url = ENDPOINT.join(self.method_name())?;
712
713 let mut body = url::form_urlencoded::Serializer::new(String::new());
714
715 self.encode_query(&mut body)?;
716
717 let body = body.finish();
718
719 Ok(client
720 .post(url)
721 .header(
722 reqwest::header::CONTENT_TYPE,
723 "application/x-www-form-urlencoded",
724 )
725 .header(reqwest::header::CONTENT_LENGTH, body.as_bytes().len())
726 .body(body)
727 .build()?)
728 }
729}
730
731impl<'s> BricksetRequest for CheckKey<'s> {
732 fn encode_query<T>(&self, query: &mut url::form_urlencoded::Serializer<T>) -> Result<(), Error>
733 where
734 T: url::form_urlencoded::Target,
735 {
736 query.append_pair("apiKey", self.api_key);
737 Ok(())
738 }
739
740 fn method_name(&self) -> &'static str {
741 "checkKey"
742 }
743}
744
745impl<'s> BricksetRequest for Login<'s> {
746 fn encode_query<T>(&self, query: &mut url::form_urlencoded::Serializer<T>) -> Result<(), Error>
747 where
748 T: url::form_urlencoded::Target,
749 {
750 query
751 .append_pair("apiKey", self.api_key)
752 .append_pair("username", self.username)
753 .append_pair("password", self.password);
754 Ok(())
755 }
756
757 fn method_name(&self) -> &'static str {
758 "login"
759 }
760}
761
762impl<'s> BricksetRequest for CheckUserHash<'s> {
763 fn encode_query<T>(&self, query: &mut url::form_urlencoded::Serializer<T>) -> Result<(), Error>
764 where
765 T: url::form_urlencoded::Target,
766 {
767 query
768 .append_pair("apiKey", self.api_key)
769 .append_pair("userHash", self.user_hash);
770 Ok(())
771 }
772
773 fn method_name(&self) -> &'static str {
774 "checkUserHash"
775 }
776}
777
778impl<'s> BricksetRequest for GetKeyUsageStats<'s> {
779 fn encode_query<T>(&self, query: &mut url::form_urlencoded::Serializer<T>) -> Result<(), Error>
780 where
781 T: url::form_urlencoded::Target,
782 {
783 query.append_pair("apiKey", self.api_key);
784 Ok(())
785 }
786
787 fn method_name(&self) -> &'static str {
788 "getKeyUsageStats"
789 }
790}
791
792impl<'s> BricksetRequest for GetSets<'s> {
793 fn encode_query<T>(&self, query: &mut url::form_urlencoded::Serializer<T>) -> Result<(), Error>
794 where
795 T: url::form_urlencoded::Target,
796 {
797 let params = serde_json::to_string(&self.params)?;
798
799 if (self.params.wanted.is_some() || self.params.owned.is_some()) && self.user_hash.is_none() {
800 #[cfg(feature = "log")]
801 warn!("User hash is required when wanted/owned parameters are used in GetSets");
802 }
803
804 query
805 .append_pair("apiKey", self.api_key)
806 .append_pair("params", ¶ms)
807 .append_pair("userHash", self.user_hash.unwrap_or(""));
808 Ok(())
809 }
810
811 fn method_name(&self) -> &'static str {
812 "getSets"
813 }
814}
815
816impl<'s> BricksetRequest for GetAdditionalImages<'s> {
817 fn encode_query<T>(&self, query: &mut url::form_urlencoded::Serializer<T>) -> Result<(), Error>
818 where
819 T: url::form_urlencoded::Target,
820 {
821 query
822 .append_pair("apiKey", self.api_key)
823 .append_pair("setID", self.set_id.to_string().as_str());
824 Ok(())
825 }
826
827 fn method_name(&self) -> &'static str {
828 "getAdditionalImages"
829 }
830}
831
832impl<'s> BricksetRequest for GetInstructions<'s> {
833 fn encode_query<T>(&self, query: &mut url::form_urlencoded::Serializer<T>) -> Result<(), Error>
834 where
835 T: url::form_urlencoded::Target,
836 {
837 query
838 .append_pair("apiKey", self.api_key)
839 .append_pair("setID", self.set_id.to_string().as_str());
840 Ok(())
841 }
842
843 fn method_name(&self) -> &'static str {
844 "getInstructions"
845 }
846}
847
848impl<'s> BricksetRequest for GetInstructions2<'s> {
849 fn encode_query<T>(&self, query: &mut url::form_urlencoded::Serializer<T>) -> Result<(), Error>
850 where
851 T: url::form_urlencoded::Target,
852 {
853 query
854 .append_pair("apiKey", self.api_key)
855 .append_pair("setNumber", self.set_number);
856 Ok(())
857 }
858
859 fn method_name(&self) -> &'static str {
860 "getInstructions2"
861 }
862}
863
864impl<'s> BricksetRequest for GetReviews<'s> {
865 fn encode_query<T>(&self, query: &mut url::form_urlencoded::Serializer<T>) -> Result<(), Error>
866 where
867 T: url::form_urlencoded::Target,
868 {
869 query
870 .append_pair("apiKey", self.api_key)
871 .append_pair("setID", self.set_id.to_string().as_str());
872 Ok(())
873 }
874
875 fn method_name(&self) -> &'static str {
876 "getReviews"
877 }
878}
879
880impl<'s> BricksetRequest for GetThemes<'s> {
881 fn encode_query<T>(&self, query: &mut url::form_urlencoded::Serializer<T>) -> Result<(), Error>
882 where
883 T: url::form_urlencoded::Target,
884 {
885 query.append_pair("apiKey", self.api_key);
886 Ok(())
887 }
888
889 fn method_name(&self) -> &'static str {
890 "getThemes"
891 }
892}
893
894impl<'s> BricksetRequest for GetSubthemes<'s> {
895 fn encode_query<T>(&self, query: &mut url::form_urlencoded::Serializer<T>) -> Result<(), Error>
896 where
897 T: url::form_urlencoded::Target,
898 {
899 query
900 .append_pair("apiKey", self.api_key)
901 .append_pair("theme", self.theme);
902 Ok(())
903 }
904
905 fn method_name(&self) -> &'static str {
906 "getSubthemes"
907 }
908}
909
910impl<'s> BricksetRequest for GetYears<'s> {
911 fn encode_query<T>(&self, query: &mut url::form_urlencoded::Serializer<T>) -> Result<(), Error>
912 where
913 T: url::form_urlencoded::Target,
914 {
915 query
916 .append_pair("apiKey", self.api_key)
917 .append_pair("theme", self.theme);
918 Ok(())
919 }
920
921 fn method_name(&self) -> &'static str {
922 "getYears"
923 }
924}
925
926impl<'s> BricksetRequest for SetCollection<'s> {
927 fn encode_query<T>(&self, query: &mut url::form_urlencoded::Serializer<T>) -> Result<(), Error>
928 where
929 T: url::form_urlencoded::Target,
930 {
931 let params = serde_json::to_string(&self.params)?;
932
933 query
934 .append_pair("apiKey", self.api_key)
935 .append_pair("userHash", self.user_hash)
936 .append_pair("setID", self.set_id.to_string().as_str())
937 .append_pair("params", ¶ms);
938 Ok(())
939 }
940
941 fn method_name(&self) -> &'static str {
942 "setCollection"
943 }
944}
945
946impl<'s> BricksetRequest for GetUserNotes<'s> {
947 fn encode_query<T>(&self, query: &mut url::form_urlencoded::Serializer<T>) -> Result<(), Error>
948 where
949 T: url::form_urlencoded::Target,
950 {
951 query
952 .append_pair("apiKey", self.api_key)
953 .append_pair("userHash", self.user_hash);
954 Ok(())
955 }
956
957 fn method_name(&self) -> &'static str {
958 "getUserNotes"
959 }
960}
961
962impl<'s> BricksetRequest for GetMinifigCollection<'s> {
963 fn encode_query<T>(&self, query: &mut url::form_urlencoded::Serializer<T>) -> Result<(), Error>
964 where
965 T: url::form_urlencoded::Target,
966 {
967 let params = serde_json::to_string(&self.params)?;
968
969 query
970 .append_pair("apiKey", self.api_key)
971 .append_pair("userHash", self.user_hash)
972 .append_pair("params", params.as_str());
973 Ok(())
974 }
975
976 fn method_name(&self) -> &'static str {
977 "getMinifigCollection"
978 }
979}
980
981impl<'s> BricksetRequest for SetMinifigCollection<'s> {
982 fn encode_query<T>(&self, query: &mut url::form_urlencoded::Serializer<T>) -> Result<(), Error>
983 where
984 T: url::form_urlencoded::Target,
985 {
986 let params = serde_json::to_string(&self.params)?;
987
988 query
989 .append_pair("apiKey", self.api_key)
990 .append_pair("userHash", self.user_hash)
991 .append_pair("minifigNumber", self.minifig_number.to_string().as_str())
992 .append_pair("params", params.as_str());
993 Ok(())
994 }
995
996 fn method_name(&self) -> &'static str {
997 "setMinifigCollection"
998 }
999}
1000
1001impl<'s> BricksetRequest for GetUserMinifigNotes<'s> {
1002 fn encode_query<T>(&self, query: &mut url::form_urlencoded::Serializer<T>) -> Result<(), Error>
1003 where
1004 T: url::form_urlencoded::Target {
1005 query
1006 .append_pair("apiKey", self.api_key)
1007 .append_pair("userHash", self.user_hash);
1008 Ok(())
1009 }
1010
1011 fn method_name(&self) -> &'static str {
1012 "getUserMinifigNotes"
1013 }
1014}
1015
1016impl From<url::ParseError> for Error {
1017 fn from(value: url::ParseError) -> Self {
1018 Self::UrlParseError(value)
1019 }
1020}
1021
1022impl From<serde_json::Error> for Error {
1023 fn from(value: serde_json::Error) -> Self {
1024 Self::SerdeJson(value)
1025 }
1026}
1027
1028#[cfg(feature = "reqwest")]
1029impl From<reqwest::Error> for Error {
1030 fn from(value: reqwest::Error) -> Self {
1031 Self::Reqwest(value)
1032 }
1033}
1034
1035impl std::fmt::Display for Error {
1036 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1037 match self {
1038 Error::UrlParseError(err) => err.fmt(f),
1039 Error::Message(err) => f.write_str(&err),
1040 Error::SerdeJson(err) => err.fmt(f),
1041 #[cfg(feature = "reqwest")]
1042 Error::Reqwest(err) => err.fmt(f),
1043 }
1044 }
1045}
1046
1047impl std::error::Error for Error {}