refactor; add order() fn; add examples

This commit is contained in:
JMARyA 2024-02-09 14:34:12 +01:00
parent d1419a2198
commit 6db5f79743
Signed by: jmarya
GPG key ID: 901B2ADDF27C2263
11 changed files with 388 additions and 11 deletions

View file

@ -1,6 +1,73 @@
mod test;
use std::cmp::Ordering;
use serde_json::json;
/// Compares two JSON values `a` and `b` based on their ordering.
///
/// This function evaluates the relationship between the JSON values `a` and `b` using the following criteria:
/// - If `a` is greater than `b`, returns `std::cmp::Ordering::Greater`.
/// - If `a` is less than `b`, returns `std::cmp::Ordering::Less`.
/// - If `a` is equal to `b`, returns `std::cmp::Ordering::Equal`.
///
/// # Arguments
///
/// * `a` - A reference to a `serde_json::Value` representing the first JSON value.
/// * `b` - A reference to a `serde_json::Value` representing the second JSON value.
///
/// # Returns
///
/// Returns `std::cmp::Ordering` indicating the relationship between `a` and `b`.
///
/// # Panics
///
/// This function panics if the values cant be compared.
///
/// # Examples
///
/// ```
/// use serde_json::json;
/// use std::cmp::Ordering;
/// use jsonfilter::order;
///
/// let a = json!(10);
/// let b = json!(5);
/// assert_eq!(order(&a, &b), Ordering::Greater);
/// ```
#[must_use]
pub fn order(a: &serde_json::Value, b: &serde_json::Value) -> std::cmp::Ordering {
if matches(
&serde_json::json!({
"a": { "$gt": b}
}),
&serde_json::json!({
"a": a
}),
) {
Ordering::Greater
} else if matches(
&serde_json::json!({
"a": { "$lt": b}
}),
&serde_json::json!({
"a": a
}),
) {
Ordering::Less
} else if matches(
&serde_json::json!({
"a": b
}),
&serde_json::json!({
"a": a
}),
) {
Ordering::Equal
} else {
unreachable!()
}
}
fn less_than_num(a: &serde_json::Value, b: &serde_json::Value) -> bool {
if a.is_f64() {
let a = a.as_f64().unwrap();
@ -14,8 +81,12 @@ fn less_than_num(a: &serde_json::Value, b: &serde_json::Value) -> bool {
let a = a.as_u64().unwrap();
let b = b.as_u64().unwrap();
a < b
} else if a.is_string() {
let a = a.as_str().unwrap();
let b = b.as_str().unwrap();
a < b
} else {
false
unreachable!()
}
}
@ -32,8 +103,12 @@ fn greater_than_num(a: &serde_json::Value, b: &serde_json::Value) -> bool {
let a = a.as_u64().unwrap();
let b = b.as_u64().unwrap();
a > b
} else if a.is_string() {
let a = a.as_str().unwrap();
let b = b.as_str().unwrap();
a > b
} else {
false
unreachable!()
}
}
@ -89,21 +164,34 @@ pub fn try_matches(
match op.as_str() {
"$and" => {
if let serde_json::Value::Array(and_list) = op_arg {
let and_list_bool: Vec<bool> = and_list
let and_list_bool: Vec<Result<bool, FilterError>> = and_list
.iter()
.map(|sub_filter| matches(sub_filter, obj))
.map(|sub_filter| try_matches(sub_filter, obj))
.collect();
return Ok(!and_list_bool.iter().any(|x| !x));
if let Some(err) = and_list_bool.iter().find(|x| x.is_err()) {
return *err;
}
return Ok(!and_list_bool.iter().map(|x| x.unwrap()).any(|x| !x));
}
return Err(FilterError::InvalidFilter);
}
"$or" => {
if let serde_json::Value::Array(or_list) = op_arg {
let or_list_bool: Vec<bool> = or_list
let or_list_bool: Vec<Result<bool, FilterError>> = or_list
.iter()
.map(|sub_filter| matches(sub_filter, obj))
.map(|sub_filter| try_matches(sub_filter, obj))
.collect();
return Ok(or_list_bool.iter().any(|x| *x));
if let Some(err) = or_list_bool.iter().find(|x| x.is_err()) {
return *err;
}
return Ok(or_list_bool.iter().map(|x| x.unwrap()).any(|x| x));
}
return Err(FilterError::InvalidFilter);
}
"$not" => {
if let Some(inner) = filter.get("$not") {
let new_filter = inner;
return Ok(!try_matches(new_filter, obj)?);
}
return Err(FilterError::InvalidFilter);
}
@ -145,6 +233,10 @@ pub fn try_matches(
}
}
check(&conditions)
}
fn check(conditions: &[Result<bool, FilterError>]) -> Result<bool, FilterError> {
conditions.iter().find(|x| x.is_err()).map_or_else(
|| Ok(!conditions.iter().map(|x| x.unwrap()).any(|x| !x)),
|possible_error| *possible_error,
@ -163,6 +255,32 @@ fn match_operator(
let op = keys.first().unwrap().as_str();
let op_arg = val.get(op).unwrap();
match op {
"$and" => {
if let serde_json::Value::Array(and_list) = op_arg {
let and_list_bool: Vec<Result<bool, FilterError>> = and_list
.iter()
.map(|sub_filter| try_matches(sub_filter, raw_obj))
.collect();
if let Some(err) = and_list_bool.iter().find(|x| x.is_err()) {
return *err;
}
return Ok(!and_list_bool.iter().map(|x| x.unwrap()).any(|x| !x));
}
return Err(FilterError::InvalidFilter);
}
"$or" => {
if let serde_json::Value::Array(or_list) = op_arg {
let or_list_bool: Vec<Result<bool, FilterError>> = or_list
.iter()
.map(|sub_filter| try_matches(sub_filter, raw_obj))
.collect();
if let Some(err) = or_list_bool.iter().find(|x| x.is_err()) {
return *err;
}
return Ok(or_list_bool.iter().map(|x| x.unwrap()).any(|x| x));
}
return Err(FilterError::InvalidFilter);
}
"$lt" => {
if let Some(a) = obj.get(key) {
return Ok(less_than_num(a, op_arg));