simple_ldap/
filter.rs

1//! # Filter
2//!
3//! This module contains the implementation of the LDAP filter.
4//!
5
6/// The `Filter` trait is implemented by all the filters.
7pub trait Filter: Send {
8    fn filter(&self) -> String;
9}
10
11/// The `AndFilter` struct represents an AND filter.
12#[derive(Default)]
13pub struct AndFilter {
14    filters: Vec<Box<dyn Filter>>,
15}
16
17impl AndFilter {
18    /// Creates a new `AndFilter`.
19    ///
20    /// # Examples
21    ///
22    /// ```
23    /// use simple_ldap::filter::AndFilter;
24    ///
25    /// let filter = AndFilter::new();
26    /// ```
27    #[deprecated(
28        since = "1.3.2",
29        note = "Please use the `Default` trait instead of this method."
30    )]
31    pub fn new() -> Self {
32        AndFilter {
33            filters: Vec::new(),
34        }
35    }
36
37    /// Adds a filter to the `AndFilter`.
38    ///
39    /// # Arguments
40    /// * `filter` - The filter to add.
41    ///
42    /// # Examples
43    ///
44    /// ```
45    /// use simple_ldap::filter::{AndFilter, EqFilter};
46    ///
47    /// let mut filter = AndFilter::new();
48    /// filter.add(Box::new(EqFilter::from("cn".to_string(), "test".to_string())));
49    /// ```
50    pub fn add(&mut self, filter: Box<dyn Filter>) {
51        self.filters.push(filter);
52    }
53}
54
55impl Filter for AndFilter {
56    fn filter(&self) -> String {
57        let mut filter = String::from("(&");
58        for f in &self.filters {
59            filter.push_str(&f.filter());
60        }
61        filter.push(')');
62        filter
63    }
64}
65
66/// The `OrFilter` struct represents an OR filter.
67#[derive(Default)]
68pub struct OrFilter {
69    filters: Vec<Box<dyn Filter>>,
70}
71
72impl OrFilter {
73    /// Creates a new `OrFilter`.
74    ///
75    /// # Examples
76    ///
77    /// ```
78    /// use simple_ldap::filter::OrFilter;
79    ///
80    /// let filter = OrFilter::new();
81    /// ```
82    #[deprecated(
83        since = "1.3.2",
84        note = "Please use the `Default` trait instead of this method."
85    )]
86    pub fn new() -> Self {
87        OrFilter {
88            filters: Vec::new(),
89        }
90    }
91
92    /// Adds a filter to the `OrFilter`.
93    ///
94    /// # Arguments
95    /// * `filter` - The filter to add.
96    ///
97    /// # Examples
98    ///
99    /// ```
100    /// use simple_ldap::filter::{OrFilter, EqFilter};
101    ///
102    /// let mut filter = OrFilter::new();
103    /// filter.add(Box::new(EqFilter::from("cn".to_string(), "test".to_string())));
104    /// ```
105    pub fn add(&mut self, filter: Box<dyn Filter>) {
106        self.filters.push(filter);
107    }
108}
109
110impl Filter for OrFilter {
111    fn filter(&self) -> String {
112        let mut filter = String::from("(|");
113        for f in &self.filters {
114            filter.push_str(&f.filter());
115        }
116        filter.push(')');
117        filter
118    }
119}
120
121/// The `EqFilter` struct represents an equality filter.
122pub struct EqFilter {
123    attribute: String,
124    value: String,
125}
126
127impl EqFilter {
128    /// Creates a new `EqFilter`.
129    ///
130    /// # Arguments
131    /// * `attribute` - The attribute to filter.
132    /// * `value` - The value of the attribute.
133    ///
134    /// # Examples
135    ///
136    /// ```
137    /// use simple_ldap::filter::EqFilter;
138    ///
139    /// let filter = EqFilter::from("cn".to_string(), "test".to_string());
140    /// ```
141    pub fn from(attribute: String, value: String) -> Self {
142        EqFilter { attribute, value }
143    }
144}
145
146impl Filter for EqFilter {
147    fn filter(&self) -> String {
148        format!("({}={})", self.attribute, self.value)
149    }
150}
151
152/// The `NotFilter` struct represents a NOT filter.
153/// This filter represents the negation of another filter. This is equal to LDAP `!` operator.
154pub struct NotFilter {
155    filter: Box<dyn Filter>,
156}
157
158impl NotFilter {
159    /// Creates a new `NotFilter`.
160    ///
161    /// # Arguments
162    /// * `filter` - The filter to negate.
163    ///
164    /// # Examples
165    ///
166    /// ```
167    /// use simple_ldap::filter::{NotFilter, EqFilter};
168    ///
169    /// let filter = NotFilter::from(Box::new(EqFilter::from("cn".to_string(), "test".to_string())));
170    /// ```
171    pub fn from(filter: Box<dyn Filter>) -> Self {
172        NotFilter { filter }
173    }
174}
175
176impl Filter for NotFilter {
177    fn filter(&self) -> String {
178        format!("(!{})", self.filter.filter())
179    }
180}
181
182/// The `LikeFilter` struct represents a LIKE filter.
183/// This generates a ldap filter with a wildcard on the left or on the right of the value.
184pub struct LikeFilter {
185    attribute: String,
186    value: String,
187    wildcard_on: WildardOn,
188}
189
190/// The `WildardOn` enum represents the wildcard position.
191pub enum WildardOn {
192    /// The wildcard is on the left of the value.
193    Pre,
194    /// The wildcard is on the right of the value.
195    Post,
196}
197
198impl LikeFilter {
199    /// Creates a new `LikeFilter`.
200    ///
201    /// # Arguments
202    /// * `attribute` - The attribute to filter.
203    /// * `value` - The value of the attribute.
204    /// * `wildcard_on` - The wildcard position.
205    ///
206    /// # Examples
207    ///
208    /// ```
209    /// use simple_ldap::filter::{LikeFilter, WildardOn};
210    ///
211    /// let filter = LikeFilter::from("cn".to_string(), "test".to_string(), WildardOn::Pre);
212    /// ```
213    pub fn from(attribute: String, value: String, wildcard_on: WildardOn) -> Self {
214        LikeFilter {
215            attribute,
216            value,
217            wildcard_on,
218        }
219    }
220}
221
222impl Filter for LikeFilter {
223    fn filter(&self) -> String {
224        match self.wildcard_on {
225            WildardOn::Pre => format!("({}=*{})", self.attribute, self.value),
226            WildardOn::Post => format!("({}={}*)", self.attribute, self.value),
227        }
228    }
229}
230
231/// The `ContainsFilter` struct represents a CONTAINS filter.
232/// This generates a ldap filter that checks if the value is contained in the attribute.
233pub struct ContainsFilter {
234    attribute: String,
235    value: String,
236}
237
238impl ContainsFilter {
239    /// Creates a new `ContainsFilter`.
240    ///
241    /// # Arguments
242    /// * `attribute` - The attribute to filter.
243    /// * `value` - The value of the attribute.
244    ///
245    /// # Examples
246    ///
247    /// ```
248    /// use simple_ldap::filter::ContainsFilter;
249    ///
250    /// let filter = ContainsFilter::from("cn".to_string(), "test".to_string());
251    /// ```
252    pub fn from(attribute: String, value: String) -> Self {
253        ContainsFilter { attribute, value }
254    }
255}
256
257impl Filter for ContainsFilter {
258    fn filter(&self) -> String {
259        format!("({}=*{}*)", self.attribute, self.value)
260    }
261}
262
263#[cfg(test)]
264mod tests {
265
266    use super::*;
267
268    #[test]
269    fn test_eq_filter() {
270        let filter = EqFilter {
271            attribute: "cn".to_string(),
272            value: "test".to_string(),
273        };
274        assert_eq!(filter.filter(), "(cn=test)");
275    }
276
277    #[test]
278    fn test_not_eq_filter() {
279        let filter = NotFilter::from(Box::new(EqFilter {
280            attribute: "cn".to_string(),
281            value: "test".to_string(),
282        }));
283        assert_eq!(filter.filter(), "(!(cn=test))");
284    }
285
286    #[test]
287    fn test_pre_like_filter() {
288        let filter = LikeFilter::from("cn".to_string(), "test".to_string(), WildardOn::Pre);
289        assert_eq!(filter.filter(), "(cn=*test)");
290    }
291
292    #[test]
293    fn test_post_like_filter() {
294        let filter = LikeFilter::from("cn".to_string(), "test".to_string(), WildardOn::Post);
295        assert_eq!(filter.filter(), "(cn=test*)");
296    }
297
298    #[test]
299    fn test_or_filter() {
300        let mut or_filter = OrFilter::default();
301        or_filter.add(Box::new(EqFilter {
302            attribute: "cn".to_string(),
303            value: "test".to_string(),
304        }));
305        or_filter.add(Box::new(EqFilter {
306            attribute: "cn".to_string(),
307            value: "test2".to_string(),
308        }));
309        assert_eq!(or_filter.filter(), "(|(cn=test)(cn=test2))");
310    }
311
312    #[test]
313    fn test_and_filter() {
314        let mut and_filter = AndFilter::default();
315        and_filter.add(Box::new(EqFilter {
316            attribute: "cn".to_string(),
317            value: "test".to_string(),
318        }));
319        and_filter.add(Box::new(EqFilter {
320            attribute: "cn".to_string(),
321            value: "test2".to_string(),
322        }));
323        assert_eq!(and_filter.filter(), "(&(cn=test)(cn=test2))");
324    }
325
326    #[test]
327    fn test_contains_filter() {
328        let filter = ContainsFilter::from("cn".to_string(), "test".to_string());
329        assert_eq!(filter.filter(), "(cn=*test*)");
330    }
331}