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}