latera/builtins/filters/
array.rs

1/// Filters operating on array
2use std::collections::HashMap;
3
4use crate::context::{get_json_pointer, ValueRender};
5use crate::errors::{Error, Result};
6use crate::filter_utils::{get_sort_strategy_for_type, get_unique_strategy_for_type};
7use crate::utils::render_to_string;
8use serde_json::value::{to_value, Map, Value};
9
10/// Returns the nth value of an array
11/// If the array is empty, returns empty string
12pub fn nth(value: &Value, args: &HashMap<String, Value>) -> Result<Value> {
13    let arr = try_get_value!("nth", "value", Vec<Value>, value);
14
15    if arr.is_empty() {
16        return Ok(to_value("").unwrap());
17    }
18
19    let index = match args.get("n") {
20        Some(val) => try_get_value!("nth", "n", usize, val),
21        None => return Err(Error::msg("The `nth` filter has to have an `n` argument")),
22    };
23
24    Ok(arr.get(index).unwrap_or(&to_value("").unwrap()).to_owned())
25}
26
27/// Returns the first value of an array
28/// If the array is empty, returns empty string
29pub fn first(value: &Value, _: &HashMap<String, Value>) -> Result<Value> {
30    let mut arr = try_get_value!("first", "value", Vec<Value>, value);
31
32    if arr.is_empty() {
33        Ok(to_value("").unwrap())
34    } else {
35        Ok(arr.swap_remove(0))
36    }
37}
38
39/// Returns the last value of an array
40/// If the array is empty, returns empty string
41pub fn last(value: &Value, _: &HashMap<String, Value>) -> Result<Value> {
42    let mut arr = try_get_value!("last", "value", Vec<Value>, value);
43
44    Ok(arr.pop().unwrap_or_else(|| to_value("").unwrap()))
45}
46
47/// Joins all values in the array by the `sep` argument given
48/// If no separator is given, it will use `""` (empty string) as separator
49/// If the array is empty, returns empty string
50pub fn join(value: &Value, args: &HashMap<String, Value>) -> Result<Value> {
51    let arr = try_get_value!("join", "value", Vec<Value>, value);
52    let sep = match args.get("sep") {
53        Some(val) => try_get_value!("truncate", "sep", String, val),
54        None => String::new(),
55    };
56
57    // Convert all the values to strings before we join them together.
58    let rendered = arr
59        .iter()
60        .map(|v| render_to_string(|| "joining array".to_string(), |w| v.render(w)))
61        .collect::<Result<Vec<_>>>()?;
62    to_value(&rendered.join(&sep)).map_err(Error::json)
63}
64
65/// Sorts the array in ascending order.
66/// Use the 'attribute' argument to define a field to sort by.
67pub fn sort(value: &Value, args: &HashMap<String, Value>) -> Result<Value> {
68    let arr = try_get_value!("sort", "value", Vec<Value>, value);
69    if arr.is_empty() {
70        return Ok(arr.into());
71    }
72
73    let attribute = match args.get("attribute") {
74        Some(val) => try_get_value!("sort", "attribute", String, val),
75        None => String::new(),
76    };
77    let ptr = match attribute.as_str() {
78        "" => "".to_string(),
79        s => get_json_pointer(s),
80    };
81
82    let first = arr[0].pointer(&ptr).ok_or_else(|| {
83        Error::msg(format!("attribute '{}' does not reference a field", attribute))
84    })?;
85
86    let mut strategy = get_sort_strategy_for_type(first)?;
87    for v in &arr {
88        let key = v.pointer(&ptr).ok_or_else(|| {
89            Error::msg(format!("attribute '{}' does not reference a field", attribute))
90        })?;
91        strategy.try_add_pair(v, key)?;
92    }
93    let sorted = strategy.sort();
94
95    Ok(sorted.into())
96}
97
98/// Remove duplicates from an array.
99/// Use the 'attribute' argument to define a field to filter on.
100/// For strings, use the 'case_sensitive' argument (defaults to false) to control the comparison.
101pub fn unique(value: &Value, args: &HashMap<String, Value>) -> Result<Value> {
102    let arr = try_get_value!("unique", "value", Vec<Value>, value);
103    if arr.is_empty() {
104        return Ok(arr.into());
105    }
106
107    let case_sensitive = match args.get("case_sensitive") {
108        Some(val) => try_get_value!("unique", "case_sensitive", bool, val),
109        None => false,
110    };
111
112    let attribute = match args.get("attribute") {
113        Some(val) => try_get_value!("unique", "attribute", String, val),
114        None => String::new(),
115    };
116    let ptr = match attribute.as_str() {
117        "" => "".to_string(),
118        s => get_json_pointer(s),
119    };
120
121    let first = arr[0].pointer(&ptr).ok_or_else(|| {
122        Error::msg(format!("attribute '{}' does not reference a field", attribute))
123    })?;
124
125    let disc = std::mem::discriminant(first);
126    let mut strategy = get_unique_strategy_for_type(first, case_sensitive)?;
127
128    let arr = arr
129        .into_iter()
130        .filter_map(|v| match v.pointer(&ptr) {
131            Some(key) => {
132                if disc == std::mem::discriminant(key) {
133                    match strategy.insert(key) {
134                        Ok(false) => None,
135                        Ok(true) => Some(Ok(v)),
136                        Err(e) => Some(Err(e)),
137                    }
138                } else {
139                    Some(Err(Error::msg("unique filter can't compare multiple types")))
140                }
141            }
142            None => None,
143        })
144        .collect::<Result<Vec<_>>>();
145
146    Ok(to_value(arr?).unwrap())
147}
148
149/// Group the array values by the `attribute` given
150/// Returns a hashmap of key => values, items without the `attribute` or where `attribute` is `null` are discarded.
151/// The returned keys are stringified
152pub fn group_by(value: &Value, args: &HashMap<String, Value>) -> Result<Value> {
153    let arr = try_get_value!("group_by", "value", Vec<Value>, value);
154    if arr.is_empty() {
155        return Ok(Map::new().into());
156    }
157
158    let key = match args.get("attribute") {
159        Some(val) => try_get_value!("group_by", "attribute", String, val),
160        None => {
161            return Err(Error::msg("The `group_by` filter has to have an `attribute` argument"))
162        }
163    };
164
165    let mut grouped = Map::new();
166    let json_pointer = get_json_pointer(&key);
167
168    for val in arr {
169        if let Some(key_val) = val.pointer(&json_pointer).cloned() {
170            if key_val.is_null() {
171                continue;
172            }
173
174            let str_key = match key_val.as_str() {
175                Some(key) => key.to_owned(),
176                None => format!("{}", key_val),
177            };
178
179            if let Some(vals) = grouped.get_mut(&str_key) {
180                vals.as_array_mut().unwrap().push(val);
181                continue;
182            }
183
184            grouped.insert(str_key, Value::Array(vec![val]));
185        }
186    }
187
188    Ok(to_value(grouped).unwrap())
189}
190
191/// Filter the array values, returning only the values where the `attribute` is equal to the `value`
192/// Values without the `attribute` or with a null `attribute` are discarded
193/// If the `value` is not passed, discard all elements where the attribute is null.
194pub fn filter(value: &Value, args: &HashMap<String, Value>) -> Result<Value> {
195    let mut arr = try_get_value!("filter", "value", Vec<Value>, value);
196    if arr.is_empty() {
197        return Ok(arr.into());
198    }
199
200    let key = match args.get("attribute") {
201        Some(val) => try_get_value!("filter", "attribute", String, val),
202        None => return Err(Error::msg("The `filter` filter has to have an `attribute` argument")),
203    };
204    let value = args.get("value").unwrap_or(&Value::Null);
205
206    let json_pointer = get_json_pointer(&key);
207    arr = arr
208        .into_iter()
209        .filter(|v| {
210            let val = v.pointer(&json_pointer).unwrap_or(&Value::Null);
211            if value.is_null() {
212                !val.is_null()
213            } else {
214                val == value
215            }
216        })
217        .collect::<Vec<_>>();
218
219    Ok(to_value(arr).unwrap())
220}
221
222/// Map retrieves an attribute from a list of objects.
223/// The 'attribute' argument specifies what to retrieve.
224pub fn map(value: &Value, args: &HashMap<String, Value>) -> Result<Value> {
225    let arr = try_get_value!("map", "value", Vec<Value>, value);
226    if arr.is_empty() {
227        return Ok(arr.into());
228    }
229
230    let attribute = match args.get("attribute") {
231        Some(val) => try_get_value!("map", "attribute", String, val),
232        None => return Err(Error::msg("The `map` filter has to have an `attribute` argument")),
233    };
234
235    let json_pointer = get_json_pointer(&attribute);
236    let arr = arr
237        .into_iter()
238        .filter_map(|v| match v.pointer(&json_pointer) {
239            Some(val) if !val.is_null() => Some(val.clone()),
240            _ => None,
241        })
242        .collect::<Vec<_>>();
243
244    Ok(to_value(arr).unwrap())
245}
246
247#[inline]
248fn get_index(i: f64, array: &[Value]) -> usize {
249    if i >= 0.0 {
250        i as usize
251    } else {
252        (array.len() as f64 + i) as usize
253    }
254}
255
256/// Slice the array
257/// Use the `start` argument to define where to start (inclusive, default to `0`)
258/// and `end` argument to define where to stop (exclusive, default to the length of the array)
259/// `start` and `end` are 0-indexed
260pub fn slice(value: &Value, args: &HashMap<String, Value>) -> Result<Value> {
261    let arr = try_get_value!("slice", "value", Vec<Value>, value);
262    if arr.is_empty() {
263        return Ok(arr.into());
264    }
265
266    let start = match args.get("start") {
267        Some(val) => get_index(try_get_value!("slice", "start", f64, val), &arr),
268        None => 0,
269    };
270
271    let mut end = match args.get("end") {
272        Some(val) => get_index(try_get_value!("slice", "end", f64, val), &arr),
273        None => arr.len(),
274    };
275
276    if end > arr.len() {
277        end = arr.len();
278    }
279
280    // Not an error, but returns an empty Vec
281    if start >= end {
282        return Ok(Vec::<Value>::new().into());
283    }
284
285    Ok(arr[start..end].into())
286}
287
288/// Concat the array with another one if the `with` parameter is an array or
289/// just append it otherwise
290pub fn concat(value: &Value, args: &HashMap<String, Value>) -> Result<Value> {
291    let mut arr = try_get_value!("concat", "value", Vec<Value>, value);
292
293    let value = match args.get("with") {
294        Some(val) => val,
295        None => return Err(Error::msg("The `concat` filter has to have a `with` argument")),
296    };
297
298    if value.is_array() {
299        match value {
300            Value::Array(vals) => {
301                for val in vals {
302                    arr.push(val.clone());
303                }
304            }
305            _ => unreachable!("Got something other than an array??"),
306        }
307    } else {
308        arr.push(value.clone());
309    }
310
311    Ok(to_value(arr).unwrap())
312}
313
314#[cfg(test)]
315mod tests {
316    use super::*;
317    use serde_derive::{Deserialize, Serialize};
318    use serde_json::json;
319    use serde_json::value::{to_value, Value};
320    use std::collections::HashMap;
321
322    #[test]
323    fn test_nth() {
324        let mut args = HashMap::new();
325        args.insert("n".to_string(), to_value(1).unwrap());
326        let result = nth(&to_value(&vec![1, 2, 3, 4]).unwrap(), &args);
327        assert!(result.is_ok());
328        assert_eq!(result.unwrap(), to_value(&2).unwrap());
329    }
330
331    #[test]
332    fn test_nth_empty() {
333        let v: Vec<Value> = Vec::new();
334        let mut args = HashMap::new();
335        args.insert("n".to_string(), to_value(1).unwrap());
336        let result = nth(&to_value(&v).unwrap(), &args);
337        assert!(result.is_ok());
338        assert_eq!(result.unwrap(), to_value("").unwrap());
339    }
340
341    #[test]
342    fn test_first() {
343        let result = first(&to_value(&vec![1, 2, 3, 4]).unwrap(), &HashMap::new());
344        assert!(result.is_ok());
345        assert_eq!(result.unwrap(), to_value(&1).unwrap());
346    }
347
348    #[test]
349    fn test_first_empty() {
350        let v: Vec<Value> = Vec::new();
351
352        let result = first(&to_value(&v).unwrap(), &HashMap::new());
353        assert!(result.is_ok());
354        assert_eq!(result.ok().unwrap(), to_value("").unwrap());
355    }
356
357    #[test]
358    fn test_last() {
359        let result = last(&to_value(&vec!["Hello", "World"]).unwrap(), &HashMap::new());
360        assert!(result.is_ok());
361        assert_eq!(result.unwrap(), to_value("World").unwrap());
362    }
363
364    #[test]
365    fn test_last_empty() {
366        let v: Vec<Value> = Vec::new();
367
368        let result = last(&to_value(&v).unwrap(), &HashMap::new());
369        assert!(result.is_ok());
370        assert_eq!(result.ok().unwrap(), to_value("").unwrap());
371    }
372
373    #[test]
374    fn test_join_sep() {
375        let mut args = HashMap::new();
376        args.insert("sep".to_owned(), to_value(&"==").unwrap());
377
378        let result = join(&to_value(&vec!["Cats", "Dogs"]).unwrap(), &args);
379        assert!(result.is_ok());
380        assert_eq!(result.unwrap(), to_value(&"Cats==Dogs").unwrap());
381    }
382
383    #[test]
384    fn test_join_sep_omitted() {
385        let result = join(&to_value(&vec![1.2, 3.4]).unwrap(), &HashMap::new());
386        assert!(result.is_ok());
387        assert_eq!(result.unwrap(), to_value(&"1.23.4").unwrap());
388    }
389
390    #[test]
391    fn test_join_empty() {
392        let v: Vec<Value> = Vec::new();
393        let mut args = HashMap::new();
394        args.insert("sep".to_owned(), to_value(&"==").unwrap());
395
396        let result = join(&to_value(&v).unwrap(), &args);
397        assert!(result.is_ok());
398        assert_eq!(result.unwrap(), to_value(&"").unwrap());
399    }
400
401    #[test]
402    fn test_sort() {
403        let v = to_value(vec![3, -1, 2, 5, 4]).unwrap();
404        let args = HashMap::new();
405        let result = sort(&v, &args);
406        assert!(result.is_ok());
407        assert_eq!(result.unwrap(), to_value(vec![-1, 2, 3, 4, 5]).unwrap());
408    }
409
410    #[test]
411    fn test_sort_empty() {
412        let v = to_value(Vec::<f64>::new()).unwrap();
413        let args = HashMap::new();
414        let result = sort(&v, &args);
415        assert!(result.is_ok());
416        assert_eq!(result.unwrap(), to_value(Vec::<f64>::new()).unwrap());
417    }
418
419    #[derive(Deserialize, Eq, Hash, PartialEq, Serialize)]
420    struct Foo {
421        a: i32,
422        b: i32,
423    }
424
425    #[test]
426    fn test_sort_attribute() {
427        let v = to_value(vec![
428            Foo { a: 3, b: 5 },
429            Foo { a: 2, b: 8 },
430            Foo { a: 4, b: 7 },
431            Foo { a: 1, b: 6 },
432        ])
433        .unwrap();
434        let mut args = HashMap::new();
435        args.insert("attribute".to_string(), to_value(&"a").unwrap());
436
437        let result = sort(&v, &args);
438        assert!(result.is_ok());
439        assert_eq!(
440            result.unwrap(),
441            to_value(vec![
442                Foo { a: 1, b: 6 },
443                Foo { a: 2, b: 8 },
444                Foo { a: 3, b: 5 },
445                Foo { a: 4, b: 7 },
446            ])
447            .unwrap()
448        );
449    }
450
451    #[test]
452    fn test_sort_invalid_attribute() {
453        let v = to_value(vec![Foo { a: 3, b: 5 }]).unwrap();
454        let mut args = HashMap::new();
455        args.insert("attribute".to_string(), to_value(&"invalid_field").unwrap());
456
457        let result = sort(&v, &args);
458        assert!(result.is_err());
459        assert_eq!(
460            result.unwrap_err().to_string(),
461            "attribute 'invalid_field' does not reference a field"
462        );
463    }
464
465    #[test]
466    fn test_sort_multiple_types() {
467        let v = to_value(vec![Value::Number(12.into()), Value::Array(vec![])]).unwrap();
468        let args = HashMap::new();
469
470        let result = sort(&v, &args);
471        assert!(result.is_err());
472        assert_eq!(result.unwrap_err().to_string(), "expected number got []");
473    }
474
475    #[test]
476    fn test_sort_non_finite_numbers() {
477        let v = to_value(vec![
478            ::std::f64::NEG_INFINITY, // NaN and friends get deserialized as Null by serde.
479            ::std::f64::NAN,
480        ])
481        .unwrap();
482        let args = HashMap::new();
483
484        let result = sort(&v, &args);
485        assert!(result.is_err());
486        assert_eq!(result.unwrap_err().to_string(), "Null is not a sortable value");
487    }
488
489    #[derive(Deserialize, Eq, Hash, PartialEq, Serialize)]
490    struct TupleStruct(i32, i32);
491
492    #[test]
493    fn test_sort_tuple() {
494        let v = to_value(vec![
495            TupleStruct(0, 1),
496            TupleStruct(7, 0),
497            TupleStruct(-1, 12),
498            TupleStruct(18, 18),
499        ])
500        .unwrap();
501        let mut args = HashMap::new();
502        args.insert("attribute".to_string(), to_value("0").unwrap());
503
504        let result = sort(&v, &args);
505        assert!(result.is_ok());
506        assert_eq!(
507            result.unwrap(),
508            to_value(vec![
509                TupleStruct(-1, 12),
510                TupleStruct(0, 1),
511                TupleStruct(7, 0),
512                TupleStruct(18, 18),
513            ])
514            .unwrap()
515        );
516    }
517
518    #[test]
519    fn test_unique_numbers() {
520        let v = to_value(vec![3, -1, 3, 3, 5, 2, 5, 4]).unwrap();
521        let args = HashMap::new();
522        let result = unique(&v, &args);
523        assert!(result.is_ok());
524        assert_eq!(result.unwrap(), to_value(vec![3, -1, 5, 2, 4]).unwrap());
525    }
526
527    #[test]
528    fn test_unique_strings() {
529        let v = to_value(vec!["One", "Two", "Three", "one", "Two"]).unwrap();
530        let mut args = HashMap::new();
531        let result = unique(&v, &args);
532        assert!(result.is_ok());
533        assert_eq!(result.unwrap(), to_value(vec!["One", "Two", "Three"]).unwrap());
534
535        args.insert("case_sensitive".to_string(), to_value(true).unwrap());
536        let result = unique(&v, &args);
537        assert!(result.is_ok());
538        assert_eq!(result.unwrap(), to_value(vec!["One", "Two", "Three", "one"]).unwrap());
539    }
540
541    #[test]
542    fn test_unique_empty() {
543        let v = to_value(Vec::<f64>::new()).unwrap();
544        let args = HashMap::new();
545        let result = sort(&v, &args);
546        assert!(result.is_ok());
547        assert_eq!(result.unwrap(), to_value(Vec::<f64>::new()).unwrap());
548    }
549
550    #[test]
551    fn test_unique_attribute() {
552        let v = to_value(vec![
553            Foo { a: 1, b: 2 },
554            Foo { a: 3, b: 3 },
555            Foo { a: 1, b: 3 },
556            Foo { a: 0, b: 4 },
557        ])
558        .unwrap();
559        let mut args = HashMap::new();
560        args.insert("attribute".to_string(), to_value(&"a").unwrap());
561
562        let result = unique(&v, &args);
563        assert!(result.is_ok());
564        assert_eq!(
565            result.unwrap(),
566            to_value(vec![Foo { a: 1, b: 2 }, Foo { a: 3, b: 3 }, Foo { a: 0, b: 4 },]).unwrap()
567        );
568    }
569
570    #[test]
571    fn test_unique_invalid_attribute() {
572        let v = to_value(vec![Foo { a: 3, b: 5 }]).unwrap();
573        let mut args = HashMap::new();
574        args.insert("attribute".to_string(), to_value(&"invalid_field").unwrap());
575
576        let result = unique(&v, &args);
577        assert!(result.is_err());
578        assert_eq!(
579            result.unwrap_err().to_string(),
580            "attribute 'invalid_field' does not reference a field"
581        );
582    }
583
584    #[test]
585    fn test_unique_multiple_types() {
586        let v = to_value(vec![Value::Number(12.into()), Value::Array(vec![])]).unwrap();
587        let args = HashMap::new();
588
589        let result = unique(&v, &args);
590        assert!(result.is_err());
591        assert_eq!(result.unwrap_err().to_string(), "unique filter can't compare multiple types");
592    }
593
594    #[test]
595    fn test_unique_non_finite_numbers() {
596        let v = to_value(vec![
597            ::std::f64::NEG_INFINITY, // NaN and friends get deserialized as Null by serde.
598            ::std::f64::NAN,
599        ])
600        .unwrap();
601        let args = HashMap::new();
602
603        let result = unique(&v, &args);
604        assert!(result.is_err());
605        assert_eq!(result.unwrap_err().to_string(), "Null is not a unique value");
606    }
607
608    #[test]
609    fn test_unique_tuple() {
610        let v = to_value(vec![
611            TupleStruct(0, 1),
612            TupleStruct(-7, -1),
613            TupleStruct(-1, 1),
614            TupleStruct(18, 18),
615        ])
616        .unwrap();
617        let mut args = HashMap::new();
618        args.insert("attribute".to_string(), to_value("1").unwrap());
619
620        let result = unique(&v, &args);
621        assert!(result.is_ok());
622        assert_eq!(
623            result.unwrap(),
624            to_value(vec![TupleStruct(0, 1), TupleStruct(-7, -1), TupleStruct(18, 18),]).unwrap()
625        );
626    }
627
628    #[test]
629    fn test_slice() {
630        fn make_args(start: Option<usize>, end: Option<f64>) -> HashMap<String, Value> {
631            let mut args = HashMap::new();
632            if let Some(s) = start {
633                args.insert("start".to_string(), to_value(s).unwrap());
634            }
635            if let Some(e) = end {
636                args.insert("end".to_string(), to_value(e).unwrap());
637            }
638            args
639        }
640
641        let v = to_value(vec![1, 2, 3, 4, 5]).unwrap();
642
643        let inputs = vec![
644            (make_args(Some(1), None), vec![2, 3, 4, 5]),
645            (make_args(None, Some(2.0)), vec![1, 2]),
646            (make_args(Some(1), Some(2.0)), vec![2]),
647            (make_args(None, Some(-2.0)), vec![1, 2, 3]),
648            (make_args(None, None), vec![1, 2, 3, 4, 5]),
649            (make_args(Some(3), Some(1.0)), vec![]),
650            (make_args(Some(9), None), vec![]),
651        ];
652
653        for (args, expected) in inputs {
654            let res = slice(&v, &args);
655            assert!(res.is_ok());
656            assert_eq!(res.unwrap(), to_value(expected).unwrap());
657        }
658    }
659
660    #[test]
661    fn test_group_by() {
662        let input = json!([
663            {"id": 1, "year": 2015},
664            {"id": 2, "year": 2015},
665            {"id": 3, "year": 2016},
666            {"id": 4, "year": 2017},
667            {"id": 5, "year": 2017},
668            {"id": 6, "year": 2017},
669            {"id": 7, "year": 2018},
670            {"id": 8},
671            {"id": 9, "year": null},
672        ]);
673        let mut args = HashMap::new();
674        args.insert("attribute".to_string(), to_value("year").unwrap());
675
676        let expected = json!({
677            "2015": [{"id": 1, "year": 2015}, {"id": 2, "year": 2015}],
678            "2016": [{"id": 3, "year": 2016}],
679            "2017": [{"id": 4, "year": 2017}, {"id": 5, "year": 2017}, {"id": 6, "year": 2017}],
680            "2018": [{"id": 7, "year": 2018}],
681        });
682
683        let res = group_by(&input, &args);
684        assert!(res.is_ok());
685        assert_eq!(res.unwrap(), to_value(expected).unwrap());
686    }
687
688    #[test]
689    fn test_group_by_nested_key() {
690        let input = json!([
691            {"id": 1, "company": {"id": 1}},
692            {"id": 2, "company": {"id": 2}},
693            {"id": 3, "company": {"id": 3}},
694            {"id": 4, "company": {"id": 4}},
695            {"id": 5, "company": {"id": 4}},
696            {"id": 6, "company": {"id": 5}},
697            {"id": 7, "company": {"id": 5}},
698            {"id": 8},
699            {"id": 9, "company": null},
700        ]);
701        let mut args = HashMap::new();
702        args.insert("attribute".to_string(), to_value("company.id").unwrap());
703
704        let expected = json!({
705            "1": [{"id": 1, "company": {"id": 1}}],
706            "2": [{"id": 2, "company": {"id": 2}}],
707            "3": [{"id": 3, "company": {"id": 3}}],
708            "4": [{"id": 4, "company": {"id": 4}}, {"id": 5, "company": {"id": 4}}],
709            "5": [{"id": 6, "company": {"id": 5}}, {"id": 7, "company": {"id": 5}}],
710        });
711
712        let res = group_by(&input, &args);
713        assert!(res.is_ok());
714        assert_eq!(res.unwrap(), to_value(expected).unwrap());
715    }
716
717    #[test]
718    fn test_filter_empty() {
719        let res = filter(&json!([]), &HashMap::new());
720        assert!(res.is_ok());
721        assert_eq!(res.unwrap(), json!([]));
722    }
723
724    #[test]
725    fn test_filter() {
726        let input = json!([
727            {"id": 1, "year": 2015},
728            {"id": 2, "year": 2015},
729            {"id": 3, "year": 2016},
730            {"id": 4, "year": 2017},
731            {"id": 5, "year": 2017},
732            {"id": 6, "year": 2017},
733            {"id": 7, "year": 2018},
734            {"id": 8},
735            {"id": 9, "year": null},
736        ]);
737        let mut args = HashMap::new();
738        args.insert("attribute".to_string(), to_value("year").unwrap());
739        args.insert("value".to_string(), to_value(2015).unwrap());
740
741        let expected = json!([
742            {"id": 1, "year": 2015},
743            {"id": 2, "year": 2015},
744        ]);
745
746        let res = filter(&input, &args);
747        assert!(res.is_ok());
748        assert_eq!(res.unwrap(), to_value(expected).unwrap());
749    }
750
751    #[test]
752    fn test_filter_no_value() {
753        let input = json!([
754            {"id": 1, "year": 2015},
755            {"id": 2, "year": 2015},
756            {"id": 3, "year": 2016},
757            {"id": 4, "year": 2017},
758            {"id": 5, "year": 2017},
759            {"id": 6, "year": 2017},
760            {"id": 7, "year": 2018},
761            {"id": 8},
762            {"id": 9, "year": null},
763        ]);
764        let mut args = HashMap::new();
765        args.insert("attribute".to_string(), to_value("year").unwrap());
766
767        let expected = json!([
768            {"id": 1, "year": 2015},
769            {"id": 2, "year": 2015},
770            {"id": 3, "year": 2016},
771            {"id": 4, "year": 2017},
772            {"id": 5, "year": 2017},
773            {"id": 6, "year": 2017},
774            {"id": 7, "year": 2018},
775        ]);
776
777        let res = filter(&input, &args);
778        assert!(res.is_ok());
779        assert_eq!(res.unwrap(), to_value(expected).unwrap());
780    }
781
782    #[test]
783    fn test_map_empty() {
784        let res = map(&json!([]), &HashMap::new());
785        assert!(res.is_ok());
786        assert_eq!(res.unwrap(), json!([]));
787    }
788
789    #[test]
790    fn test_map() {
791        let input = json!([
792            {"id": 1, "year": 2015},
793            {"id": 2, "year": true},
794            {"id": 3, "year": 2016.5},
795            {"id": 4, "year": "2017"},
796            {"id": 5, "year": 2017},
797            {"id": 6, "year": 2017},
798            {"id": 7, "year": [1900, 1901]},
799            {"id": 8, "year": {"a": 2018, "b": 2019}},
800            {"id": 9},
801            {"id": 10, "year": null},
802        ]);
803        let mut args = HashMap::new();
804        args.insert("attribute".to_string(), to_value("year").unwrap());
805
806        let expected =
807            json!([2015, true, 2016.5, "2017", 2017, 2017, [1900, 1901], {"a": 2018, "b": 2019}]);
808
809        let res = map(&input, &args);
810        assert!(res.is_ok());
811        assert_eq!(res.unwrap(), to_value(expected).unwrap());
812    }
813
814    #[test]
815    fn test_concat_array() {
816        let input = json!([1, 2, 3,]);
817        let mut args = HashMap::new();
818        args.insert("with".to_string(), json!([3, 4]));
819        let expected = json!([1, 2, 3, 3, 4,]);
820
821        let res = concat(&input, &args);
822        assert!(res.is_ok());
823        assert_eq!(res.unwrap(), to_value(expected).unwrap());
824    }
825
826    #[test]
827    fn test_concat_single_value() {
828        let input = json!([1, 2, 3,]);
829        let mut args = HashMap::new();
830        args.insert("with".to_string(), json!(4));
831        let expected = json!([1, 2, 3, 4,]);
832
833        let res = concat(&input, &args);
834        assert!(res.is_ok());
835        assert_eq!(res.unwrap(), to_value(expected).unwrap());
836    }
837}