✨ any + all
This commit is contained in:
parent
b1ad069731
commit
89517943f2
3 changed files with 118 additions and 1 deletions
33
src/lib.rs
33
src/lib.rs
|
@ -197,7 +197,6 @@ pub fn try_matches(
|
|||
obj: &serde_json::Value,
|
||||
) -> Result<bool, FilterError> {
|
||||
let filter = filter.as_object().unwrap();
|
||||
let obj_map = obj.as_object().unwrap();
|
||||
|
||||
// Handle the case where the filter has a single key, such as top level $and, $or, $not
|
||||
if filter.len() == 1 {
|
||||
|
@ -238,6 +237,25 @@ pub fn try_matches(
|
|||
}
|
||||
return Err(FilterError::InvalidFilter);
|
||||
}
|
||||
"$contains" | "$in" => match obj {
|
||||
serde_json::Value::String(str) => return Ok(str.contains(op_arg.as_str().unwrap())),
|
||||
serde_json::Value::Array(values) => {
|
||||
return Ok(values.into_iter().any(|x| x == op_arg))
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
"$any" => {
|
||||
let elem_filter = op_arg;
|
||||
let list = obj.as_array().unwrap();
|
||||
return Ok(list.into_iter().any(|x| matches(&elem_filter, x)));
|
||||
}
|
||||
"$all" => {
|
||||
let elem_filter = json!({ "key": op_arg });
|
||||
let list = obj.as_array().unwrap();
|
||||
return Ok(!list
|
||||
.into_iter()
|
||||
.any(|x| !matches(&elem_filter, &json!({"key": x}))));
|
||||
}
|
||||
_ => {
|
||||
if op.starts_with('$') {
|
||||
return Err(FilterError::UnknownOperator);
|
||||
|
@ -246,6 +264,7 @@ pub fn try_matches(
|
|||
}
|
||||
}
|
||||
|
||||
let obj_map = obj.as_object().unwrap();
|
||||
let mut conditions = vec![];
|
||||
|
||||
for (key, val) in filter {
|
||||
|
@ -509,6 +528,18 @@ fn match_operator(
|
|||
key,
|
||||
);
|
||||
}
|
||||
"$any" => {
|
||||
let elem_filter = op_arg;
|
||||
let list = raw_obj.get(key).unwrap().as_array().unwrap();
|
||||
return Ok(list.into_iter().any(|x| matches(&elem_filter, x)));
|
||||
}
|
||||
"$all" => {
|
||||
let elem_filter = json!({ "key": op_arg });
|
||||
let list = raw_obj.get(key).unwrap().as_array().unwrap();
|
||||
return Ok(!list
|
||||
.into_iter()
|
||||
.any(|x| !matches(&elem_filter, &json!({"key": x}))));
|
||||
}
|
||||
_ => {
|
||||
if op.starts_with('$') {
|
||||
return Err(FilterError::UnknownOperator);
|
||||
|
|
74
src/test.rs
74
src/test.rs
|
@ -3,6 +3,80 @@ mod tests {
|
|||
use crate::matches;
|
||||
use serde_json::json;
|
||||
|
||||
#[test]
|
||||
fn array_element_match() {
|
||||
assert!(matches(
|
||||
&json!(
|
||||
{ "a": { "$contains": 3 }}
|
||||
),
|
||||
&json!({ "a": [1,2,3,4]})
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn array_any_str() {
|
||||
assert!(matches(
|
||||
&json!(
|
||||
{ "a": { "$any": { "$contains": "world"} }}
|
||||
),
|
||||
&json!({ "a": ["hello", "world"]})
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn array_any_sub() {
|
||||
assert!(matches(
|
||||
&json!(
|
||||
{ "a": { "$any": { "key": { "$contains": "world"} }}}
|
||||
),
|
||||
&json!({ "a": [{ "key": "hello" }, {"key": "world"}]})
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn array_all_nested() {
|
||||
assert!(!matches(
|
||||
&json!(
|
||||
{ "key": { "$all": { "$gt": 10} }}
|
||||
),
|
||||
&json!({ "key": [1,2,3,4,5]})
|
||||
));
|
||||
|
||||
assert!(matches(
|
||||
&json!(
|
||||
{ "key": { "$all": { "$gt": 5} }}
|
||||
),
|
||||
&json!({ "key": [6,7,8,9]})
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn array_all_direct() {
|
||||
assert!(!matches(
|
||||
&json!(
|
||||
{ "$all": { "$gt": 10} }
|
||||
),
|
||||
&json!([1, 2, 3, 4, 5])
|
||||
));
|
||||
|
||||
assert!(matches(
|
||||
&json!(
|
||||
{ "$all": { "$gt": 5} }
|
||||
),
|
||||
&json!([6, 7, 8, 9])
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn array_any_direct() {
|
||||
assert!(matches(
|
||||
&json!(
|
||||
{ "$any": { "$contains": "world"} }
|
||||
),
|
||||
&json!(["hello", "world"])
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simple_mask() {
|
||||
assert!(matches(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue