From b1ad069731586b4ebd3e484d432d3fef87d315da Mon Sep 17 00:00:00 2001 From: JMARyA Date: Tue, 6 May 2025 23:43:23 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20updates?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/filter.md | 27 +++++++++++++++++--- examples/range.rs | 3 ++- src/lib.rs | 28 ++++++++++++++++++--- src/test.rs | 64 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 114 insertions(+), 8 deletions(-) diff --git a/docs/filter.md b/docs/filter.md index 52bb623..e022b98 100644 --- a/docs/filter.md +++ b/docs/filter.md @@ -40,10 +40,10 @@ This filter would match all of these objects: ``` but not: ```json -{ "key": "Lol"} +{ "key": "lol"} ``` -## Operators +## Logical Operators ### `$and` Chain multiple filters together. All must evaluate to `true` ```json @@ -72,6 +72,7 @@ Inverts the result of the nested filter expression. { "$not": { "key": "value" }} ``` +## Comparison Operators ### `$lt` & `$lte` Evaluates to `true` if the value is less than or less than equal the specified value. ```json @@ -90,7 +91,10 @@ Evaluates to `true` if the value is not equal to the specified value. { "key": { "$ne": "value" }} ``` -### `$in` +> **Note**: The `$eq` operator is implicit. Example: `{ "key": "value" }` + +## Array / Object Operators +### `$in` & `$contains` Evaluates to `true` if the value exists in the specified array. ```json { "array": { "$in": "value" }} @@ -115,12 +119,20 @@ Evaluates to `true` if the array length matches the specified value { "array": { "$size": 5 }} ``` +## Text Operators ### `$regex` Evaluates to `true` if the value matches the regular expression pattern. ```json { "key": { "$regex": "^regex" }} ``` +### `$contains` +Evaluates to `true` if the value contains the text. +```json +{ "key": { "$contains": "text" }} +``` + +## Misc Operators ### `$type` Evaluates to `true` if the value matches the specified type. ```json @@ -130,4 +142,11 @@ Evaluates to `true` if the value matches the specified type. { "key": { "$type": "object" }} { "key": { "$type": "array" }} { "key": { "$type": "boolean" }} -``` \ No newline at end of file +``` + +### `$range` +Evaluates to `true` if the value is within the specified range. This operator is actually just syntactic sugar for `let filter = json!({"$and": [{"key": {"$gte": x}}, {"key": {"$lte": y}}]});`. + +```json +{"key": { "$range": [x, y] }} +``` diff --git a/examples/range.rs b/examples/range.rs index 01c9a64..678c09f 100644 --- a/examples/range.rs +++ b/examples/range.rs @@ -2,7 +2,8 @@ use jsonfilter::{try_matches, FilterError}; use serde_json::{json, Value}; fn main() { - let filter = json!({"$and": [{"age": {"$gte": 18}}, {"age": {"$lte": 30}}]}); + let filter = json!({"age": { "$range": [18, 30] }}); // same as: + // let filter = json!({"$and": [{"age": {"$gte": 18}}, {"age": {"$lte": 30}}]}); let obj1 = json!({"name": "John Doe", "age": 25}); let obj2 = json!({"name": "Alice Smith", "age": 35}); diff --git a/src/lib.rs b/src/lib.rs index 4101ee5..bfc3c02 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -402,10 +402,18 @@ fn match_operator( } return Err(FilterError::KeyNotFound); } - "$in" => { + "$in" | "$contains" => { if let Some(valb) = obj.get(key) { - if let serde_json::Value::Array(list) = valb { - return Ok(list.iter().any(|x| x == op_arg)); + match valb { + serde_json::Value::String(str) => { + if let serde_json::Value::String(op_arg) = op_arg { + return Ok(str.contains(op_arg)); + } + } + serde_json::Value::Array(list) => { + return Ok(list.iter().any(|x| x == op_arg)); + } + _ => {} } return Err(FilterError::InvalidFilter); } @@ -487,6 +495,20 @@ fn match_operator( } return Err(FilterError::KeyNotFound); } + "$range" => { + let x = op_arg.as_array().unwrap().get(0).unwrap(); + let y = op_arg.as_array().unwrap().get(1).unwrap(); + return match_operator( + &json!({ + "$and": [ + { key: { "$gte": x}}, + { key: { "$lte": y}} + ] + }), + raw_obj, + key, + ); + } _ => { if op.starts_with('$') { return Err(FilterError::UnknownOperator); diff --git a/src/test.rs b/src/test.rs index 7677fda..941b2a8 100644 --- a/src/test.rs +++ b/src/test.rs @@ -109,6 +109,70 @@ mod tests { )); } + #[test] + fn text_contains() { + assert!(matches( + &json!({ + "key": { + "$contains": "world" + } + }), + &json!({ + "key": "hello world" + }) + )); + } + + #[test] + fn range_op() { + assert!(matches( + &json!({"key": { "$range": [18, 30] }}), + &json!({ + "key": 20 + }) + )); + + assert!(!matches( + &json!({"key": { "$range": [18, 30] }}), + &json!({ + "key": 15 + }) + )); + + assert!(!matches( + &json!({"key": { "$range": [18, 30] }}), + &json!({ + "key": 40 + }) + )); + } + + #[test] + fn in_array_contains() { + assert!(matches( + &json!({ + "key": { + "$contains": 3 + } + }), + &json!({ + "key": [1,2,3,4,5] + }) + )); + + assert!(matches( + &json!({ + "$not": { + "key": { + "$contains": 3 + }} + }), + &json!({ + "key": [1,2,4,5] + }) + )); + } + #[test] fn in_array() { assert!(matches(