diff --git a/lib/src/fun/fun_factory.dart b/lib/src/fun/fun_factory.dart index 8942f2d..2f8b2af 100644 --- a/lib/src/fun/fun_factory.dart +++ b/lib/src/fun/fun_factory.dart @@ -48,17 +48,37 @@ class FunFactory { Expression _any1(String name, Expression a0) { final f = _getFun1(name); - final cast0 = cast(value: f is Fun1, logical: f is Fun1); - return a0.map(cast0).map(f.call); + if (f is Fun1) { + if (a0 is Expression) { + return a0.map(f.call); + } + if (a0 is Expression) { + return a0.map((v) => v.asValue).map(f.call); + } + } + if (f is Fun1) { + if (a0 is Expression) { + return a0.map(f.call); + } + if (a0 is Expression) { + return a0.map((v) => v.asLogical).map(f.call); + } + } + if (f is Fun1) { + if (a0 is Expression) { + return a0.map(f.call); + } + } + throw Exception('Fun arg mismatch'); } Expression _any2( String name, Expression a0, Expression a1) { final f = _getFun2(name); - final cast0 = cast( + final cast0 = cast(a0, value: f is Fun2, logical: f is Fun2); - final cast1 = cast( + final cast1 = cast(a1, value: f is Fun2, logical: f is Fun2); return a0.map(cast0).merge(a1.map(cast1), f.call); @@ -76,9 +96,14 @@ class FunFactory { throw StateError('Function "$name" of 2 arguments is not found'); } - static Object Function(Object) cast( + static Object Function(Object) cast(Expression arg, {required bool value, required bool logical}) { - if (value) return _value; + if (value) { + if (arg is! Expression && arg is! Expression) { + throw Exception('Arg type mismatch'); + } + return _value; + } if (logical) return _logical; return _nodes; } diff --git a/lib/src/grammar/json_path.dart b/lib/src/grammar/json_path.dart index 5bf3c89..e050331 100644 --- a/lib/src/grammar/json_path.dart +++ b/lib/src/grammar/json_path.dart @@ -62,7 +62,8 @@ class JsonPathGrammarDefinition Parser _funArgument() => [ literal, - _filterPath(), + ref0(_singularFilterPath), + ref0(_filterPath), ref0(_valueFunExpr), ref0(_logicalFunExpr), ref0(_nodesFunExpr), @@ -113,7 +114,7 @@ class JsonPathGrammarDefinition ref0(_absPath), ].toChoiceParser(); - Parser> _singularFilterPath() => [ + Parser> _singularFilterPath() => [ ref0(_singularRelPath), ref0(_singularAbsPath), ].toChoiceParser(); @@ -156,12 +157,13 @@ class JsonPathGrammarDefinition Parser> _singularAbsPath() => _singularSegmentSequence() - .skip(before: char(r'$')) + .skip(before: char(r'$'), after: _segment().not()) .map((expr) => Expression((node) => expr.call(node.root))); Parser> _relPath() => _segmentSequence().skip(before: char('@')); Parser> _singularRelPath() => - _singularSegmentSequence().skip(before: char('@')); + _singularSegmentSequence() + .skip(before: char('@'), after: _segment().not()); } diff --git a/test/cases/extra/cases.json b/test/cases/extra/cases.json index 6a3222d..754dec9 100644 --- a/test/cases/extra/cases.json +++ b/test/cases/extra/cases.json @@ -1,31 +1,31 @@ { "tests": [ { - "name": "reverse()", + "name": "reverse(@)", "selector" : "$[?reverse(@)=='cba']", "document" : ["abc", "cba"], "result": ["abc"] }, { - "name": "reverse(reverse())", + "name": "reverse(reverse(@))", "selector" : "$[?reverse(reverse(@))=='cba']", "document" : ["abc", "cba"], "result": ["cba"] }, { - "name": "reverse(reverse())", + "name": "count(siblings(@))", "selector" : "$..[?count(siblings(@)) == 1]", "document" : {"a": {"b": "x", "d": "x"}}, "result": ["x", "x"] }, { - "name": "is_object", + "name": "is_object(@)", "selector" : "$[?is_object(@)]", "document" : [1, true, {}, [42], "foo", {"a": "b"}], "result": [{}, {"a": "b"}] }, { - "name": "is_array", + "name": "is_array(@)", "selector" : "$[?is_array(@)]", "document" : [1, true, {}, [42], "foo", {"a": "b"}], "result": [[42]] @@ -53,6 +53,74 @@ "selector" : "$[?xor((@.b), (@.a))]", "document" : [{"a": 0}, {"a": 0, "b": 0}, {"b": 0}, {}], "result": [{"a": 0}, {"b": 0}] + }, + { + "name": "functions, length, non-singular query arg", + "selector": "$[?length(@.*)<3]", + "invalid_selector": true + }, + { + "name": "functions, length, arg is a function expression", + "selector": "$.values[?length(@.a)==length(value($..c))]", + "document": { + "c": "cd", + "values": [ + { + "a": "ab" + }, + { + "a": "d" + } + ] + }, + "result": [ + { + "a": "ab" + } + ] + }, { + "name": "functions, match, arg is a function expression", + "selector": "$.values[?match(@.a, value($..['regex']))]", + "document": { + "regex": "a.*", + "values": [ + { + "a": "ab" + }, + { + "a": "ba" + } + ] + }, + "result": [ + { + "a": "ab" + } + ] + }, + { + "name": "functions, search, arg is a function expression", + "selector": "$.values[?search(@, value($..['regex']))]", + "document": { + "regex": "b.?b", + "values": [ + "abc", + "bcd", + "bab", + "bba", + "bbab", + "b", + true, + [], + {} + ] + }, + "result": [ + "bab", + "bba", + "bbab" + ] } + ] } \ No newline at end of file diff --git a/test/parser_test.dart b/test/parser_test.dart index f92f8f3..a3d394e 100644 --- a/test/parser_test.dart +++ b/test/parser_test.dart @@ -29,3 +29,5 @@ void main() { }); }); } + +