jsonpath_rust/path/
json.rs

1use crate::path::config::cache::{RegexCache, RegexCacheInst};
2use regex::Regex;
3use serde_json::Value;
4
5/// compare sizes of json elements
6/// The method expects to get a number on the right side and array or string or object on the left
7/// where the number of characters, elements or fields will be compared respectively.
8pub fn size(left: Vec<&Value>, right: Vec<&Value>) -> bool {
9    if let Some(Value::Number(n)) = right.first() {
10        if let Some(sz) = n.as_f64() {
11            for el in left.iter() {
12                match el {
13                    Value::String(v) if v.len() == sz as usize => true,
14                    Value::Array(elems) if elems.len() == sz as usize => true,
15                    Value::Object(fields) if fields.len() == sz as usize => true,
16                    _ => return false,
17                };
18            }
19            return true;
20        }
21    }
22    false
23}
24
25/// ensure the array on the left side is a subset of the array on the right side.
26//todo change the naive impl to sets
27pub fn sub_set_of(left: Vec<&Value>, right: Vec<&Value>) -> bool {
28    if left.is_empty() {
29        return true;
30    }
31    if right.is_empty() {
32        return false;
33    }
34
35    if let Some(elems) = left.first().and_then(|e| e.as_array()) {
36        if let Some(Value::Array(right_elems)) = right.first() {
37            if right_elems.is_empty() {
38                return false;
39            }
40
41            for el in elems {
42                let mut res = false;
43
44                for r in right_elems.iter() {
45                    if el.eq(r) {
46                        res = true
47                    }
48                }
49                if !res {
50                    return false;
51                }
52            }
53            return true;
54        }
55    }
56    false
57}
58
59/// ensure at least one element in the array  on the left side belongs to the array on the right side.
60//todo change the naive impl to sets
61pub fn any_of(left: Vec<&Value>, right: Vec<&Value>) -> bool {
62    if left.is_empty() {
63        return true;
64    }
65    if right.is_empty() {
66        return false;
67    }
68
69    if let Some(Value::Array(elems)) = right.first() {
70        if elems.is_empty() {
71            return false;
72        }
73
74        for el in left.iter() {
75            if let Some(left_elems) = el.as_array() {
76                for l in left_elems.iter() {
77                    for r in elems.iter() {
78                        if l.eq(r) {
79                            return true;
80                        }
81                    }
82                }
83            } else {
84                for r in elems.iter() {
85                    if el.eq(&r) {
86                        return true;
87                    }
88                }
89            }
90        }
91    }
92
93    false
94}
95
96/// ensure that the element on the left sides matches the regex on the right side
97pub fn regex(
98    left: Vec<&Value>,
99    right: Vec<&Value>,
100    cache: &RegexCache<impl RegexCacheInst + Clone>,
101) -> bool {
102    if left.is_empty() || right.is_empty() {
103        return false;
104    }
105
106    match right.first() {
107        Some(Value::String(str)) => {
108            if cache.is_implemented() {
109                cache
110                    .get_instance()
111                    .and_then(|inst| inst.validate(str, left))
112                    .unwrap_or(false)
113            } else if let Ok(regex) = Regex::new(str) {
114                for el in left.iter() {
115                    if let Some(v) = el.as_str() {
116                        if regex.is_match(v) {
117                            return true;
118                        }
119                    }
120                }
121                false
122            } else {
123                false
124            }
125        }
126        _ => false,
127    }
128}
129
130/// ensure that the element on the left side belongs to the array on the right side.
131pub fn inside(left: Vec<&Value>, right: Vec<&Value>) -> bool {
132    if left.is_empty() {
133        return false;
134    }
135
136    match right.first() {
137        Some(Value::Array(elems)) => {
138            for el in left.iter() {
139                if elems.contains(el) {
140                    return true;
141                }
142            }
143            false
144        }
145        Some(Value::Object(elems)) => {
146            for el in left.iter() {
147                for r in elems.values() {
148                    if el.eq(&r) {
149                        return true;
150                    }
151                }
152            }
153            false
154        }
155        _ => false,
156    }
157}
158
159/// ensure the number on the left side is less the number on the right side
160pub fn less(left: Vec<&Value>, right: Vec<&Value>) -> bool {
161    if left.len() == 1 && right.len() == 1 {
162        match (left.first(), right.first()) {
163            (Some(Value::Number(l)), Some(Value::Number(r))) => l
164                .as_f64()
165                .and_then(|v1| r.as_f64().map(|v2| v1 < v2))
166                .unwrap_or(false),
167            _ => false,
168        }
169    } else {
170        false
171    }
172}
173
174/// compare elements
175pub fn eq(left: Vec<&Value>, right: Vec<&Value>) -> bool {
176    if left.len() != right.len() {
177        false
178    } else {
179        left.iter().zip(right).map(|(a, b)| a.eq(&b)).all(|a| a)
180    }
181}
182
183#[cfg(test)]
184mod tests {
185    use crate::path::config::cache::RegexCache;
186    use crate::path::json::{any_of, eq, less, regex, size, sub_set_of};
187    use serde_json::{json, Value};
188
189    #[test]
190    fn value_eq_test() {
191        let left = json!({"value":42});
192        let right = json!({"value":42});
193        let right_uneq = json!([42]);
194
195        assert!(&left.eq(&right));
196        assert!(!&left.eq(&right_uneq));
197    }
198
199    #[test]
200    fn vec_value_test() {
201        let left = json!({"value":42});
202        let left1 = json!(42);
203        let left2 = json!([1, 2, 3]);
204        let left3 = json!({"value2":[42],"value":[42]});
205
206        let right = json!({"value":42});
207        let right1 = json!(42);
208        let right2 = json!([1, 2, 3]);
209        let right3 = json!({"value":[42],"value2":[42]});
210
211        assert!(eq(vec![&left], vec![&right]));
212
213        assert!(!eq(vec![], vec![&right]));
214        assert!(!eq(vec![&right], vec![]));
215
216        assert!(eq(
217            vec![&left, &left1, &left2, &left3],
218            vec![&right, &right1, &right2, &right3],
219        ));
220
221        assert!(!eq(
222            vec![&left1, &left, &left2, &left3],
223            vec![&right, &right1, &right2, &right3],
224        ));
225    }
226
227    #[test]
228    fn less_value_test() {
229        let left = json!(10);
230        let right = json!(11);
231
232        assert!(less(vec![&left], vec![&right]));
233        assert!(!less(vec![&right], vec![&left]));
234
235        let left = json!(-10);
236        let right = json!(-11);
237
238        assert!(!less(vec![&left], vec![&right]));
239        assert!(less(vec![&right], vec![&left]));
240
241        let left = json!(-10.0);
242        let right = json!(-11.0);
243
244        assert!(!less(vec![&left], vec![&right]));
245        assert!(less(vec![&right], vec![&left]));
246
247        assert!(!less(vec![], vec![&right]));
248        assert!(!less(vec![&right, &right], vec![&left]));
249    }
250
251    #[test]
252    fn regex_test() {
253        let right = json!("[a-zA-Z]+[0-9]#[0-9]+");
254        let left1 = json!("a11#");
255        let left2 = json!("a1#1");
256        let left3 = json!("a#11");
257        let left4 = json!("#a11");
258
259        assert!(regex(
260            vec![&left1, &left2, &left3, &left4],
261            vec![&right],
262            &RegexCache::default()
263        ));
264        assert!(!regex(
265            vec![&left1, &left3, &left4],
266            vec![&right],
267            &RegexCache::default()
268        ))
269    }
270
271    #[test]
272    fn any_of_test() {
273        let right = json!([1, 2, 3, 4, 5, 6]);
274        let left = json!([1, 100, 101]);
275        assert!(any_of(vec![&left], vec![&right]));
276
277        let left = json!([11, 100, 101]);
278        assert!(!any_of(vec![&left], vec![&right]));
279
280        let left1 = json!(1);
281        let left2 = json!(11);
282        assert!(any_of(vec![&left1, &left2], vec![&right]));
283    }
284
285    #[test]
286    fn sub_set_of_test() {
287        let left1 = json!(1);
288        let left2 = json!(2);
289        let left3 = json!(3);
290        let left40 = json!(40);
291        let right = json!([1, 2, 3, 4, 5, 6]);
292        assert!(sub_set_of(
293            vec![&Value::Array(vec![
294                left1.clone(),
295                left2.clone(),
296                left3.clone(),
297            ])],
298            vec![&right],
299        ));
300        assert!(!sub_set_of(
301            vec![&Value::Array(vec![left1, left2, left3, left40])],
302            vec![&right],
303        ));
304    }
305
306    #[test]
307    fn size_test() {
308        let left1 = json!("abc");
309        let left2 = json!([1, 2, 3]);
310        let left3 = json!([1, 2, 3, 4]);
311        let right = json!(3);
312        assert!(size(vec![&left1], vec![&right]));
313        assert!(size(vec![&left2], vec![&right]));
314        assert!(!size(vec![&left3], vec![&right]));
315    }
316}