From 2149879ac34bb06d1410324de9a3a55d0970a89c Mon Sep 17 00:00:00 2001 From: Harishankar Narayanan Date: Tue, 10 Dec 2024 10:26:14 +0530 Subject: [PATCH] refactor: Simplify operator retrieval by introducing get_operator method --- Cargo.toml | 1 - src/lib.rs | 82 ++++---- tests/tests.json | 532 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 574 insertions(+), 41 deletions(-) create mode 100644 tests/tests.json diff --git a/Cargo.toml b/Cargo.toml index 750f2bf..10708fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,6 @@ keywords = ["rules", "engine", "json", "logic"] categories = ["data-structures", "development-tools", "parsing"] [dependencies] -serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" thiserror = "1.0" diff --git a/src/lib.rs b/src/lib.rs index 454be63..f457e61 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -119,6 +119,47 @@ impl JsonLogic { } } + fn get_operator(&self, op: &str) -> Result<&dyn Operator, Error> { + match op { + "var" => Ok(&*self.var_op), + "==" => Ok(&*self.eq_op), + "===" => Ok(&*self.strict_eq_op), + ">" => Ok(&*self.gt_op), + "<" => Ok(&*self.lt_op), + "and" => Ok(&*self.and_op), + "or" => Ok(&*self.or_op), + "!" => Ok(&*self.not_op), + "map" => Ok(&*self.map_op), + "filter" => Ok(&*self.filter_op), + "reduce" => Ok(&*self.reduce_op), + "!=" => Ok(&*self.not_eq_op), + "!==" => Ok(&*self.strict_not_eq_op), + ">=" => Ok(&*self.gt_eq_op), + "<=" => Ok(&*self.lt_eq_op), + "?:" => Ok(&*self.ternary_op), + "!!" => Ok(&*self.double_bang_op), + "if" => Ok(&*self.if_op), + "merge" => Ok(&*self.merge_op), + "missing" => Ok(&*self.missing_op), + "missing_some" => Ok(&*self.missing_some_op), + "all" => Ok(&*self.all_op), + "none" => Ok(&*self.none_op), + "some" => Ok(&*self.some_op), + "preserve" => Ok(&*self.preserve_op), + "in" => Ok(&*self.in_op), + "cat" => Ok(&*self.cat_op), + "substr" => Ok(&*self.substr_op), + "+" => Ok(&*self.add_op), + "*" => Ok(&*self.multiply_op), + "-" => Ok(&*self.subtract_op), + "/" => Ok(&*self.divide_op), + "%" => Ok(&*self.modulo_op), + "max" => Ok(&*self.max_op), + "min" => Ok(&*self.min_op), + _ => Err(Error::UnknownOperator(op.to_string())), + } + } + pub fn apply(&self, logic: &Value, data: &Value) -> JsonLogicResult { match logic { Value::String(_) | Value::Number(_) | Value::Bool(_) | Value::Null => { @@ -126,46 +167,7 @@ impl JsonLogic { } Value::Object(map) if map.len() == 1 => { let (op, args) = map.iter().next().unwrap(); - let operator: &dyn Operator = match op.as_str() { - "var" => &*self.var_op, - "==" => &*self.eq_op, - "===" => &*self.strict_eq_op, - ">" => &*self.gt_op, - "<" => &*self.lt_op, - "and" => &*self.and_op, - "or" => &*self.or_op, - "!" => &*self.not_op, - "map" => &*self.map_op, - "filter" => &*self.filter_op, - "reduce" => &*self.reduce_op, - "!=" => &*self.not_eq_op, - "!==" => &*self.strict_not_eq_op, - ">=" => &*self.gt_eq_op, - "<=" => &*self.lt_eq_op, - "?:" => &*self.ternary_op, - "!!" => &*self.double_bang_op, - "if" => &*self.if_op, - "merge" => &*self.merge_op, - "missing" => &*self.missing_op, - "missing_some" => &*self.missing_some_op, - "all" => &*self.all_op, - "none" => &*self.none_op, - "some" => &*self.some_op, - "preserve" => &*self.preserve_op, - "in" => &*self.in_op, - "cat" => &*self.cat_op, - "substr" => &*self.substr_op, - "+" => &*self.add_op, - "*" => &*self.multiply_op, - "-" => &*self.subtract_op, - "/" => &*self.divide_op, - "%" => &*self.modulo_op, - "max" => &*self.max_op, - "min" => &*self.min_op, - _ => { - return Err(Error::UnknownOperator(op.clone())); - } - }; + let operator: &dyn Operator = self.get_operator(op)?; if operator.auto_traverse() { match args { diff --git a/tests/tests.json b/tests/tests.json new file mode 100644 index 0000000..d1c9c4f --- /dev/null +++ b/tests/tests.json @@ -0,0 +1,532 @@ +[ + "# Non-rules get passed through", + [ true, {}, true ], + [ false, {}, false ], + [ 17, {}, 17 ], + [ 3.14, {}, 3.14 ], + [ "apple", {}, "apple" ], + [ null, {}, null ], + [ ["a","b"], {}, ["a","b"] ], + + "# Single operator tests", + [ {"==":[1,1]}, {}, true ], + [ {"==":[1,"1"]}, {}, true ], + [ {"==":[1,2]}, {}, false ], + [ {"===":[1,1]}, {}, true ], + [ {"===":[1,"1"]}, {}, false ], + [ {"===":[1,2]}, {}, false ], + [ {"!=":[1,2]}, {}, true ], + [ {"!=":[1,1]}, {}, false ], + [ {"!=":[1,"1"]}, {}, false ], + [ {"!==":[1,2]}, {}, true ], + [ {"!==":[1,1]}, {}, false ], + [ {"!==":[1,"1"]}, {}, true ], + [ {">":[2,1]}, {}, true ], + [ {">":[1,1]}, {}, false ], + [ {">":[1,2]}, {}, false ], + [ {">":["2",1]}, {}, true ], + [ {">=":[2,1]}, {}, true ], + [ {">=":[1,1]}, {}, true ], + [ {">=":[1,2]}, {}, false ], + [ {">=":["2",1]}, {}, true ], + [ {"<":[2,1]}, {}, false ], + [ {"<":[1,1]}, {}, false ], + [ {"<":[1,2]}, {}, true ], + [ {"<":["1",2]}, {}, true ], + [ {"<":[1,2,3]}, {}, true ], + [ {"<":[1,1,3]}, {}, false ], + [ {"<":[1,4,3]}, {}, false ], + [ {"<=":[2,1]}, {}, false ], + [ {"<=":[1,1]}, {}, true ], + [ {"<=":[1,2]}, {}, true ], + [ {"<=":["1",2]}, {}, true ], + [ {"<=":[1,2,3]}, {}, true ], + [ {"<=":[1,4,3]}, {}, false ], + [ {"!":[false]}, {}, true ], + [ {"!":false}, {}, true ], + [ {"!":[true]}, {}, false ], + [ {"!":true}, {}, false ], + [ {"!":0}, {}, true ], + [ {"!":1}, {}, false ], + [ {"or":[true,true]}, {}, true ], + [ {"or":[false,true]}, {}, true ], + [ {"or":[true,false]}, {}, true ], + [ {"or":[false,false]}, {}, false ], + [ {"or":[false,false,true]}, {}, true ], + [ {"or":[false,false,false]}, {}, false ], + [ {"or":[false]}, {}, false ], + [ {"or":[true]}, {}, true ], + [ {"or":[1,3]}, {}, 1 ], + [ {"or":[3,false]}, {}, 3 ], + [ {"or":[false,3]}, {}, 3 ], + [ {"and":[true,true]}, {}, true ], + [ {"and":[false,true]}, {}, false ], + [ {"and":[true,false]}, {}, false ], + [ {"and":[false,false]}, {}, false ], + [ {"and":[true,true,true]}, {}, true ], + [ {"and":[true,true,false]}, {}, false ], + [ {"and":[false]}, {}, false ], + [ {"and":[true]}, {}, true ], + [ {"and":[1,3]}, {}, 3 ], + [ {"and":[3,false]}, {}, false ], + [ {"and":[false,3]}, {}, false ], + [ {"?:":[true,1,2]}, {}, 1 ], + [ {"?:":[false,1,2]}, {}, 2 ], + [ {"in":["Bart",["Bart","Homer","Lisa","Marge","Maggie"]]}, {}, true ], + [ {"in":["Milhouse",["Bart","Homer","Lisa","Marge","Maggie"]]}, {}, false ], + [ {"in":["Spring","Springfield"]}, {}, true ], + [ {"in":["i","team"]}, {}, false ], + [ {"cat":"ice"}, {}, "ice" ], + [ {"cat":["ice"]}, {}, "ice" ], + [ {"cat":["ice","cream"]}, {}, "icecream" ], + [ {"cat":[1,2]}, {}, "12" ], + [ {"cat":["Robocop",2]}, {}, "Robocop2" ], + [ {"cat":["we all scream for ","ice","cream"]}, {}, "we all scream for icecream" ], + [ {"%":[1,2]}, {}, 1 ], + [ {"%":[2,2]}, {}, 0 ], + [ {"%":[3,2]}, {}, 1 ], + [ {"max":[1,2,3]}, {}, 3 ], + [ {"max":[1,3,3]}, {}, 3 ], + [ {"max":[3,2,1]}, {}, 3 ], + [ {"max":[1]}, {}, 1 ], + [ {"min":[1,2,3]}, {}, 1 ], + [ {"min":[1,1,3]}, {}, 1 ], + [ {"min":[3,2,1]}, {}, 1 ], + [ {"min":[1]}, {}, 1 ], + + [ {"+":[1,2]}, {}, 3 ], + [ {"+":[2,2,2]}, {}, 6 ], + [ {"+":[1]}, {}, 1 ], + [ {"+":["1",1]}, {}, 2 ], + [ {"*":[3,2]}, {}, 6 ], + [ {"*":[2,2,2]}, {}, 8 ], + [ {"*":[1]}, {}, 1 ], + [ {"*":["1",1]}, {}, 1 ], + [ {"-":[2,3]}, {}, -1 ], + [ {"-":[3,2]}, {}, 1 ], + [ {"-":[3]}, {}, -3 ], + [ {"-":["1",1]}, {}, 0 ], + [ {"/":[4,2]}, {}, 2 ], + [ {"/":[2,4]}, {}, 0.5 ], + [ {"/":["1",1]}, {}, 1 ], + + "Substring", + [{"substr":["jsonlogic", 4]}, null, "logic"], + [{"substr":["jsonlogic", -5]}, null, "logic"], + [{"substr":["jsonlogic", 0, 1]}, null, "j"], + [{"substr":["jsonlogic", -1, 1]}, null, "c"], + [{"substr":["jsonlogic", 4, 5]}, null, "logic"], + [{"substr":["jsonlogic", -5, 5]}, null, "logic"], + [{"substr":["jsonlogic", -5, -2]}, null, "log"], + [{"substr":["jsonlogic", 1, -5]}, null, "son"], + + "Merge arrays", + [{"merge":[]}, null, []], + [{"merge":[[1]]}, null, [1]], + [{"merge":[[1],[]]}, null, [1]], + [{"merge":[[1], [2]]}, null, [1,2]], + [{"merge":[[1], [2], [3]]}, null, [1,2,3]], + [{"merge":[[1, 2], [3]]}, null, [1,2,3]], + [{"merge":[[1], [2, 3]]}, null, [1,2,3]], + "Given non-array arguments, merge converts them to arrays", + [{"merge":1}, null, [1]], + [{"merge":[1,2]}, null, [1,2]], + [{"merge":[1,[2]]}, null, [1,2]], + + "Too few args", + [{"if":[]}, null, null], + [{"if":[true]}, null, true], + [{"if":[false]}, null, false], + [{"if":["apple"]}, null, "apple"], + + "Simple if/then/else cases", + [{"if":[true, "apple"]}, null, "apple"], + [{"if":[false, "apple"]}, null, null], + [{"if":[true, "apple", "banana"]}, null, "apple"], + [{"if":[false, "apple", "banana"]}, null, "banana"], + + "Empty arrays are falsey", + [{"if":[ [], "apple", "banana"]}, null, "banana"], + [{"if":[ [1], "apple", "banana"]}, null, "apple"], + [{"if":[ [1,2,3,4], "apple", "banana"]}, null, "apple"], + + "Empty strings are falsey, all other strings are truthy", + [{"if":[ "", "apple", "banana"]}, null, "banana"], + [{"if":[ "zucchini", "apple", "banana"]}, null, "apple"], + [{"if":[ "0", "apple", "banana"]}, null, "apple"], + + "You can cast a string to numeric with a unary + ", + [{"===":[0,"0"]}, null, false], + [{"===":[0,{"+":"0"}]}, null, true], + [{"if":[ {"+":"0"}, "apple", "banana"]}, null, "banana"], + [{"if":[ {"+":"1"}, "apple", "banana"]}, null, "apple"], + + "Zero is falsy, all other numbers are truthy", + [{"if":[ 0, "apple", "banana"]}, null, "banana"], + [{"if":[ 1, "apple", "banana"]}, null, "apple"], + [{"if":[ 3.1416, "apple", "banana"]}, null, "apple"], + [{"if":[ -1, "apple", "banana"]}, null, "apple"], + + "Truthy and falsy definitions matter in Boolean operations", + [{"!" : [ [] ]}, {}, true], + [{"!!" : [ [] ]}, {}, false], + [{"and" : [ [], true ]}, {}, [] ], + [{"or" : [ [], true ]}, {}, true ], + + [{"!" : [ 0 ]}, {}, true], + [{"!!" : [ 0 ]}, {}, false], + [{"and" : [ 0, true ]}, {}, 0 ], + [{"or" : [ 0, true ]}, {}, true ], + + [{"!" : [ "" ]}, {}, true], + [{"!!" : [ "" ]}, {}, false], + [{"and" : [ "", true ]}, {}, "" ], + [{"or" : [ "", true ]}, {}, true ], + + [{"!" : [ "0" ]}, {}, false], + [{"!!" : [ "0" ]}, {}, true], + [{"and" : [ "0", true ]}, {}, true ], + [{"or" : [ "0", true ]}, {}, "0" ], + + "If the conditional is logic, it gets evaluated", + [{"if":[ {">":[2,1]}, "apple", "banana"]}, null, "apple"], + [{"if":[ {">":[1,2]}, "apple", "banana"]}, null, "banana"], + + "If the consequents are logic, they get evaluated", + [{"if":[ true, {"cat":["ap","ple"]}, {"cat":["ba","na","na"]} ]}, null, "apple"], + [{"if":[ false, {"cat":["ap","ple"]}, {"cat":["ba","na","na"]} ]}, null, "banana"], + + "If/then/elseif/then cases", + [{"if":[true, "apple", true, "banana"]}, null, "apple"], + [{"if":[true, "apple", false, "banana"]}, null, "apple"], + [{"if":[false, "apple", true, "banana"]}, null, "banana"], + [{"if":[false, "apple", false, "banana"]}, null, null], + + [{"if":[true, "apple", true, "banana", "carrot"]}, null, "apple"], + [{"if":[true, "apple", false, "banana", "carrot"]}, null, "apple"], + [{"if":[false, "apple", true, "banana", "carrot"]}, null, "banana"], + [{"if":[false, "apple", false, "banana", "carrot"]}, null, "carrot"], + + [{"if":[false, "apple", false, "banana", false, "carrot"]}, null, null], + [{"if":[false, "apple", false, "banana", false, "carrot", "date"]}, null, "date"], + [{"if":[false, "apple", false, "banana", true, "carrot", "date"]}, null, "carrot"], + [{"if":[false, "apple", true, "banana", false, "carrot", "date"]}, null, "banana"], + [{"if":[false, "apple", true, "banana", true, "carrot", "date"]}, null, "banana"], + [{"if":[true, "apple", false, "banana", false, "carrot", "date"]}, null, "apple"], + [{"if":[true, "apple", false, "banana", true, "carrot", "date"]}, null, "apple"], + [{"if":[true, "apple", true, "banana", false, "carrot", "date"]}, null, "apple"], + [{"if":[true, "apple", true, "banana", true, "carrot", "date"]}, null, "apple"], + + "Arrays with logic", + [[1, {"var": "x"}, 3], {"x": 2}, [1, 2, 3]], + [{"if": [{"var": "x"}, [{"var": "y"}], 99]}, {"x": true, "y": 42}, [42]], + + "# Compound Tests", + [ {"and":[{">":[3,1]},true]}, {}, true ], + [ {"and":[{">":[3,1]},false]}, {}, false ], + [ {"and":[{">":[3,1]},{"!":true}]}, {}, false ], + [ {"and":[{">":[3,1]},{"<":[1,3]}]}, {}, true ], + [ {"?:":[{">":[3,1]},"visible","hidden"]}, {}, "visible" ], + + "# Data-Driven", + [ {"var":["a"]},{"a":1},1 ], + [ {"var":["b"]},{"a":1},null ], + [ {"var":["a"]},null,null ], + [ {"var":"a"},{"a":1},1 ], + [ {"var":"b"},{"a":1},null ], + [ {"var":"a"},null,null ], + [ {"var":["a", 1]},null,1 ], + [ {"var":["b", 2]},{"a":1},2 ], + [ {"var":"a.b"},{"a":{"b":"c"}},"c" ], + [ {"var":"a.q"},{"a":{"b":"c"}},null ], + [ {"var":["a.q", 9]},{"a":{"b":"c"}},9 ], + [ {"var":1}, ["apple","banana"], "banana" ], + [ {"var":"1"}, ["apple","banana"], "banana" ], + [ {"var":"1.1"}, ["apple",["banana","beer"]], "beer" ], + [ {"and":[{"<":[{"var":"temp"},110]},{"==":[{"var":"pie.filling"},"apple"]}]},{"temp":100,"pie":{"filling":"apple"}},true ], + [ {"var":[{"?:":[{"<":[{"var":"temp"},110]},"pie.filling","pie.eta"]}]},{"temp":100,"pie":{"filling":"apple","eta":"60s"}},"apple" ], + [ {"in":[{"var":"filling"},["apple","cherry"]]},{"filling":"apple"},true ], + [ {"var":"a.b.c"}, null, null ], + [ {"var":"a.b.c"}, {"a":null}, null ], + [ {"var":"a.b.c"}, {"a":{"b":null}}, null ], + [ {"var":""}, 1, 1 ], + [ {"var":null}, 1, 1 ], + [ {"var":[]}, 1, 1 ], + + "Missing", + [{"missing":[]}, null, []], + [{"missing":["a"]}, null, ["a"]], + [{"missing":"a"}, null, ["a"]], + [{"missing":"a"}, {"a":"apple"}, []], + [{"missing":["a"]}, {"a":"apple"}, []], + [{"missing":["a","b"]}, {"a":"apple"}, ["b"]], + [{"missing":["a","b"]}, {"b":"banana"}, ["a"]], + [{"missing":["a","b"]}, {"a":"apple", "b":"banana"}, []], + [{"missing":["a","b"]}, {}, ["a","b"]], + [{"missing":["a","b"]}, null, ["a","b"]], + + [{"missing":["a.b"]}, null, ["a.b"]], + [{"missing":["a.b"]}, {"a":"apple"}, ["a.b"]], + [{"missing":["a.b"]}, {"a":{"c":"apple cake"}}, ["a.b"]], + [{"missing":["a.b"]}, {"a":{"b":"apple brownie"}}, []], + [{"missing":["a.b", "a.c"]}, {"a":{"b":"apple brownie"}}, ["a.c"]], + + + "Missing some", + [{"missing_some":[1, ["a", "b"]]}, {"a":"apple"}, [] ], + [{"missing_some":[1, ["a", "b"]]}, {"b":"banana"}, [] ], + [{"missing_some":[1, ["a", "b"]]}, {"a":"apple", "b":"banana"}, [] ], + [{"missing_some":[1, ["a", "b"]]}, {"c":"carrot"}, ["a", "b"]], + + [{"missing_some":[2, ["a", "b", "c"]]}, {"a":"apple", "b":"banana"}, [] ], + [{"missing_some":[2, ["a", "b", "c"]]}, {"a":"apple", "c":"carrot"}, [] ], + [{"missing_some":[2, ["a", "b", "c"]]}, {"a":"apple", "b":"banana", "c":"carrot"}, [] ], + [{"missing_some":[2, ["a", "b", "c"]]}, {"a":"apple", "d":"durian"}, ["b", "c"] ], + [{"missing_some":[2, ["a", "b", "c"]]}, {"d":"durian", "e":"eggplant"}, ["a", "b", "c"] ], + + + "Missing and If are friends, because empty arrays are falsey in JsonLogic", + [{"if":[ {"missing":"a"}, "missed it", "found it" ]}, {"a":"apple"}, "found it"], + [{"if":[ {"missing":"a"}, "missed it", "found it" ]}, {"b":"banana"}, "missed it"], + + "Missing, Merge, and If are friends. VIN is always required, APR is only required if financing is true.", + [ + {"missing":{"merge":[ "vin", {"if": [{"var":"financing"}, ["apr"], [] ]} ]} }, + {"financing":true}, + ["vin","apr"] + ], + + [ + {"missing":{"merge":[ "vin", {"if": [{"var":"financing"}, ["apr"], [] ]} ]} }, + {"financing":false}, + ["vin"] + ], + + "Filter, map, all, none, and some", + [ + {"filter":[{"var":"integers"}, true]}, + {"integers":[1,2,3]}, + [1,2,3] + ], + [ + {"filter":[{"var":"integers"}, false]}, + {"integers":[1,2,3]}, + [] + ], + [ + {"filter":[{"var":"integers"}, {">=":[{"var":""},2]}]}, + {"integers":[1,2,3]}, + [2,3] + ], + [ + {"filter":[{"var":"integers"}, {"%":[{"var":""},2]}]}, + {"integers":[1,2,3]}, + [1,3] + ], + + [ + {"map":[{"var":"integers"}, {"*":[{"var":""},2]}]}, + {"integers":[1,2,3]}, + [2,4,6] + ], + [ + {"map":[{"var":"integers"}, {"*":[{"var":""},2]}]}, + null, + [] + ], + [ + {"map":[{"var":"desserts"}, {"var":"qty"}]}, + {"desserts":[ + {"name":"apple","qty":1}, + {"name":"brownie","qty":2}, + {"name":"cupcake","qty":3} + ]}, + [1,2,3] + ], + + [ + {"reduce":[ + {"var":"integers"}, + {"+":[{"var":"current"}, {"var":"accumulator"}]}, + 0 + ]}, + {"integers":[1,2,3,4]}, + 10 + ], + [ + {"reduce":[ + {"var":"integers"}, + {"+":[{"var":"current"}, {"var":"accumulator"}]}, + {"var": "start_with"} + ]}, + {"integers":[1,2,3,4], "start_with": 59}, + 69 + ], + [ + {"reduce":[ + {"var":"integers"}, + {"+":[{"var":"current"}, {"var":"accumulator"}]}, + 0 + ]}, + null, + 0 + ], + [ + {"reduce":[ + {"var":"integers"}, + {"*":[{"var":"current"}, {"var":"accumulator"}]}, + 1 + ]}, + {"integers":[1,2,3,4]}, + 24 + ], + [ + {"reduce":[ + {"var":"integers"}, + {"*":[{"var":"current"}, {"var":"accumulator"}]}, + 0 + ]}, + {"integers":[1,2,3,4]}, + 0 + ], + [ + {"reduce": [ + {"var":"desserts"}, + {"+":[ {"var":"accumulator"}, {"var":"current.qty"}]}, + 0 + ]}, + {"desserts":[ + {"name":"apple","qty":1}, + {"name":"brownie","qty":2}, + {"name":"cupcake","qty":3} + ]}, + 6 + ], + + + [ + {"all":[{"var":"integers"}, {">=":[{"var":""}, 1]}]}, + {"integers":[1,2,3]}, + true + ], + [ + {"all":[{"var":"integers"}, {"==":[{"var":""}, 1]}]}, + {"integers":[1,2,3]}, + false + ], + [ + {"all":[{"var":"integers"}, {"<":[{"var":""}, 1]}]}, + {"integers":[1,2,3]}, + false + ], + [ + {"all":[{"var":"integers"}, {"<":[{"var":""}, 1]}]}, + {"integers":[]}, + false + ], + [ + {"all":[ {"var":"items"}, {">=":[{"var":"qty"}, 1]}]}, + {"items":[{"qty":1,"sku":"apple"},{"qty":2,"sku":"banana"}]}, + true + ], + [ + {"all":[ {"var":"items"}, {">":[{"var":"qty"}, 1]}]}, + {"items":[{"qty":1,"sku":"apple"},{"qty":2,"sku":"banana"}]}, + false + ], + [ + {"all":[ {"var":"items"}, {"<":[{"var":"qty"}, 1]}]}, + {"items":[{"qty":1,"sku":"apple"},{"qty":2,"sku":"banana"}]}, + false + ], + [ + {"all":[ {"var":"items"}, {">=":[{"var":"qty"}, 1]}]}, + {"items":[]}, + false + ], + + + [ + {"none":[{"var":"integers"}, {">=":[{"var":""}, 1]}]}, + {"integers":[1,2,3]}, + false + ], + [ + {"none":[{"var":"integers"}, {"==":[{"var":""}, 1]}]}, + {"integers":[1,2,3]}, + false + ], + [ + {"none":[{"var":"integers"}, {"<":[{"var":""}, 1]}]}, + {"integers":[1,2,3]}, + true + ], + [ + {"none":[{"var":"integers"}, {"<":[{"var":""}, 1]}]}, + {"integers":[]}, + true + ], + [ + {"none":[ {"var":"items"}, {">=":[{"var":"qty"}, 1]}]}, + {"items":[{"qty":1,"sku":"apple"},{"qty":2,"sku":"banana"}]}, + false + ], + [ + {"none":[ {"var":"items"}, {">":[{"var":"qty"}, 1]}]}, + {"items":[{"qty":1,"sku":"apple"},{"qty":2,"sku":"banana"}]}, + false + ], + [ + {"none":[ {"var":"items"}, {"<":[{"var":"qty"}, 1]}]}, + {"items":[{"qty":1,"sku":"apple"},{"qty":2,"sku":"banana"}]}, + true + ], + [ + {"none":[ {"var":"items"}, {">=":[{"var":"qty"}, 1]}]}, + {"items":[]}, + true + ], + + [ + {"some":[{"var":"integers"}, {">=":[{"var":""}, 1]}]}, + {"integers":[1,2,3]}, + true + ], + [ + {"some":[{"var":"integers"}, {"==":[{"var":""}, 1]}]}, + {"integers":[1,2,3]}, + true + ], + [ + {"some":[{"var":"integers"}, {"<":[{"var":""}, 1]}]}, + {"integers":[1,2,3]}, + false + ], + [ + {"some":[{"var":"integers"}, {"<":[{"var":""}, 1]}]}, + {"integers":[]}, + false + ], + [ + {"some":[ {"var":"items"}, {">=":[{"var":"qty"}, 1]}]}, + {"items":[{"qty":1,"sku":"apple"},{"qty":2,"sku":"banana"}]}, + true + ], + [ + {"some":[ {"var":"items"}, {">":[{"var":"qty"}, 1]}]}, + {"items":[{"qty":1,"sku":"apple"},{"qty":2,"sku":"banana"}]}, + true + ], + [ + {"some":[ {"var":"items"}, {"<":[{"var":"qty"}, 1]}]}, + {"items":[{"qty":1,"sku":"apple"},{"qty":2,"sku":"banana"}]}, + false + ], + [ + {"some":[ {"var":"items"}, {">=":[{"var":"qty"}, 1]}]}, + {"items":[]}, + false + ], + + "EOF" +] \ No newline at end of file