Proposal - val and context replacements
#18
Replies: 8 comments 23 replies
-
|
I'm flagging this as "draft"; I'd like to request input on |
Beta Was this translation helpful? Give feedback.
-
|
Couple of remarks w.r.t.
|
Beta Was this translation helpful? Give feedback.
-
|
A note, potentially for another proposal 😬. It also seems likely to me that if we introduce I know we're aiming to keep operator introductions low, but if we're deprecating 3 operators... 😅 |
Beta Was this translation helpful? Give feedback.
-
|
Hey folks, I've revised the proposal a bit. At the moment, I've included all three operators:
We could choose to separate |
Beta Was this translation helpful? Give feedback.
-
|
I'm undrafting this, @json-logic/tc, @rmannibucau Do y'all have any thoughts / objections? I'm voting with a This is a bit of a leap, so I'm going to try to aim for an aggregate score of 4 before proceeding (existing voting rules apply, but I'm hoping for decent consensus on this). To clarify, community votes count towards the aggregate score. Community objections will also be noted, and consensus will be sought out. This proposal is the result of a community objection. |
Beta Was this translation helpful? Give feedback.
-
|
Just so the RFC 6901 option doesn't live in isolation, maybe it's a good idea to include RFC 9535 (JSON Path) as another option. |
Beta Was this translation helpful? Give feedback.
-
|
I believe this proposal has met the TC criteria to move forward; so I'm marking it as approved, but I'd like @toddbaert to weigh in and give the community some time to voice any objections. TC Votes
With While I'd like to settle one more proposal (deciding if we're going to support implicit application / operator chaining), I think this opens the door for us to begin the process of evaluating each existing operator. |
Beta Was this translation helpful? Give feedback.
-
|
Important While I failed to explicitly communicate it, the tests codify that JSON Logic uses zero-based indexing for This detail will be important to include in the RFC / formal specification we produce. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Background
Hey folks! I expect this to be one of the more difficult proposals.
Some previous discussions:
And some commentary here:
In JSON Logic, there are a handful of keys that are inaccessible from JSON Logic.
Examples include:
{ "": 7 }{ "hello.world": 7 },{ ".": 8 }{ ".": { "": 9 } }Getting to the point:
var,missingandmissing_someare controversial operators.They are controversial because:
varwith improvements without reinventing RFC6901.Proposal
var,missingandmissing_someinto the "Legacy" extension for JSON Logic. This means excluding them from the JSON Logic Core RFC. As a community extension, they still appear in Compat Tables.valvalcould be an operator where you explicitly define the path in the arguments, making it more AST-like.By doing this, you could more easily chain things to
val, like anrfc6901custom operator,{ "val": { "rfc6901": "/hello/world" } }Another operator we might introduce is
exists, which receives the same arguments asval, but returns abooleanOne more operator we'd probably want to introduce is
??or "coalesce", which is similar to "or", but performs a nullish check rather than a truthiness check. Very similar to https://www.geeksforgeeks.org/postgresql-coalesce/Arguments
number/stringare used as pathing argumentsarrayis something I'd like to leave as placeholder, likely for scope control.null/boolean/objectare defined as error behavior. I'd like to discuss how we test for errors in another proposal.Test Cases / Showing how the Operators Work
val[ "Test Specification for val", { "description": "Fetches a value", "rule": { "val": "hello" }, "data": { "hello" : 0 }, "result": 0 }, { "description": "Fetches a nested value", "rule": { "val": ["hello", "world"] }, "data": { "hello" : { "world": 1 } }, "result": 1 }, { "description": "Fetches a value from an empty key", "rule": { "val": "" }, "data": { "" : 1 }, "result": 1 }, { "description": "Fetches a value from a nested empty key", "rule": { "val": ["", ""] }, "data": { "" : { "": 2 } }, "result": 2 }, { "description": "Fetches a value from an array", "rule": { "val": [1] }, "data": [1, 2], "result": 2 }, { "description": "Fetches a value from an array in an object", "rule": { "val": ["arr", 1] }, "data": { "arr": [1, 2] }, "result": 2 }, { "description": "Fetches a value from a doubly nested empty key", "rule": { "val": ["", "", ""] }, "data": { "" : { "": { "": 3 } } }, "result": 3 }, { "description": "Fetches a value from a key that is purely a dot", "rule": { "val": "." }, "data": { "." : 20 }, "result": 20 }, { "description": "Fetching a value from null returns null", "rule": { "val": "hello" }, "data": { "hello" : null }, "result": null }, { "description": "Fetching a value from a null fetched value returns null", "rule": { "val": ["hello", "world"] }, "data": { "hello" : null }, "result": null }, { "description": "Fetches the entire context", "rule": { "val": [] }, "data": { "": 21 }, "result": { "": 21 } }, { "description": "Fetches the entire context for a nested key", "rule": { "val": "" }, "data": { "": { "": 22 } }, "result": { "": 22 } }, { "description": "Using val in a map", "rule": { "map": [[1,2,3], { "+": [{ "val": [] }, 1] }] }, "data": null, "result": [2,3,4] } ]exists[ "Test Specification for exists", { "description": "Checks if a normal key exists", "rule": { "exists": "hello" }, "data": { "hello" : 1 }, "result": true }, { "description": "Checks if a normal key exists (array)", "rule": { "exists": ["hello"] }, "data": { "hello" : 1 }, "result": true }, { "description": "Checks if a normal key exists (false)", "rule": { "exists": "hello" }, "data": { "world" : 1 }, "result": false }, { "description": "Checks if an empty key exists (true)", "rule": { "exists": [""] }, "data": { "" : 1 }, "result": true }, { "description": "Checks if an empty key exists (false)", "rule": { "exists": [""] }, "data": { "hello" : 1 }, "result": false }, { "description": "Checks if a nested key exists", "rule": { "exists": ["hello", "world"] }, "data": { "hello" : { "world": false } }, "result": true }, { "description": "Checks if a nested key exists (false)", "rule": { "exists": ["hello", "world"] }, "data": { "hello" : { "x": false } }, "result": false }, { "description": "Checks if a null value exists", "rule": { "exists": "hello" }, "data": { "hello" : null }, "result": true } ]??[ "Test Specification for ??", { "description": "Coalesces a string alone", "rule": { "??": ["hello"] }, "data": null, "result": "hello" }, { "description": "Coalesces a number alone", "rule": { "??": [1] }, "data": null, "result": 1 }, { "description": "Coalesces a boolean alone", "rule": { "??": [true] }, "data": null, "result": true }, { "description": "Coalesces an object from context alone", "rule": { "??": [{ "val": "person" }]}, "data": { "person": { "name": "John" } }, "result": { "name": "John" } }, { "description": "Empty behavior", "rule": { "??": [] }, "data": null, "result": null }, { "description": "Coalesces a string with nulls before", "rule": { "??": [null, "hello"] }, "data": null, "result": "hello" }, { "description": "Coalesces a string with multiple nulls before", "rule": { "??": [null, null, null, "hello"] }, "data": null, "result": "hello" }, { "description": "Coalesces a string with nulls after", "rule": { "??": ["hello", null] }, "data": null, "result": "hello" }, { "description": "Coalesces a string with nulls both before and after", "rule": { "??": [null, "hello", null] }, "data": null, "result": "hello" }, { "description": "Coalesces a number with nulls both before and after", "rule": { "??": [null, 1, null] }, "data": null, "result": 1 }, { "description": "Uses the first non-null value", "rule": { "??": [null, 1, "hello"] }, "data": null, "result": 1 }, { "description": "Uses the first non-null value, even if it is false", "rule": { "??": [null, false, "hello"] }, "data": null, "result": false }, { "description": "Uses the first non-null value from context", "rule": { "??": [{ "val": ["person", "name"] }, { "val": "name" }, "Unknown Name"] }, "data": { "person": { "name": "John" }, "name": "Jane" }, "result": "John" }, { "description": "Uses the first non-null value from context (with person undefined)", "rule": { "??": [{ "val": ["person", "name"] }, { "val": "name" }, "Unknown Name"] }, "data": { "name": "Jane" }, "result": "Jane" }, { "description": "Uses the first non-null value from context (without any context)", "rule": { "??": [{ "val": ["person", "name"] }, { "val": "name" }, "Unknown Name"] }, "data": {}, "result": "Unknown Name" } ]Probable Objections
valuse RFC6901?This... is a reasonable alternative. I assume this will be debated, but I like the
AST-like nature this enables here, and I like how this allows us to avoid embedding a string parsing spec.Out of Scope
Scopes
Scopes are out of scope for this proposal. I have experimented with a syntax for this,
{ "val": [[2], "hello"] }This would ascend two scopes to get "hello", but this is not part of this specific proposal.
Beta Was this translation helpful? Give feedback.
All reactions