ietf-wg-jsonpath / draft-ietf-jsonpath-base

Development of a JSONPath internet draft
https://ietf-wg-jsonpath.github.io/draft-ietf-jsonpath-base/
Other
58 stars 20 forks source link

"Singular Query" definition #481

Closed gregsdennis closed 11 months ago

gregsdennis commented 11 months ago

The "Singular Query" is defined as:

Singular Query: A JSONPath expression built from segments each of which, regardless of the input value, produces a nodelist containing at most one node.

Based on this definition, is $.foo[1,'1'].bar a singular query? It seems to match the definition. But we have typically (informally) maintained that a singular query isn't allowed to have multiple selectors within a segment.

I thought of this when conisdering how to create a JSON Path that functions the same as a JSON Pointer. Since numeric segments can be either array indices or object keys, I thought it was impossible to do, in general, if a numeric segment existed in the pointer. However, a numeric segment really means "if the data is an array, select this index; if it's an object, select this key." And that's exactly what the above does.

Arguably, with different data it would select different locations, but with any given data, it would select at most one node.

glyn commented 11 months ago

The "Singular Query" is defined as:

Singular Query: A JSONPath expression built from segments each of which, regardless of the input value, produces a nodelist containing at most one node.

Based on this definition, is $.foo[1,'1'].bar a singular query? It seems to match the definition. But we have typically (informally) maintained that a singular query isn't allowed to have multiple selectors within a segment.

It does seem to be a Singular Query according to the definition. Admittedly it's rather unexpected, but I don't think there are any negative consequences where "Singular Query" is used in the spec. Are you aware of negative consequences?

I thought of this when conisdering how to create a JSON Path that functions the same as a JSON Pointer. Since numeric segments can be either array indices or object keys, I thought it was impossible to do, in general, if a numeric segment existed in the pointer. However, a numeric segment really means "if the data is an array, select this index; if it's an object, select this key." And that's exactly what the above does.

Arguably, with different data it would select different locations, but with any given data, it would select at most one node.

That's also true of the Singular Query $[-3] (mentioned in the spec as an example of a Singular Query that is not a Normalized Path).

gregsdennis commented 11 months ago

I can't think of any negative consequences either, although I'm also not sure how one can identify this (as a general case) as a singular query programmatically. (Is it possible to assert that this or a similar construct always gives a single node result?) Do you think it's worth a test in the suite?

I may have been thinking of a normalized path, which it definitely is not.

f3ath commented 11 months ago

I can't think of any negative consequences either, although I'm also not sure how one can identify this (as a general case) as a singular query programmatically. (Is it possible to assert that this or a similar construct always gives a single node result?) Do you think it's worth a test in the suite?

Take the "union" selector (e.g. ["a", "b", "c", 1, 2, 3]) count the number of unique strings and the number of unique numbers, if each of the counts is not greater than 1, it's a singular selector. Wildcard obviously disqualifies it as singular. Am I getting the problem wrong?

gregsdennis commented 11 months ago

Yeah, that could select up to three values. At most you could have only a single selector that handles objects plus a single selector that handles arrays.

f3ath commented 11 months ago

I guess we don't even need uniqueness, since [1, 1] is not singular according to the definition.

f3ath commented 11 months ago

Doesn't the ABNF disqalify @['0', 0] as a singular selector?

singular-query-segments = *(S (name-segment / index-segment))
name-segment        = ("[" name-selector "]") /
                      ("." member-name-shorthand)
index-segment       = "[" index-selector "]"

Also, is this a valid jsonpath: $[?(@['0', 0] == 42)]?

gregsdennis commented 11 months ago

Yeah, the ABNF does seem quite stricter than the prose definition.

And, the path is a valid path, but it's not singular because it will select any object in an array that has @[0,'0']==42, which could be multiple.

f3ath commented 11 months ago

Is it really? The ABNF seems to allow comparison only between comparables which this is not:

comparison-expr     = comparable S comparison-op S comparable
literal             = number / string-literal /
                      true / false / null
comparable          = literal /
                      singular-query / ; singular query value
                      function-expr 

Am I missing something?

gregsdennis commented 11 months ago

Oh! I see what you're getting at. Sorry, I was looking at the query as a whole, not the singular-ness of the inner query.

Yeah, I think you're right that it's not technically valid, though it definitely seems like it could be.

f3ath commented 11 months ago

It seems to be worth adding to the CTS. My implementation currently accepts it, I guess it's an incorrect behavior.

cabo commented 11 months ago

The "Singular Query" is defined as:

Singular Query: A JSONPath expression built from segments each of which, regardless of the input value, produces a nodelist containing at most one node.

I think some of the confusion here comes from reading this as the complete definition.

Actually, a Singular Query is one that has been syntactically restricted in a specific way that always produces zero or one nodes. As noted, there are ways for a query that is not a Singular Query to always produce zero or one nodes: Not every singular query is a Singular Query.

cabo commented 11 months ago

So here is a pedantic definition:

Singular Query: A JSONPath expression built from segments that have been syntactically restricted in a certain way (Section 2.3.5.1) such that each of them, with an input nodelist of at most one node, produces a nodelist containing at most one node.

cabo commented 11 months ago

Maybe we should add a note that not every JSONPath expression that always produces a singular nodelist is a Singular Query.

Note: This definition is based on the syntactical definition of Section 2.3.5.1; JSONPath expressions that always produce a singular nodelist but do not match that syntax are not Singular Queries.

gregsdennis commented 11 months ago

I agree with adding a note. Thanks for the discussion.

glyn commented 11 months ago

I'm writing a PR and, for consistency, I think we should add a similar note to the definition of Normalized Path.