Closed gregsdennis closed 1 year ago
Thanks. As a general observation, I prefer to use a different name for JSONPath-level logicals from JSON-level Booleans. In my draft, I have settled for "logical" for this.
Have you checked what functionality is lost with this approach?
Thanks. As a general observation, I prefer to use a different name for JSONPath-level logicals from JSON-level Booleans. In my draft, I have settled for "logical" for this.
I'm not hung up on naming things. I'm happy with "logical."
Have you checked what functionality is lost with this approach?
Because match()
and search()
MUST be used as "logicals," they can't be used as comparable
s. While you get $[?match(@.a, 'a.*')]
and $[?!match(@.a, 'a.*')]
, you don't get $[?match(@.a, 'a.*') == @.b]
. But I think that has a very niche use case that I'm sure could be covered with a custom function.
I agree that $[?match(@.a, 'a.*') == @.b]
can be expressed without Booleanness:
$[?(match(@.a, 'a.*') && true == @.b) || (!match(@.a, 'a.*') && false == @.b)]
I wrote the 44 lines of code needed to check well-typedness in this type system (with the four predefined functions) and things do look good to me. More testing and word-smithing required...
Sample (error messages precede the example; the right column is a JSON representation of the query):
$[?match(@.a, "x*")] ["$", ["filt", ["func", "match", ["@", "a"], "x*"]]]
*** Cannot use ["func", "match", ["@", "a"], "a.*"] with declared_type logical for required type value in comparable
$[?match(@.a, 'a.*') == @.b] ["$", ["filt", ["==", ["func", "match", ["@", "a"], "a.*"], ["@", "b"]]]]
*** Cannot use ["func", "match", ["@", "a"], "a.*"] with declared_type logical for required type value in comparable
$[?match(@.a, 'a.*') == @[1]] ["$", ["filt", ["==", ["func", "match", ["@", "a"], "a.*"], ["@", 1]]]]
$[?(match(@.a, 'a.*') && true == @.b) || (!match(@.a, 'a.*') && false == @.b)] ["$", ["filt", ["or", ["and", ["func", "match", ["@", "a"], "a.*"], ["==", true, ["@", "b"]]], ["and", ["not", ["func", "match", ["@", "a"], "a.*"]], ["==", false, ["@", "b"]]]]]]
*** Cannot use ["func", "length", ["@", "a"]] with declared_type value for required type logical in test expression
$[?length(@.a)] ["$", ["filt", ["func", "length", ["@", "a"]]]]
$[?length(@.a)==5] ["$", ["filt", ["==", ["func", "length", ["@", "a"]], 5]]]
$[?count(@.a)==5] ["$", ["filt", ["==", ["func", "count", ["@", "a"]], 5]]]
*** Cannot use 4 with declared_type value for required type nodes in ["func", "count", 4]
$[?count(4)==5] ["$", ["filt", ["==", ["func", "count", 4], 5]]]
$[?(@['key']==count(@))] ["$", ["filt", ["==", ["@", "key"], ["func", "count", ["@"]]]]]
@cabo although we haven't defined one in the spec, a nodelist-function is the outlier. Assuming the follow definition for @glyn's ad-hoc proposal for distinct()
, could you run the same tests, please?
Name: distinct
Arguments:
NodelistType
- Likely the result of a subquery, like @.*
Returns NodelistType
- A copy of the argument nodelist with duplicates removed. A duplicate (for the purpose of this comment) is the same JSON value regardless of its location in the data.
Path to test | Validity | Node selection | Note |
---|---|---|---|
$[?distinct(@.*)] |
valid | selects the node if it has children | This example is not really useful as it should evaluate the same as $[?@.*] because removing duplicates has no effect on empty-ness |
$[?distinct(@.*)==42] |
valid | selects the node if the resulting nodelist is just a collection of one or more 42 s |
Again, maybe not too useful.* |
I'm not looking for evaluation here, just parsing, as you have above.
* As a note for the second example, the function would return a nodelist here, which is convertible to a value. If @.*
results in a nodelist with non-zero nodes all containing the same value, that nodelist would be de-duplicated returning a nodelist with a single node. The convertion to a value would then be the value of that node. If that value is 42
, then that node is selected.
I'm not trying to make a case for this function. It's merely an example for your parser.
could you run the same tests, please
$ cat test-data/distinct.jpl
$[?distinct(@.*)]
$[?distinct(@.*)==42]
$ jpt -l -fdistinct-nn test-data/distinct.jpl
$[?distinct(@.*)] ["$", ["filt", ["func", "distinct", ["@", ["wild"]]]]]
$[?distinct(@.*)==42] ["$", ["filt", ["==", ["func", "distinct", ["@", ["wild"]]], 42]]]
$
So the well-typedness comes out well with these examples for a distinct(nodes) ➔ nodes (distinct-nn
).
Distinct of course can generate general nodelists, not just singular ones, so this is a bit of the violation of the signature of ==
, but then we don't try to distinguish 0-or-1 nodelists from general nodelists in the simple type system we seem to be converging on.
(Get the JPT tool via gem install jpt
.)
Distinct of course can generate general nodelists, not just singular ones, so this is a bit of the violation of the signature of == - @cabo
First, thanks for runnig that test and sharing the results.
The type conversion from NodelistType
to ValueType
(which is accepted by ==
) now includes multiple nodelists as being converted to Nothing
. The need for this was explained in the final section of https://github.com/ietf-wg-jsonpath/draft-ietf-jsonpath-base/issues/387#issuecomment-1436079071.
Since the ABNF only allows Singluar Paths and explicit JSON values to be used with ==
, functions become the only way to have a multiple nodelist in a comparison, so I think this conversion is suitable.
Superseded by #403, which cherry-picked a lot from this one. Thank you!
Yes, thanks @gregsdennis.
Resolves #387 (specifcally implements https://github.com/ietf-wg-jsonpath/draft-ietf-jsonpath-base/issues/387#issuecomment-1436079071)
This is effectively an extension of #396 (though not a continuation of that git branch). I purposely didn't use
PropositionType
because earlier in the text (under#filter-selector
), it saysSince the "boolean" language is here, I just stuck with it.