mtgapi_client/api/card/filter.rs
1use crate::api::card::filtertypes::*;
2use itertools::Itertools;
3use std::fmt::Display;
4
5const SEP_AND: &str = ",";
6const SEP_OR: &str = "|";
7
8/// Builder for filtered card requests
9#[derive(Clone, Debug)]
10pub struct CardFilterBuilder {
11 filter: String,
12}
13
14impl CardFilterBuilder {
15 fn new() -> CardFilterBuilder {
16 CardFilterBuilder {
17 filter: String::new(),
18 }
19 }
20
21 /// Creates a CardFilter with the specified filter parameters
22 ///
23 /// ```
24 /// # use mtgapi_client::prelude::*;
25 /// let builder = CardFilter::builder();
26 /// let filter = builder
27 /// .color(CardColor::Red)
28 /// .converted_mana_cost(2)
29 /// .cardtype(CardType::Instant)
30 /// .build();
31 /// assert!(filter == CardFilter("colors=Red&cmc=2&types=Instant".to_string()))
32 /// ```
33 #[allow(dead_code)]
34 pub fn build(self) -> CardFilter {
35 CardFilter(self.filter)
36 }
37
38 /// Create a custom filter
39 ///
40 /// ```
41 /// # use mtgapi_client::prelude::*;
42 /// let builder = CardFilter::builder();
43 /// let filter = builder.custom("name", "Shock|Mountain")
44 /// .build();
45 /// assert!(filter == CardFilter("name=Shock|Mountain".to_string()))
46 /// ```
47 #[allow(dead_code)]
48 pub fn custom<'a, T>(mut self, key: T, value: T) -> CardFilterBuilder
49 where
50 T: Into<&'a str>,
51 {
52 self.add_filter(key.into(), value.into());
53 self
54 }
55
56 /// Every card that (partially) matches the specified name will match the filter
57 ///
58 /// ```
59 /// # use mtgapi_client::prelude::*;
60 /// let builder = CardFilter::builder();
61 /// let filter = builder.name("Shock")
62 /// .build();
63 /// assert!(filter == CardFilter("name=Shock".to_string()))
64 /// ```
65 #[allow(dead_code)]
66 pub fn name<'a, T>(mut self, name: T) -> CardFilterBuilder
67 where
68 T: Into<&'a str>,
69 {
70 self.add_filter("name", name.into());
71 self
72 }
73
74 /// Every card that (partially) matches one of the specified names will match the filter
75 ///
76 /// ```
77 /// # use mtgapi_client::prelude::*;
78 /// let builder = CardFilter::builder();
79 /// let filter = builder.names(&vec!["Shock", "Mountain"])
80 /// .build();
81 /// assert!(filter == CardFilter("name=Shock|Mountain".to_string()));
82 /// ```
83 #[allow(dead_code)]
84 pub fn names<T>(mut self, names: &[T]) -> CardFilterBuilder
85 where
86 T: Display,
87 {
88 let values = names.iter().join(SEP_OR);
89 self.add_filter("name", &values);
90 self
91 }
92
93 /// Every card that (partially) matches the specified name will match the filter
94 ///
95 /// ```
96 /// # use mtgapi_client::prelude::*;
97 /// let builder = CardFilter::builder();
98 /// let filter = builder.name_with_language("Schock", CardLanguage::German)
99 /// .build();
100 /// assert!(filter == CardFilter("name=Schock&language=German".to_string()))
101 /// ```
102 #[allow(dead_code)]
103 pub fn name_with_language<'a, T>(mut self, name: T, language: CardLanguage) -> CardFilterBuilder
104 where
105 T: Into<&'a str>,
106 {
107 self.add_filter("name", name.into());
108 self.add_filter("language", &language.as_str());
109 self
110 }
111
112 /// Every card that (partially) matches one of the specified names will match the filter
113 ///
114 /// ```
115 /// # use mtgapi_client::prelude::*;
116 /// let builder = CardFilter::builder();
117 /// let filter = builder.names_with_language(&vec!["Schock", "Gebirge"], CardLanguage::German)
118 /// .build();
119 /// assert!(filter == CardFilter("name=Schock|Gebirge&language=German".to_string()));
120 /// ```
121 #[allow(dead_code)]
122 pub fn names_with_language<T>(
123 mut self,
124 names: &[T],
125 language: CardLanguage,
126 ) -> CardFilterBuilder
127 where
128 T: Display,
129 {
130 let values = names.iter().join(SEP_OR);
131 self.add_filter("name", &values);
132 self.add_filter("language", &language.as_str());
133 self
134 }
135
136 /// Every card name that has the specified layout will match the filter
137 ///
138 /// ```
139 /// # use mtgapi_client::prelude::*;
140 /// let builder = CardFilter::builder();
141 /// let filter = builder.layout(CardLayout::DoubleFaced)
142 /// .build();
143 /// assert!(filter == CardFilter("layout=Double-Faced".to_string()));
144 /// ```
145 #[allow(dead_code)]
146 pub fn layout(mut self, layout: CardLayout) -> CardFilterBuilder {
147 self.add_filter("layout", &layout.as_str());
148 self
149 }
150
151 /// Every card that has one of the specified layouts will match the filter
152 ///
153 /// ```
154 /// # use mtgapi_client::prelude::*;
155 /// let builder = CardFilter::builder();
156 /// let filter = builder.layouts(&vec![CardLayout::Normal, CardLayout::DoubleFaced])
157 /// .build();
158 /// assert!(filter == CardFilter("layout=Normal|Double-Faced".to_string()));
159 /// ```
160 #[allow(dead_code)]
161 pub fn layouts(mut self, layouts: &[CardLayout]) -> CardFilterBuilder {
162 let values = layouts.iter().map(|value| value.as_str()).join(SEP_OR);
163 self.add_filter("layout", &values);
164 self
165 }
166
167 /// Every card name that has the specified converted mana cost will match the filter
168 ///
169 /// ```
170 /// # use mtgapi_client::prelude::*;
171 /// let builder = CardFilter::builder();
172 /// let filter = builder.converted_mana_cost(3)
173 /// .build();
174 /// assert!(filter == CardFilter("cmc=3".to_string()));
175 /// ```
176 #[allow(dead_code)]
177 pub fn converted_mana_cost(mut self, cmc: u8) -> CardFilterBuilder {
178 self.add_filter("cmc", &cmc.to_string());
179 self
180 }
181
182 /// Every card that includes the specified color will match the filter
183 ///
184 /// ```
185 /// # use mtgapi_client::prelude::*;
186 /// let builder = CardFilter::builder();
187 /// let filter = builder.color(CardColor::Red)
188 /// .build();
189 /// assert!(filter == CardFilter("colors=Red".to_string()));
190 /// ```
191 #[allow(dead_code)]
192 pub fn color(mut self, color: CardColor) -> CardFilterBuilder {
193 self.add_filter("colors", &color.as_str());
194 self
195 }
196
197 /// Every card that includes one the specified colors will match the filter
198 ///
199 /// ```
200 /// # use mtgapi_client::prelude::*;
201 /// let builder = CardFilter::builder();
202 /// let filter = builder.colors_or(&vec![CardColor::Red, CardColor::Blue])
203 /// .build();
204 /// assert!(filter == CardFilter("colors=Red|Blue".to_string()));
205 /// ```
206 #[allow(dead_code)]
207 pub fn colors_or(mut self, colors: &[CardColor]) -> CardFilterBuilder {
208 let values = colors.iter().map(|value| value.as_str()).join(SEP_OR);
209 self.add_filter("colors", &values);
210 self
211 }
212
213 /// Every card that includes all the specified colors will match the filter
214 ///
215 /// ```
216 /// # use mtgapi_client::prelude::*;
217 /// let builder = CardFilter::builder();
218 /// let filter = builder.colors_and(&vec![CardColor::Red, CardColor::Blue])
219 /// .build();
220 /// assert!(filter == CardFilter("colors=Red,Blue".to_string()));
221 /// ```
222 #[allow(dead_code)]
223 pub fn colors_and(mut self, colors: &[CardColor]) -> CardFilterBuilder {
224 let values = colors.iter().map(|value| value.as_str()).join(SEP_AND);
225 self.add_filter("colors", &values);
226 self
227 }
228
229 /// Every card that includes the specified color code will match the filter
230 ///
231 /// ```
232 /// # use mtgapi_client::prelude::*;
233 /// let builder = CardFilter::builder();
234 /// let filter = builder.color_identity(CardColorIdentity::R)
235 /// .build();
236 /// assert!(filter == CardFilter("colorIdentity=R".to_string()));
237 /// ```
238 #[allow(dead_code)]
239 pub fn color_identity(mut self, color_identity: CardColorIdentity) -> CardFilterBuilder {
240 self.add_filter("colorIdentity", &color_identity.as_str());
241 self
242 }
243
244 /// Every card that includes one of the specified color codes will match the filter
245 ///
246 /// ```
247 /// # use mtgapi_client::prelude::*;
248 /// let builder = CardFilter::builder();
249 /// let filter = builder.color_identities_or(&vec![CardColorIdentity::R, CardColorIdentity::U])
250 /// .build();
251 /// assert!(filter == CardFilter("colorIdentity=R|U".to_string()));
252 /// ```
253 #[allow(dead_code)]
254 pub fn color_identities_or(
255 mut self,
256 color_identities: &[CardColorIdentity],
257 ) -> CardFilterBuilder {
258 let values = color_identities
259 .iter()
260 .map(|value| value.as_str())
261 .join(SEP_OR);
262 self.add_filter("colorIdentity", &values);
263 self
264 }
265
266 /// Every card that includes all of the specified color codes will match the filter
267 ///
268 /// ```
269 /// # use mtgapi_client::prelude::*;
270 /// let builder = CardFilter::builder();
271 /// let filter = builder.color_identities_and(&vec![CardColorIdentity::R, CardColorIdentity::U])
272 /// .build();
273 /// assert!(filter == CardFilter("colorIdentity=R,U".to_string()));
274 /// ```
275 #[allow(dead_code)]
276 pub fn color_identities_and(
277 mut self,
278 color_identities: &[CardColorIdentity],
279 ) -> CardFilterBuilder {
280 let values = color_identities
281 .iter()
282 .map(|value| value.as_str())
283 .join(SEP_AND);
284 self.add_filter("colorIdentity", &values);
285 self
286 }
287
288 /// Every card that (partially) matches the specified types will match the filter
289 ///
290 /// ```
291 /// # use mtgapi_client::prelude::*;
292 /// let builder = CardFilter::builder();
293 /// let filter = builder.fulltype("Legendary Creature")
294 /// .build();
295 /// assert!(filter == CardFilter("types=Legendary Creature".to_string()));
296 /// ```
297 #[allow(dead_code)]
298 pub fn fulltype<'a, T>(mut self, fulltype: T) -> CardFilterBuilder
299 where
300 T: Into<&'a str>,
301 {
302 self.add_filter("types", &fulltype.into());
303 self
304 }
305
306 /// Every card that (partially) matches one of the specified types will match the filter
307 ///
308 /// ```
309 /// # use mtgapi_client::prelude::*;
310 /// let builder = CardFilter::builder();
311 /// let filter = builder.fulltypes_or(&vec!["Legendary Creature", "Human"])
312 /// .build();
313 /// assert!(filter == CardFilter("types=Legendary Creature|Human".to_string()));
314 /// ```
315 #[allow(dead_code)]
316 pub fn fulltypes_or<T>(mut self, fulltypes: &[T]) -> CardFilterBuilder
317 where
318 T: Display,
319 {
320 let values = fulltypes.iter().join(SEP_OR);
321 self.add_filter("types", &values);
322 self
323 }
324
325 /// Every card that (partially) matches all of the specified types will match the filter
326 ///
327 /// ```
328 /// # use mtgapi_client::prelude::*;
329 /// let builder = CardFilter::builder();
330 /// let filter = builder.fulltypes_and(&vec!["Legendary", "Creature", "Human"])
331 /// .build();
332 /// assert!(filter == CardFilter("types=Legendary,Creature,Human".to_string()));
333 /// ```
334 #[allow(dead_code)]
335 pub fn fulltypes_and<T>(mut self, fulltypes: &[T]) -> CardFilterBuilder
336 where
337 T: Display,
338 {
339 let values = fulltypes.iter().join(SEP_AND);
340 self.add_filter("types", &values);
341 self
342 }
343
344 /// Every card that is of the specified supertype will match the filter
345 ///
346 /// ```
347 /// # use mtgapi_client::prelude::*;
348 /// let builder = CardFilter::builder();
349 /// let filter = builder.supertype(CardSuperType::Legendary)
350 /// .build();
351 /// assert!(filter == CardFilter("supertypes=Legendary".to_string()));
352 /// ```
353 #[allow(dead_code)]
354 pub fn supertype(mut self, supertype: CardSuperType) -> CardFilterBuilder {
355 self.add_filter("supertypes", &supertype.as_str());
356 self
357 }
358
359 /// Every card that is one of the specified supertypes will match the filter
360 ///
361 /// ```
362 /// # use mtgapi_client::prelude::*;
363 /// let builder = CardFilter::builder();
364 /// let filter = builder.supertypes_or(&vec![CardSuperType::Basic, CardSuperType::Legendary])
365 /// .build();
366 /// assert!(filter == CardFilter("supertypes=Basic|Legendary".to_string()));
367 /// ```
368 #[allow(dead_code)]
369 pub fn supertypes_or(mut self, supertypes: &[CardSuperType]) -> CardFilterBuilder {
370 let values = supertypes
371 .iter()
372 .map(|value| value.as_str())
373 .join(SEP_OR);
374 self.add_filter("supertypes", &values);
375 self
376 }
377
378 /// Every card that is all of the specified supertypes will match the filter
379 ///
380 /// ```
381 /// # use mtgapi_client::prelude::*;
382 /// let builder = CardFilter::builder();
383 /// let filter = builder.supertypes_and(&vec![CardSuperType::Basic, CardSuperType::Legendary])
384 /// .build();
385 /// assert!(filter == CardFilter("supertypes=Basic,Legendary".to_string()));
386 /// ```
387 #[allow(dead_code)]
388 pub fn supertypes_and(mut self, supertypes: &[CardSuperType]) -> CardFilterBuilder {
389 let values = supertypes
390 .iter()
391 .map(|value| value.as_str())
392 .join(SEP_AND);
393 self.add_filter("supertypes", &values);
394 self
395 }
396
397 /// Every card that is of the specified types will match the filter
398 ///
399 /// ```
400 /// # use mtgapi_client::prelude::*;
401 /// let builder = CardFilter::builder();
402 /// let filter = builder.cardtype(CardType::Creature)
403 /// .build();
404 /// assert!(filter == CardFilter("types=Creature".to_string()));
405 /// ```
406 #[allow(dead_code)]
407 pub fn cardtype(mut self, cardtype: CardType) -> CardFilterBuilder {
408 self.add_filter("types", &cardtype.as_str());
409 self
410 }
411
412 /// Every card that is of one of the specified types will match the filter
413 ///
414 /// ```
415 /// # use mtgapi_client::prelude::*;
416 /// let builder = CardFilter::builder();
417 /// let filter = builder.cardtypes_or(&vec![CardType::Creature, CardType::Artifact])
418 /// .build();
419 /// assert!(filter == CardFilter("types=Creature|Artifact".to_string()));
420 /// ```
421 #[allow(dead_code)]
422 pub fn cardtypes_or(mut self, cardtypes: &[CardType]) -> CardFilterBuilder {
423 let values = cardtypes
424 .iter()
425 .map(|value| value.as_str())
426 .join(SEP_OR);
427 self.add_filter("types", &values);
428 self
429 }
430
431 /// Every card that is of all of the specified types will match the filter
432 ///
433 /// ```
434 /// # use mtgapi_client::prelude::*;
435 /// let builder = CardFilter::builder();
436 /// let filter = builder.cardtypes_and(&vec![CardType::Creature, CardType::Artifact])
437 /// .build();
438 /// assert!(filter == CardFilter("types=Creature,Artifact".to_string()));
439 /// ```
440 #[allow(dead_code)]
441 pub fn cardtypes_and(mut self, cardtypes: &[CardType]) -> CardFilterBuilder {
442 let values = cardtypes
443 .iter()
444 .map(|value| value.as_str())
445 .join(SEP_AND);
446 self.add_filter("types", &values);
447 self
448 }
449
450 /// Every card that is of the specified subtype will match the filter
451 ///
452 /// ```
453 /// # use mtgapi_client::prelude::*;
454 /// let builder = CardFilter::builder();
455 /// let filter = builder.subtype("Human")
456 /// .build();
457 /// assert!(filter == CardFilter("subtypes=Human".to_string()));
458 /// ```
459 #[allow(dead_code)]
460 pub fn subtype<'a, T>(mut self, subtype: T) -> CardFilterBuilder
461 where
462 T: Into<&'a str>,
463 {
464 self.add_filter("subtypes", &subtype.into());
465 self
466 }
467
468 /// Every card that is of one of the specified subtypes will match the filter
469 ///
470 /// ```
471 /// # use mtgapi_client::prelude::*;
472 /// let builder = CardFilter::builder();
473 /// let filter = builder.subtypes_or(&vec!["Human", "Soldier"])
474 /// .build();
475 /// assert!(filter == CardFilter("subtypes=Human|Soldier".to_string()));
476 /// ```
477 #[allow(dead_code)]
478 pub fn subtypes_or<T>(mut self, subtypes: &[T]) -> CardFilterBuilder
479 where
480 T: Display,
481 {
482 let values = subtypes.iter().join(SEP_OR);
483 self.add_filter("subtypes", &values);
484 self
485 }
486
487 /// Every card that is of all of the specified subtypes will match the filter
488 ///
489 /// ```
490 /// # use mtgapi_client::prelude::*;
491 /// let builder = CardFilter::builder();
492 /// let filter = builder.subtypes_and(&vec!["Human", "Soldier"])
493 /// .build();
494 /// assert!(filter == CardFilter("subtypes=Human,Soldier".to_string()));
495 /// ```
496 #[allow(dead_code)]
497 pub fn subtypes_and<T>(mut self, subtypes: &[T]) -> CardFilterBuilder
498 where
499 T: Display,
500 {
501 let values = subtypes.iter().join(SEP_AND);
502 self.add_filter("subtypes", &values);
503 self
504 }
505
506 /// Every card that is of the specified rarity will match the filter
507 ///
508 /// ```
509 /// # use mtgapi_client::prelude::*;
510 /// let builder = CardFilter::builder();
511 /// let filter = builder.rarity(CardRarity::Rare)
512 /// .build();
513 /// assert!(filter == CardFilter("rarity=Rare".to_string()));
514 /// ```
515 #[allow(dead_code)]
516 pub fn rarity(mut self, rarity: CardRarity) -> CardFilterBuilder {
517 self.add_filter("rarity", &rarity.as_str());
518 self
519 }
520
521 /// Every card that is of one of the specified rarities will match the filter
522 ///
523 /// ```
524 /// # use mtgapi_client::prelude::*;
525 /// let builder = CardFilter::builder();
526 /// let filter = builder.rarities(&vec![CardRarity::Rare, CardRarity::MythicRare])
527 /// .build();
528 /// assert!(filter == CardFilter("rarity=Rare|Mythic Rare".to_string()));
529 /// ```
530 #[allow(dead_code)]
531 pub fn rarities(mut self, rarities: &[CardRarity]) -> CardFilterBuilder {
532 let values = rarities
533 .iter()
534 .map(|value| value.as_str())
535 .join(SEP_OR);
536 self.add_filter("rarity", &values);
537 self
538 }
539
540 /// Every card that is in the specified set will match the filter
541 ///
542 /// ```
543 /// # use mtgapi_client::prelude::*;
544 /// let builder = CardFilter::builder();
545 /// let filter = builder.set("AER")
546 /// .build();
547 /// assert!(filter == CardFilter("set=AER".to_string()));
548 /// ```
549 #[allow(dead_code)]
550 pub fn set<'a, T>(mut self, set: T) -> CardFilterBuilder
551 where
552 T: Into<&'a str>,
553 {
554 self.add_filter("set", &set.into());
555 self
556 }
557
558 /// Every card that is in one of the specified sets will match the filter
559 ///
560 /// ```
561 /// # use mtgapi_client::prelude::*;
562 /// let builder = CardFilter::builder();
563 /// let filter = builder.sets(&vec!["AER", "M19"])
564 /// .build();
565 /// assert!(filter == CardFilter("set=AER|M19".to_string()));
566 /// ```
567 #[allow(dead_code)]
568 pub fn sets<T>(mut self, sets: &[T]) -> CardFilterBuilder
569 where
570 T: Display,
571 {
572 let values = sets.iter().join(SEP_OR);
573 self.add_filter("set", &values);
574 self
575 }
576
577 /// Every card that (partially) matches the specified set name will match the filter
578 ///
579 /// ```
580 /// # use mtgapi_client::prelude::*;
581 /// let builder = CardFilter::builder();
582 /// let filter = builder.set_name("Core Set 2019")
583 /// .build();
584 /// assert!(filter == CardFilter("setName=Core Set 2019".to_string()));
585 /// ```
586 #[allow(dead_code)]
587 pub fn set_name<'a, T>(mut self, set: T) -> CardFilterBuilder
588 where
589 T: Into<&'a str>,
590 {
591 self.add_filter("setName", &set.into());
592 self
593 }
594
595 /// Every card that (partially) matches one of the specified set names will match the filter
596 ///
597 /// ```
598 /// # use mtgapi_client::prelude::*;
599 /// let builder = CardFilter::builder();
600 /// let filter = builder.set_names(&vec!["Core Set 2019", "Aether Revolt"])
601 /// .build();
602 /// assert!(filter == CardFilter("setName=Core Set 2019|Aether Revolt".to_string()));
603 /// ```
604 #[allow(dead_code)]
605 pub fn set_names<T>(mut self, sets: &[T]) -> CardFilterBuilder
606 where
607 T: Display,
608 {
609 let values = sets.iter().join(SEP_OR);
610 self.add_filter("setName", &values);
611 self
612 }
613
614 /// Every card that (partially) matches the specified oracle text will match the filter
615 ///
616 /// ```
617 /// # use mtgapi_client::prelude::*;
618 /// let builder = CardFilter::builder();
619 /// let filter = builder.text("deals 2 damage")
620 /// .build();
621 /// assert!(filter == CardFilter("text=deals 2 damage".to_string()));
622 /// ```
623 #[allow(dead_code)]
624 pub fn text<'a, T>(mut self, text: T) -> CardFilterBuilder
625 where
626 T: Into<&'a str>,
627 {
628 self.add_filter("text", &text.into());
629 self
630 }
631
632 /// Every card that (partially) matches one of the specified oracle texts will match the filter
633 ///
634 /// ```
635 /// # use mtgapi_client::prelude::*;
636 /// let builder = CardFilter::builder();
637 /// let filter = builder.texts_or(&vec!["deals", "damage"])
638 /// .build();
639 /// assert!(filter == CardFilter("text=deals|damage".to_string()));
640 /// ```
641 #[allow(dead_code)]
642 pub fn texts_or<T>(mut self, texts: &[T]) -> CardFilterBuilder
643 where
644 T: Display,
645 {
646 let values = texts.iter().join(SEP_OR);
647 self.add_filter("text", &values);
648 self
649 }
650
651 /// Every card that (partially) matches all of the specified oracle texts will match the filter
652 ///
653 /// ```
654 /// # use mtgapi_client::prelude::*;
655 /// let builder = CardFilter::builder();
656 /// let filter = builder.texts_and(&vec!["deals", "damage"])
657 /// .build();
658 /// assert!(filter == CardFilter("text=deals,damage".to_string()));
659 /// ```
660 #[allow(dead_code)]
661 pub fn texts_and<T>(mut self, texts: &[T]) -> CardFilterBuilder
662 where
663 T: Display,
664 {
665 let values = texts.iter().join(SEP_AND);
666 self.add_filter("text", &values);
667 self
668 }
669
670 /// Every card that (partially) matches the specified flavour text will match the filter
671 ///
672 /// ```
673 /// # use mtgapi_client::prelude::*;
674 /// let builder = CardFilter::builder();
675 /// let filter = builder.flavor("S.N.E.A.K.")
676 /// .build();
677 /// assert!(filter == CardFilter("flavor=S.N.E.A.K.".to_string()));
678 /// ```
679 #[allow(dead_code)]
680 pub fn flavor<'a, T>(mut self, flavor: T) -> CardFilterBuilder
681 where
682 T: Into<&'a str>,
683 {
684 self.add_filter("flavor", &flavor.into());
685 self
686 }
687
688 /// Every card that (partially) matches one of the specified flavour texts will match the filter
689 ///
690 /// ```
691 /// # use mtgapi_client::prelude::*;
692 /// let builder = CardFilter::builder();
693 /// let filter = builder.flavors_or(&vec!["Espionage", "Kidnapping"])
694 /// .build();
695 /// assert!(filter == CardFilter("flavor=Espionage|Kidnapping".to_string()));
696 /// ```
697 #[allow(dead_code)]
698 pub fn flavors_or<T>(mut self, flavors: &[T]) -> CardFilterBuilder
699 where
700 T: Display,
701 {
702 let values = flavors.iter().join(SEP_OR);
703 self.add_filter("flavor", &values);
704 self
705 }
706
707 /// Every card that (partially) matches all of the specified flavour texts will match the filter
708 ///
709 /// ```
710 /// # use mtgapi_client::prelude::*;
711 /// let builder = CardFilter::builder();
712 /// let filter = builder.flavors_and(&vec!["Serious", "Nonstop Espionage and Kidnapping"])
713 /// .build();
714 /// assert!(filter == CardFilter("flavor=Serious,Nonstop Espionage and Kidnapping".to_string()));
715 /// ```
716 #[allow(dead_code)]
717 pub fn flavors_and<T>(mut self, flavors: &[T]) -> CardFilterBuilder
718 where
719 T: Display,
720 {
721 let values = flavors.iter().join(SEP_AND);
722 self.add_filter("flavor", &values);
723 self
724 }
725
726 /// Every card that is drawn by the specified artist will match the filter
727 ///
728 /// ```
729 /// # use mtgapi_client::prelude::*;
730 /// let builder = CardFilter::builder();
731 /// let filter = builder.artist("Kev Walker")
732 /// .build();
733 /// assert!(filter == CardFilter("artist=Kev Walker".to_string()));
734 /// ```
735 #[allow(dead_code)]
736 pub fn artist<'a, T>(mut self, artist: T) -> CardFilterBuilder
737 where
738 T: Into<&'a str>,
739 {
740 self.add_filter("artist", &artist.into());
741 self
742 }
743
744 /// Every card that is drawn by one of the specified artists will match the filter
745 ///
746 /// ```
747 /// # use mtgapi_client::prelude::*;
748 /// let builder = CardFilter::builder();
749 /// let filter = builder.artists(&vec!["Kev Walker", "Pete Venters"])
750 /// .build();
751 /// assert!(filter == CardFilter("artist=Kev Walker|Pete Venters".to_string()));
752 /// ```
753 #[allow(dead_code)]
754 pub fn artists<T>(mut self, artists: &[T]) -> CardFilterBuilder
755 where
756 T: Display,
757 {
758 let values = artists.iter().join(SEP_OR);
759 self.add_filter("artist", &values);
760 self
761 }
762
763 /// Every card with the specified card number will match the filter
764 ///
765 /// The card number may contain letters
766 ///
767 /// ```
768 /// # use mtgapi_client::prelude::*;
769 /// let builder = CardFilter::builder();
770 /// let filter = builder.number("1")
771 /// .build();
772 /// assert!(filter == CardFilter("number=1".to_string()));
773 /// ```
774 #[allow(dead_code)]
775 pub fn number<'a, T>(mut self, number: T) -> CardFilterBuilder
776 where
777 T: Into<&'a str>,
778 {
779 self.add_filter("number", &number.into());
780 self
781 }
782
783 /// Every card with one of the specified card numbers will match the filter
784 ///
785 /// The card number may contain letters
786 ///
787 /// ```
788 /// # use mtgapi_client::prelude::*;
789 /// let builder = CardFilter::builder();
790 /// let filter = builder.numbers(&vec!["1", "2"])
791 /// .build();
792 /// assert!(filter == CardFilter("number=1|2".to_string()));
793 /// ```
794 #[allow(dead_code)]
795 pub fn numbers<T>(mut self, numbers: &[T]) -> CardFilterBuilder
796 where
797 T: Display,
798 {
799 let values = numbers.iter().join(SEP_OR);
800 self.add_filter("number", &values);
801 self
802 }
803
804 /// Every card with the specified power will match the filter
805 ///
806 /// Some cards have powers like: “1+*”
807 ///
808 /// ```
809 /// # use mtgapi_client::prelude::*;
810 /// let builder = CardFilter::builder();
811 /// let filter = builder.power("1")
812 /// .build();
813 /// assert!(filter == CardFilter("power=1".to_string()));
814 /// ```
815 #[allow(dead_code)]
816 pub fn power<'a, T>(mut self, power: T) -> CardFilterBuilder
817 where
818 T: Into<&'a str>,
819 {
820 self.add_filter("power", &power.into());
821 self
822 }
823
824 /// Every card with one of the specified powers will match the filter
825 ///
826 /// Some cards have powers like: “1+*”
827 ///
828 /// ```
829 /// # use mtgapi_client::prelude::*;
830 /// let builder = CardFilter::builder();
831 /// let filter = builder.powers(&vec!["1", "2"])
832 /// .build();
833 /// assert!(filter == CardFilter("power=1|2".to_string()));
834 /// ```
835 #[allow(dead_code)]
836 pub fn powers<T>(mut self, powers: &[T]) -> CardFilterBuilder
837 where
838 T: Display,
839 {
840 let values = powers.iter().join(SEP_OR);
841 self.add_filter("power", &values);
842 self
843 }
844
845 /// Every card with the specified toughness will match the filter
846 ///
847 /// Some cards have toughness like: “1+*”
848 ///
849 /// ```
850 /// # use mtgapi_client::prelude::*;
851 /// let builder = CardFilter::builder();
852 /// let filter = builder.toughness("1")
853 /// .build();
854 /// assert!(filter == CardFilter("toughness=1".to_string()));
855 /// ```
856 #[allow(dead_code)]
857 pub fn toughness<'a, T>(mut self, toughness: T) -> CardFilterBuilder
858 where
859 T: Into<&'a str>,
860 {
861 self.add_filter("toughness", &toughness.into());
862 self
863 }
864
865 /// Every card with one of the specified toughnesses will match the filter
866 ///
867 /// Some cards have toughnesses like: “1+*”
868 ///
869 /// ```
870 /// # use mtgapi_client::prelude::*;
871 /// let builder = CardFilter::builder();
872 /// let filter = builder.toughnesses(&vec!["1", "2"])
873 /// .build();
874 /// assert!(filter == CardFilter("toughness=1|2".to_string()));
875 /// ```
876 #[allow(dead_code)]
877 pub fn toughnesses<T>(mut self, toughnesses: &[T]) -> CardFilterBuilder
878 where
879 T: Display,
880 {
881 let values = toughnesses.iter().join(SEP_OR);
882 self.add_filter("toughness", &values);
883 self
884 }
885
886 /// Every card with the specified loyality will match the filter
887 ///
888 /// This is only present for planeswalkers
889 ///
890 /// ```
891 /// # use mtgapi_client::prelude::*;
892 /// let builder = CardFilter::builder();
893 /// let filter = builder.loyality("3")
894 /// .build();
895 /// assert!(filter == CardFilter("loyality=3".to_string()));
896 /// ```
897 #[allow(dead_code)]
898 pub fn loyality<'a, T>(mut self, loyality: T) -> CardFilterBuilder
899 where
900 T: Into<&'a str>,
901 {
902 self.add_filter("loyality", &loyality.into());
903 self
904 }
905
906 /// Every card with one of the specified loyalities will match the filter
907 ///
908 /// This is only present for planeswalkers
909 ///
910 /// ```
911 /// # use mtgapi_client::prelude::*;
912 /// let builder = CardFilter::builder();
913 /// let filter = builder.loyalities(&vec!["3", "5"])
914 /// .build();
915 /// assert!(filter == CardFilter("loyality=3|5".to_string()));
916 /// ```
917 #[allow(dead_code)]
918 pub fn loyalities<T>(mut self, loyalities: &[T]) -> CardFilterBuilder
919 where
920 T: Display,
921 {
922 let values = loyalities.iter().join(SEP_OR);
923 self.add_filter("loyality", &values);
924 self
925 }
926
927 /// Every card that is legal in the specified game format will match the filter
928 ///
929 /// ```
930 /// # use mtgapi_client::prelude::*;
931 /// let builder = CardFilter::builder();
932 /// let filter = builder.game_format(GameFormat::Standard)
933 /// .build();
934 /// assert!(filter == CardFilter("gameFormat=Standard".to_string()));
935 /// ```
936 #[allow(dead_code)]
937 pub fn game_format(mut self, format: GameFormat) -> CardFilterBuilder {
938 self.add_filter("gameFormat", &format.as_str());
939 self
940 }
941
942 /// Every card that is legal in the specified game formats will match the filter
943 ///
944 /// ```
945 /// # use mtgapi_client::prelude::*;
946 /// let builder = CardFilter::builder();
947 /// let filter = builder.game_format(GameFormat::Standard)
948 /// .build();
949 /// assert!(filter == CardFilter("gameFormat=Standard".to_string()));
950 /// ```
951 #[allow(dead_code)]
952 pub fn game_formats(mut self, formats: &[GameFormat]) -> CardFilterBuilder {
953 let values = formats.iter().map(|value| value.as_str()).join(SEP_OR);
954 self.add_filter("gameFormat", &values);
955 self
956 }
957
958 /// Every card that is of the specified legality in the specified game format will match the filter
959 ///
960 /// ```
961 /// # use mtgapi_client::prelude::*;
962 /// let builder = CardFilter::builder();
963 /// let filter = builder.game_format_with_legality(GameFormat::Commander, CardLegality::Banned)
964 /// .build();
965 /// assert!(filter == CardFilter("gameFormat=Commander&legality=Banned".to_string()));
966 /// ```
967 #[allow(dead_code)]
968 pub fn game_format_with_legality(
969 mut self,
970 format: GameFormat,
971 legality: CardLegality,
972 ) -> CardFilterBuilder {
973 self.add_filter("gameFormat", &format.as_str());
974 self.add_filter("legality", &legality.as_str());
975 self
976 }
977
978 /// Every card that is of the specified legality in the specified game formats will match the filter
979 ///
980 /// ```
981 /// # use mtgapi_client::prelude::*;
982 /// let builder = CardFilter::builder();
983 /// let filter = builder.game_formats_with_legality(&vec![GameFormat::Standard, GameFormat::Commander], CardLegality::Banned)
984 /// .build();
985 /// assert!(filter == CardFilter("gameFormat=Standard|Commander&legality=Banned".to_string()));
986 /// ```
987 #[allow(dead_code)]
988 pub fn game_formats_with_legality(
989 mut self,
990 formats: &[GameFormat],
991 legality: CardLegality,
992 ) -> CardFilterBuilder {
993 let values = formats.iter().map(|value| value.as_str()).join(SEP_OR);
994 self.add_filter("gameFormat", &values);
995 self.add_filter("legality", &legality.as_str());
996 self
997 }
998
999 fn add_filter<T>(&mut self, key: T, values: T)
1000 where
1001 T: Display,
1002 {
1003 if !self.filter.is_empty() {
1004 self.filter = [&self.filter, "&"].join("");
1005 }
1006 self.filter = self.filter.clone() + &[key, values].iter().join("=")
1007 }
1008
1009 /// Every card with the specified multiverse Id will match the filter
1010 ///
1011 /// This is only present for planeswalkers
1012 ///
1013 /// ```
1014 /// # use mtgapi_client::prelude::*;
1015 /// let builder = CardFilter::builder();
1016 /// let filter = builder.multiverse_id("409741")
1017 /// .build();
1018 /// assert!(filter == CardFilter("multiverseid=409741".to_string()));
1019 /// ```
1020 #[allow(dead_code)]
1021 pub fn multiverse_id<'a, T>(mut self, multiverse_id: T) -> CardFilterBuilder
1022 where
1023 T: Into<&'a str>,
1024 {
1025 self.add_filter("multiverseid", &multiverse_id.into());
1026 self
1027 }
1028
1029 /// Every card with one of the specified multiverse Ids will match the filter
1030 ///
1031 /// This is only present for planeswalkers
1032 ///
1033 /// ```
1034 /// # use mtgapi_client::prelude::*;
1035 /// let builder = CardFilter::builder();
1036 /// let filter = builder.multiverse_ids(&vec!["409741", "409742"])
1037 /// .build();
1038 /// assert!(filter == CardFilter("multiverseid=409741|409742".to_string()));
1039 /// ```
1040 #[allow(dead_code)]
1041 pub fn multiverse_ids<T>(mut self, multiverse_ids: &[T]) -> CardFilterBuilder
1042 where
1043 T: Display,
1044 {
1045 let values = multiverse_ids.iter().join(SEP_OR);
1046 self.add_filter("multiverseid", &values);
1047 self
1048 }
1049
1050 /// Every card that contains the specified field in the response will match the filter
1051 ///
1052 /// ```
1053 /// # use mtgapi_client::prelude::*;
1054 /// let builder = CardFilter::builder();
1055 /// let filter = builder.contains_field(CardResponseField::ImageUrl)
1056 /// .build();
1057 /// assert!(filter == CardFilter("contains=imageUrl".to_string()));
1058 /// ```
1059 #[allow(dead_code)]
1060 pub fn contains_field(mut self, field: CardResponseField) -> CardFilterBuilder {
1061 self.add_filter("contains", &field.as_str());
1062 self
1063 }
1064
1065 /// Every card that contains one of the specified fields in the response will match the filter
1066 ///
1067 /// ```
1068 /// # use mtgapi_client::prelude::*;
1069 /// let builder = CardFilter::builder();
1070 /// let filter = builder.contains_fields(&vec![CardResponseField::ImageUrl, CardResponseField::MultiverseId])
1071 /// .build();
1072 /// assert!(filter == CardFilter("contains=imageUrl|multiverseid".to_string()));
1073 /// ```
1074 #[allow(dead_code)]
1075 pub fn contains_fields(mut self, fields: &[CardResponseField]) -> CardFilterBuilder {
1076 let values = fields.iter().map(|value| value.as_str()).join(SEP_OR);
1077 self.add_filter("contains", &values);
1078 self
1079 }
1080}
1081
1082/// Wrapper around the filter string to be used for filtered card api requests
1083#[derive(PartialEq, Eq, Clone, Debug)]
1084pub struct CardFilter(pub String);
1085
1086impl CardFilter {
1087 /// Creates a new CardFilterBuilder
1088 #[allow(dead_code)]
1089 pub fn builder() -> CardFilterBuilder {
1090 CardFilterBuilder::new()
1091 }
1092}