1use serde::ser::{SerializeSeq, Serializer};
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, PartialEq, Deserialize)]
5pub struct ContainsAllTokensParams {
6 #[serde(skip_serializing_if = "Option::is_none")]
7 pub last_as_prefix: Option<bool>,
8}
9
10#[derive(Debug, Clone, PartialEq)]
11pub enum Filter {
12 Eq { attr: String, value: serde_json::Value },
14 NotEq { attr: String, value: serde_json::Value },
15 Lt { attr: String, value: serde_json::Value },
16 Lte { attr: String, value: serde_json::Value },
17 Gt { attr: String, value: serde_json::Value },
18 Gte { attr: String, value: serde_json::Value },
19
20 AnyLt { attr: String, value: serde_json::Value },
22 AnyLte { attr: String, value: serde_json::Value },
23 AnyGt { attr: String, value: serde_json::Value },
24 AnyGte { attr: String, value: serde_json::Value },
25
26 In { attr: String, values: Vec<serde_json::Value> },
28 NotIn { attr: String, values: Vec<serde_json::Value> },
29 Contains { attr: String, value: serde_json::Value },
30 NotContains { attr: String, value: serde_json::Value },
31 ContainsAny { attr: String, values: Vec<serde_json::Value> },
32 NotContainsAny { attr: String, values: Vec<serde_json::Value> },
33
34 Glob { attr: String, pattern: String },
36 NotGlob { attr: String, pattern: String },
37 IGlob { attr: String, pattern: String },
38 NotIGlob { attr: String, pattern: String },
39 Regex { attr: String, pattern: String },
40
41 ContainsAllTokens { attr: String, value: String, params: Option<ContainsAllTokensParams> },
43 ContainsTokenSequence { attr: String, value: String },
44
45 And(Vec<Filter>),
47 Or(Vec<Filter>),
48 Not(Box<Filter>),
49}
50
51impl Filter {
52 pub fn eq(attr: impl Into<String>, value: impl Into<serde_json::Value>) -> Self {
53 Filter::Eq { attr: attr.into(), value: value.into() }
54 }
55
56 pub fn not_eq(attr: impl Into<String>, value: impl Into<serde_json::Value>) -> Self {
57 Filter::NotEq { attr: attr.into(), value: value.into() }
58 }
59
60 pub fn lt(attr: impl Into<String>, value: impl Into<serde_json::Value>) -> Self {
61 Filter::Lt { attr: attr.into(), value: value.into() }
62 }
63
64 pub fn lte(attr: impl Into<String>, value: impl Into<serde_json::Value>) -> Self {
65 Filter::Lte { attr: attr.into(), value: value.into() }
66 }
67
68 pub fn gt(attr: impl Into<String>, value: impl Into<serde_json::Value>) -> Self {
69 Filter::Gt { attr: attr.into(), value: value.into() }
70 }
71
72 pub fn gte(attr: impl Into<String>, value: impl Into<serde_json::Value>) -> Self {
73 Filter::Gte { attr: attr.into(), value: value.into() }
74 }
75
76 pub fn r#in(attr: impl Into<String>, values: Vec<serde_json::Value>) -> Self {
77 Filter::In { attr: attr.into(), values }
78 }
79
80 pub fn not_in(attr: impl Into<String>, values: Vec<serde_json::Value>) -> Self {
81 Filter::NotIn { attr: attr.into(), values }
82 }
83
84 pub fn contains(attr: impl Into<String>, value: impl Into<serde_json::Value>) -> Self {
85 Filter::Contains { attr: attr.into(), value: value.into() }
86 }
87
88 pub fn contains_any(attr: impl Into<String>, values: Vec<serde_json::Value>) -> Self {
89 Filter::ContainsAny { attr: attr.into(), values }
90 }
91
92 pub fn glob(attr: impl Into<String>, pattern: impl Into<String>) -> Self {
93 Filter::Glob { attr: attr.into(), pattern: pattern.into() }
94 }
95
96 pub fn iglob(attr: impl Into<String>, pattern: impl Into<String>) -> Self {
97 Filter::IGlob { attr: attr.into(), pattern: pattern.into() }
98 }
99
100 pub fn regex(attr: impl Into<String>, pattern: impl Into<String>) -> Self {
101 Filter::Regex { attr: attr.into(), pattern: pattern.into() }
102 }
103
104 pub fn and(filters: Vec<Filter>) -> Self {
105 Filter::And(filters)
106 }
107
108 pub fn or(filters: Vec<Filter>) -> Self {
109 Filter::Or(filters)
110 }
111
112 pub fn not(filter: Filter) -> Self {
113 Filter::Not(Box::new(filter))
114 }
115
116 pub fn contains_all_tokens(attr: impl Into<String>, value: impl Into<String>) -> Self {
117 Filter::ContainsAllTokens {
118 attr: attr.into(),
119 value: value.into(),
120 params: None,
121 }
122 }
123
124 pub fn contains_all_tokens_with_params(
125 attr: impl Into<String>,
126 value: impl Into<String>,
127 params: ContainsAllTokensParams,
128 ) -> Self {
129 Filter::ContainsAllTokens {
130 attr: attr.into(),
131 value: value.into(),
132 params: Some(params),
133 }
134 }
135}
136
137impl Serialize for Filter {
138 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
139 where
140 S: Serializer,
141 {
142 match self {
143 Filter::Eq { attr, value } => {
145 let mut seq = serializer.serialize_seq(Some(3))?;
146 seq.serialize_element(attr)?;
147 seq.serialize_element("Eq")?;
148 seq.serialize_element(value)?;
149 seq.end()
150 }
151 Filter::NotEq { attr, value } => {
152 let mut seq = serializer.serialize_seq(Some(3))?;
153 seq.serialize_element(attr)?;
154 seq.serialize_element("NotEq")?;
155 seq.serialize_element(value)?;
156 seq.end()
157 }
158 Filter::Lt { attr, value } => {
159 let mut seq = serializer.serialize_seq(Some(3))?;
160 seq.serialize_element(attr)?;
161 seq.serialize_element("Lt")?;
162 seq.serialize_element(value)?;
163 seq.end()
164 }
165 Filter::Lte { attr, value } => {
166 let mut seq = serializer.serialize_seq(Some(3))?;
167 seq.serialize_element(attr)?;
168 seq.serialize_element("Lte")?;
169 seq.serialize_element(value)?;
170 seq.end()
171 }
172 Filter::Gt { attr, value } => {
173 let mut seq = serializer.serialize_seq(Some(3))?;
174 seq.serialize_element(attr)?;
175 seq.serialize_element("Gt")?;
176 seq.serialize_element(value)?;
177 seq.end()
178 }
179 Filter::Gte { attr, value } => {
180 let mut seq = serializer.serialize_seq(Some(3))?;
181 seq.serialize_element(attr)?;
182 seq.serialize_element("Gte")?;
183 seq.serialize_element(value)?;
184 seq.end()
185 }
186 Filter::AnyLt { attr, value } => {
187 let mut seq = serializer.serialize_seq(Some(3))?;
188 seq.serialize_element(attr)?;
189 seq.serialize_element("AnyLt")?;
190 seq.serialize_element(value)?;
191 seq.end()
192 }
193 Filter::AnyLte { attr, value } => {
194 let mut seq = serializer.serialize_seq(Some(3))?;
195 seq.serialize_element(attr)?;
196 seq.serialize_element("AnyLte")?;
197 seq.serialize_element(value)?;
198 seq.end()
199 }
200 Filter::AnyGt { attr, value } => {
201 let mut seq = serializer.serialize_seq(Some(3))?;
202 seq.serialize_element(attr)?;
203 seq.serialize_element("AnyGt")?;
204 seq.serialize_element(value)?;
205 seq.end()
206 }
207 Filter::AnyGte { attr, value } => {
208 let mut seq = serializer.serialize_seq(Some(3))?;
209 seq.serialize_element(attr)?;
210 seq.serialize_element("AnyGte")?;
211 seq.serialize_element(value)?;
212 seq.end()
213 }
214 Filter::In { attr, values } => {
215 let mut seq = serializer.serialize_seq(Some(3))?;
216 seq.serialize_element(attr)?;
217 seq.serialize_element("In")?;
218 seq.serialize_element(values)?;
219 seq.end()
220 }
221 Filter::NotIn { attr, values } => {
222 let mut seq = serializer.serialize_seq(Some(3))?;
223 seq.serialize_element(attr)?;
224 seq.serialize_element("NotIn")?;
225 seq.serialize_element(values)?;
226 seq.end()
227 }
228 Filter::Contains { attr, value } => {
229 let mut seq = serializer.serialize_seq(Some(3))?;
230 seq.serialize_element(attr)?;
231 seq.serialize_element("Contains")?;
232 seq.serialize_element(value)?;
233 seq.end()
234 }
235 Filter::NotContains { attr, value } => {
236 let mut seq = serializer.serialize_seq(Some(3))?;
237 seq.serialize_element(attr)?;
238 seq.serialize_element("NotContains")?;
239 seq.serialize_element(value)?;
240 seq.end()
241 }
242 Filter::ContainsAny { attr, values } => {
243 let mut seq = serializer.serialize_seq(Some(3))?;
244 seq.serialize_element(attr)?;
245 seq.serialize_element("ContainsAny")?;
246 seq.serialize_element(values)?;
247 seq.end()
248 }
249 Filter::NotContainsAny { attr, values } => {
250 let mut seq = serializer.serialize_seq(Some(3))?;
251 seq.serialize_element(attr)?;
252 seq.serialize_element("NotContainsAny")?;
253 seq.serialize_element(values)?;
254 seq.end()
255 }
256 Filter::Glob { attr, pattern } => {
257 let mut seq = serializer.serialize_seq(Some(3))?;
258 seq.serialize_element(attr)?;
259 seq.serialize_element("Glob")?;
260 seq.serialize_element(pattern)?;
261 seq.end()
262 }
263 Filter::NotGlob { attr, pattern } => {
264 let mut seq = serializer.serialize_seq(Some(3))?;
265 seq.serialize_element(attr)?;
266 seq.serialize_element("NotGlob")?;
267 seq.serialize_element(pattern)?;
268 seq.end()
269 }
270 Filter::IGlob { attr, pattern } => {
271 let mut seq = serializer.serialize_seq(Some(3))?;
272 seq.serialize_element(attr)?;
273 seq.serialize_element("IGlob")?;
274 seq.serialize_element(pattern)?;
275 seq.end()
276 }
277 Filter::NotIGlob { attr, pattern } => {
278 let mut seq = serializer.serialize_seq(Some(3))?;
279 seq.serialize_element(attr)?;
280 seq.serialize_element("NotIGlob")?;
281 seq.serialize_element(pattern)?;
282 seq.end()
283 }
284 Filter::Regex { attr, pattern } => {
285 let mut seq = serializer.serialize_seq(Some(3))?;
286 seq.serialize_element(attr)?;
287 seq.serialize_element("Regex")?;
288 seq.serialize_element(pattern)?;
289 seq.end()
290 }
291 Filter::ContainsAllTokens { attr, value, params } => {
292 if let Some(p) = params {
293 let mut seq = serializer.serialize_seq(Some(4))?;
294 seq.serialize_element(attr)?;
295 seq.serialize_element("ContainsAllTokens")?;
296 seq.serialize_element(value)?;
297 seq.serialize_element(p)?;
298 seq.end()
299 } else {
300 let mut seq = serializer.serialize_seq(Some(3))?;
301 seq.serialize_element(attr)?;
302 seq.serialize_element("ContainsAllTokens")?;
303 seq.serialize_element(value)?;
304 seq.end()
305 }
306 }
307 Filter::ContainsTokenSequence { attr, value } => {
308 let mut seq = serializer.serialize_seq(Some(3))?;
309 seq.serialize_element(attr)?;
310 seq.serialize_element("ContainsTokenSequence")?;
311 seq.serialize_element(value)?;
312 seq.end()
313 }
314 Filter::And(filters) => {
316 let mut seq = serializer.serialize_seq(Some(2))?;
317 seq.serialize_element("And")?;
318 seq.serialize_element(filters)?;
319 seq.end()
320 }
321 Filter::Or(filters) => {
322 let mut seq = serializer.serialize_seq(Some(2))?;
323 seq.serialize_element("Or")?;
324 seq.serialize_element(filters)?;
325 seq.end()
326 }
327 Filter::Not(filter) => {
328 let mut seq = serializer.serialize_seq(Some(2))?;
329 seq.serialize_element("Not")?;
330 seq.serialize_element(filter)?;
331 seq.end()
332 }
333 }
334 }
335}
336
337impl Serialize for ContainsAllTokensParams {
338 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
339 where
340 S: Serializer,
341 {
342 use serde::ser::SerializeMap;
343 let mut map = serializer.serialize_map(None)?;
344 if let Some(v) = self.last_as_prefix {
345 map.serialize_entry("last_as_prefix", &v)?;
346 }
347 map.end()
348 }
349}
350
351#[cfg(test)]
352mod tests {
353 use super::*;
354
355 #[test]
356 fn test_eq_serialization() {
357 let f = Filter::eq("name", "foo");
358 let json = serde_json::to_string(&f).unwrap();
359 assert_eq!(json, r#"["name","Eq","foo"]"#);
360 }
361
362 #[test]
363 fn test_not_eq_serialization() {
364 let f = Filter::not_eq("status", "deleted");
365 let json = serde_json::to_string(&f).unwrap();
366 assert_eq!(json, r#"["status","NotEq","deleted"]"#);
367 }
368
369 #[test]
370 fn test_comparison_ops() {
371 assert_eq!(
372 serde_json::to_string(&Filter::lt("age", 30)).unwrap(),
373 r#"["age","Lt",30]"#
374 );
375 assert_eq!(
376 serde_json::to_string(&Filter::lte("age", 30)).unwrap(),
377 r#"["age","Lte",30]"#
378 );
379 assert_eq!(
380 serde_json::to_string(&Filter::gt("score", 0.5)).unwrap(),
381 r#"["score","Gt",0.5]"#
382 );
383 assert_eq!(
384 serde_json::to_string(&Filter::gte("score", 0.5)).unwrap(),
385 r#"["score","Gte",0.5]"#
386 );
387 }
388
389 #[test]
390 fn test_and_serialization() {
391 let f = Filter::and(vec![
392 Filter::eq("name", "foo"),
393 Filter::gt("age", 18),
394 ]);
395 let json = serde_json::to_string(&f).unwrap();
396 assert_eq!(json, r#"["And",[["name","Eq","foo"],["age","Gt",18]]]"#);
397 }
398
399 #[test]
400 fn test_or_serialization() {
401 let f = Filter::or(vec![
402 Filter::eq("role", "admin"),
403 Filter::eq("role", "mod"),
404 ]);
405 let json = serde_json::to_string(&f).unwrap();
406 assert_eq!(json, r#"["Or",[["role","Eq","admin"],["role","Eq","mod"]]]"#);
407 }
408
409 #[test]
410 fn test_not_serialization() {
411 let f = Filter::not(Filter::eq("deleted", true));
412 let json = serde_json::to_string(&f).unwrap();
413 assert_eq!(json, r#"["Not",["deleted","Eq",true]]"#);
414 }
415
416 #[test]
417 fn test_in_serialization() {
418 let f = Filter::r#in("status", vec!["active".into(), "pending".into()]);
419 let json = serde_json::to_string(&f).unwrap();
420 assert_eq!(json, r#"["status","In",["active","pending"]]"#);
421 }
422
423 #[test]
424 fn test_not_in_serialization() {
425 let f = Filter::not_in("status", vec!["deleted".into()]);
426 let json = serde_json::to_string(&f).unwrap();
427 assert_eq!(json, r#"["status","NotIn",["deleted"]]"#);
428 }
429
430 #[test]
431 fn test_contains_serialization() {
432 let f = Filter::contains("tags", "rust");
433 let json = serde_json::to_string(&f).unwrap();
434 assert_eq!(json, r#"["tags","Contains","rust"]"#);
435 }
436
437 #[test]
438 fn test_contains_any_serialization() {
439 let f = Filter::contains_any("tags", vec!["rust".into(), "go".into()]);
440 let json = serde_json::to_string(&f).unwrap();
441 assert_eq!(json, r#"["tags","ContainsAny",["rust","go"]]"#);
442 }
443
444 #[test]
445 fn test_glob_serialization() {
446 let f = Filter::glob("name", "a*");
447 let json = serde_json::to_string(&f).unwrap();
448 assert_eq!(json, r#"["name","Glob","a*"]"#);
449 }
450
451 #[test]
452 fn test_iglob_serialization() {
453 let f = Filter::iglob("name", "A*");
454 let json = serde_json::to_string(&f).unwrap();
455 assert_eq!(json, r#"["name","IGlob","A*"]"#);
456 }
457
458 #[test]
459 fn test_regex_serialization() {
460 let f = Filter::regex("email", r".*@.*\.com");
461 let json = serde_json::to_string(&f).unwrap();
462 assert_eq!(json, r#"["email","Regex",".*@.*\\.com"]"#);
463 }
464
465 #[test]
466 fn test_nested_logical_ops() {
467 let f = Filter::and(vec![
468 Filter::or(vec![
469 Filter::eq("a", 1),
470 Filter::eq("b", 2),
471 ]),
472 Filter::not(Filter::eq("c", 3)),
473 ]);
474 let json = serde_json::to_string(&f).unwrap();
475 assert_eq!(
476 json,
477 r#"["And",[["Or",[["a","Eq",1],["b","Eq",2]]],["Not",["c","Eq",3]]]]"#
478 );
479 }
480
481 #[test]
482 fn test_numeric_values() {
483 let f = Filter::eq("count", 42);
484 let json = serde_json::to_string(&f).unwrap();
485 assert_eq!(json, r#"["count","Eq",42]"#);
486
487 let f = Filter::eq("price", 19.99);
488 let json = serde_json::to_string(&f).unwrap();
489 assert_eq!(json, r#"["price","Eq",19.99]"#);
490 }
491
492 #[test]
493 fn test_null_value() {
494 let f = Filter::Eq { attr: "field".into(), value: serde_json::Value::Null };
495 let json = serde_json::to_string(&f).unwrap();
496 assert_eq!(json, r#"["field","Eq",null]"#);
497 }
498}