lotr_api/request/
filter.rs

1use crate::{attribute::Attribute, ItemType};
2
3use super::GetUrl;
4
5/// A filter that can be used to filter the results of a request.
6///
7/// # Examples
8///
9/// ```
10/// use lotr_api::{
11///     attribute::{Attribute, BookAttribute},
12///     request::GetUrl,
13///     filter::{Filter, Operator}};
14///
15///
16///
17/// let filter = Filter::Match(
18///     Attribute::Book(BookAttribute::Name),
19///     Operator::Eq,
20///     vec!["The Fellowship of the Ring".to_string()]);
21///
22/// assert_eq!(filter.get_url(), "name=The Fellowship of the Ring");
23/// ```
24#[derive(Debug, Clone, PartialEq, Eq)]
25pub enum Filter {
26    Match(Attribute, Operator, Vec<String>),
27    Exists(Attribute, bool),
28}
29
30impl GetUrl for Filter {
31    fn get_url(&self) -> String {
32        match self {
33            Filter::Match(attribute, operation, values) => {
34                let mut url = attribute.get_url();
35                url.push_str(&operation.get_url());
36                url.push_str(&values.join(","));
37                url
38            }
39            Filter::Exists(attribute, exists) => {
40                let mut url = String::new();
41                if !exists {
42                    url.push('!');
43                }
44                url.push_str(&attribute.get_url());
45                url
46            }
47        }
48    }
49}
50
51impl Filter {
52    pub(crate) fn get_item_type(&self) -> ItemType {
53        match self {
54            Filter::Match(attribute, _, _) => attribute.get_item_type(),
55            Filter::Exists(attribute, _) => attribute.get_item_type(),
56        }
57    }
58}
59
60/// The operator used to compare the attribute and the values.
61#[derive(Debug, Copy, Clone, PartialEq, Eq)]
62pub enum Operator {
63    /// Equal to
64    Eq,
65    /// Not equal to
66    Ne,
67    /// Greater than
68    Gt,
69    /// Less than
70    Lt,
71    /// Greater than or equal to
72    Gte,
73    /// Less than or equal to
74    Lte,
75}
76
77impl GetUrl for Operator {
78    fn get_url(&self) -> String {
79        match self {
80            Operator::Eq => "=",
81            Operator::Ne => "!=",
82            Operator::Gt => ">",
83            Operator::Lt => "<",
84            Operator::Gte => ">=",
85            Operator::Lte => "<=",
86        }
87        .into()
88    }
89}
90
91#[cfg(test)]
92mod tests {
93    use super::*;
94
95    use crate::attribute::{Attribute, BookAttribute, CharacterAttribute, MovieAttribute};
96
97    #[test]
98    fn test_match_eq() {
99        let filter_eq = Filter::Match(
100            Attribute::Book(BookAttribute::Name),
101            Operator::Eq,
102            vec!["The Fellowship of the Ring".to_string()],
103        );
104        assert_eq!(
105            filter_eq.get_url(),
106            "name=The Fellowship of the Ring".to_string()
107        );
108    }
109
110    #[test]
111    fn test_match_ne() {
112        let filter_ne = Filter::Match(
113            Attribute::Book(BookAttribute::Name),
114            Operator::Ne,
115            vec!["The Fellowship of the Ring".to_string()],
116        );
117        assert_eq!(
118            filter_ne.get_url(),
119            "name!=The Fellowship of the Ring".to_string()
120        );
121    }
122
123    #[test]
124    fn test_exists() {
125        let filter_include = Filter::Exists(Attribute::Character(CharacterAttribute::Name), true);
126        assert_eq!(filter_include.get_url(), "name".to_string());
127    }
128
129    #[test]
130    fn test_dont_exist() {
131        let filter_exclude = Filter::Exists(Attribute::Character(CharacterAttribute::Name), false);
132        assert_eq!(filter_exclude.get_url(), "!name".to_string());
133    }
134
135    #[test]
136    fn test_include_and_exclude() {
137        let filter = Filter::Match(
138            Attribute::Book(BookAttribute::Name),
139            Operator::Eq,
140            vec![
141                "The Fellowship Of The Ring".to_string(),
142                "The Two Towers".to_string(),
143                "The Return Of The King".to_string(),
144            ],
145        );
146
147        assert_eq!(
148            filter.get_url(),
149            "name=The Fellowship Of The Ring,The Two Towers,The Return Of The King".to_string()
150        );
151
152        let filter = Filter::Match(
153            Attribute::Book(BookAttribute::Name),
154            Operator::Ne,
155            vec![
156                "The Fellowship Of The Ring".to_string(),
157                "The Two Towers".to_string(),
158                "The Return Of The King".to_string(),
159            ],
160        );
161
162        assert_eq!(
163            filter.get_url(),
164            "name!=The Fellowship Of The Ring,The Two Towers,The Return Of The King".to_string()
165        );
166    }
167
168    #[test]
169    fn test_operations() {
170        let tests = vec![
171            (
172                Filter::Match(
173                    Attribute::Movie(MovieAttribute::BudgetInMillions),
174                    Operator::Gt,
175                    vec!["10".to_string()],
176                ),
177                "budgetInMillions>10",
178            ),
179            (
180                Filter::Match(
181                    Attribute::Movie(MovieAttribute::BudgetInMillions),
182                    Operator::Gte,
183                    vec!["10".to_string()],
184                ),
185                "budgetInMillions>=10",
186            ),
187            (
188                Filter::Match(
189                    Attribute::Movie(MovieAttribute::BudgetInMillions),
190                    Operator::Lt,
191                    vec!["10".to_string()],
192                ),
193                "budgetInMillions<10",
194            ),
195            (
196                Filter::Match(
197                    Attribute::Movie(MovieAttribute::BudgetInMillions),
198                    Operator::Lte,
199                    vec!["10".to_string()],
200                ),
201                "budgetInMillions<=10",
202            ),
203        ];
204
205        for (filter, expected) in tests {
206            assert_eq!(filter.get_url(), expected.to_string());
207        }
208    }
209}