Proposal - If / And / Or #31
Replies: 4 comments 7 replies
-
|
Comments from Slack:
I actually kinda agree with @JTeeuwissen, but I'm also aiming for consistency across the operators + backwards compat, hence why I recommended |
Beta Was this translation helpful? Give feedback.
-
|
Placeholder for tracking votes. Current Votes
|
Beta Was this translation helpful? Give feedback.
-
|
Removing Draft Status as Truthiness Proposal has advanced. |
Beta Was this translation helpful? Give feedback.
-
|
I've modifed the proposal here to switch I'm... still leaving it in pending, there's some discussion in Slack right now that I think we need to get sync'd on, There's debate over whether |
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
This proposal is meant to codify tests and boundaries for some of the notable control structures in JSON Logic, namely
if,orandand.Each of these operators are "lazy" (with full control of their traversal) and short circuit without evaluating unnecessary branches.
Proposal
Most of the test cases come from
tests.json, with some additional checks thrown in.Some notable additions:
throw.Tests
if[ "Boolean checks", { "description": "true is true, and uses the then", "rule": { "if": [true, "apple", "banana"] }, "data": null, "result": "apple" }, { "description": "false is false, and uses the fallback", "rule": { "if": [false, "apple", "banana"] }, "data": null, "result": "banana" }, "Null check", { "description": "null is falsy", "rule": { "if": [null, "apple", "banana"] }, "data": null, "result": "banana" }, "Object checks", { "description": "Empty object is falsy.", "rule": { "if": [{}, "apple", "banana"] }, "data": null, "result": "banana" }, { "description": "Objects are truthy, with keys defined", "rule": { "if": [{ "val": [] }, "apple", "banana"] }, "data": { "some": "value" }, "result": "apple" }, "Array checks", { "description": "Empty array is falsy", "rule": { "if": [[], "apple", "banana"] }, "data": null, "result": "banana" }, { "description": "Array with single element is truthy", "rule": { "if": [[1], "apple", "banana" ] }, "data": null, "result": "apple" }, { "description": "Array with multiple elements is truthy", "rule": { "if": [[1, 2, 3, 4], "apple", "banana" ] }, "data": null, "result": "apple" }, "String checks", { "description": "Empty string is falsy", "rule": { "if": ["", "apple", "banana"] }, "data": null, "result": "banana" }, { "description": "Any non-empty string is truthy", "rule": { "if": ["zucchini", "apple", "banana"] }, "data": null, "result": "apple" }, { "description": "Any non-empty string is truthy, even 0", "rule": { "if": ["0", "apple", "banana"] }, "data": null, "result": "apple" }, "Too few arguments", { "description": "No arguments is just null.", "rule": { "if": [] }, "data": null, "result": null }, { "description": "If no 'then' is defined, it should return the first argument (true)", "rule": { "if": [true] }, "data": null, "result": true }, { "description": "If no 'then' is defined, it should return the first argument (false)", "rule": { "if": [false] }, "data": null, "result": false }, { "description": "If no 'then' is defined, it should return the first argument (apple string)", "rule": { "if": ["apple"] }, "data": null, "result": "apple" }, { "description": "When truthy, it'll return the 'then' even if no fallback is defined.", "rule": { "if": [true, "apple"] }, "data": null, "result": "apple" }, { "description": "When falsy, it'll return null if the fallback is not defined, even if the 'then' is defined.", "rule": { "if": [false, "apple"] }, "data": null, "result": null }, "Variadic Tests", { "description": "Returns the first truthy if condition", "rule": { "if": [true, "apple", false, "banana"] }, "data": null, "result": "apple" }, { "description": "Returns the first truthy then condition, even if multiple conditions are true", "rule": { "if": [true, "apple", true, "banana"] }, "data": null, "result": "apple" }, { "description": "Retuns the first truthy condition, with the fallback defined.", "rule": { "if": [true, "apple", false, "banana", "carrot"] }, "data": null, "result": "apple" }, { "description": "Returns the first truthy condition, with the fallback defined; multiple true conditions.", "rule": { "if": [true, "apple", true, "banana", "carrot"] }, "data": null, "result": "apple" }, { "description": "Returns the first truthy condition, with the first condition falsy. Fallback defined.", "rule": { "if": [false, "apple", true, "banana", "carrot"] }, "data": null, "result": "banana" }, { "description": "Returns the first truthy condition, in this case it's the 2nd one.", "rule": { "if": [false, "apple", true, "banana"] }, "data": null, "result": "banana" }, { "description": "When none of the conditions are true, it returns the fallback.", "rule": { "if": [false, "apple", false, "banana", "carrot"] }, "data": null, "result": "carrot" }, { "description": "When none of the conditions are true, it returns the fallback. In this case the fallback is not defined, so it is null.", "rule": { "if": [false, "apple", false, "banana"] }, "data": null, "result": null }, { "description": "3 Conditions, all falsy. Returns fallback.", "rule": { "if": [false, "apple", false, "banana", false, "carrot", "date"] }, "data": null, "result": "date" }, { "description": "3 Conditions, all falsy, no fallback defined. Returns null.", "rule": { "if": [false, "apple", false, "banana", false, "carrot"] }, "data": null, "result": null }, { "description": "First condition truthy, 3 conditions.", "rule": { "if": [true, "apple", false, "banana", false, "carrot", "date"] }, "data": null, "result": "apple" }, { "description": "2nd Condition is Truthy", "rule": { "if": [false, "apple", true, "banana", false, "carrot", "date"] }, "data": null, "result": "banana" }, { "description": "Third Condition is Truthy", "rule": { "if": [false, "apple", false, "banana", true, "carrot", "date"] }, "data": null, "result": "carrot" }, { "description": "Returns first truthy value, some conditions truthy", "rule": { "if": [false, "apple", true, "banana", true, "carrot", "date"] }, "data": null, "result": "banana" }, { "description": "Returns first truthy value, some conditions truthy (2)", "rule": { "if": [true, "apple", false, "banana", true, "carrot", "date"] }, "data": null, "result": "apple" }, { "description": "Returns first truthy value, some conditions truthy (3)", "rule": { "if": [true, "apple", true, "banana", false, "carrot", "date"] }, "data": null, "result": "apple" }, { "description": "Returns first truthy value, all conditions truthy", "rule": { "if": [true, "apple", true, "banana", true, "carrot", "date"] }, "data": null, "result": "apple" }, "Some Variadic Checks with Other Types", { "description": "Returns first truthy value, some conditions truthy (4)", "rule": { "if": [false, "apple", [1], "banana", true, "carrot", "date"] }, "data": null, "result": "banana" }, { "description": "Returns first truthy value, some conditions truthy (5)", "rule": { "if": [false, "apple", "This is true", "banana", true, "carrot", "date"] }, "data": null, "result": "banana" }, { "description": "Returns first truthy value, some conditions truthy (6)", "rule": { "if": [null, "apple", 0, "banana", 7, "carrot", "date"] }, "data": null, "result": "carrot" }, { "description": "Returns first truthy value, some conditions truthy (7)", "rule": { "if": ["0", "apple", 0, "banana", 7, "carrot", "date"] }, "data": null, "result": "apple" }, { "description": "Returns first truthy value, some conditions truthy (8)", "rule": { "if": [{}, "apple", 0, "banana", 7, "carrot", "date"] }, "data": null, "result": "carrot" }, { "description": "Returns first truthy value, some conditions truthy (9)", "rule": { "if": [{ "val": "a" }, "apple", 0, "banana", 7, "carrot", "date"] }, "data": { "a": { "b": 1 } }, "result": "apple" }, "Bad Arguments", { "description": "If with non-array arguments throws", "rule": { "if": "apple" }, "data": null, "error": { "type": "Invalid Arguments" } }, "Short circuiting check", { "description": "If will not evaluate then branch if the condition is false", "rule": { "if": [false, { "throw": "Not Lazy" }, "banana"] }, "data": null, "result": "banana" }, { "description": "If will not evaluate fallback branch if the condition is true", "rule": { "if": [true, "apple", { "throw": "Not Lazy" }] }, "data": null, "result": "apple" }, { "description": "If will not evaluate other branches or checks if a prior condition is true", "rule": { "if": [false, { "throw": "Not Lazy" }, true, "apple", { "throw": "Not Lazy" }, { "throw": "Not Lazy" }, { "throw": "Not Lazy" }] }, "data": null, "result": "apple" }, { "description": "No branches except the fallback check will be evaluated if the condition is false", "rule": { "if": [false, { "throw": "Not Lazy" }, false, { "throw": "Not Lazy" }, false, { "throw": "Not Lazy" }, "carrot"] }, "data": null, "result": "carrot" } ]and[ "Basic Checks", { "description": "Two true values should be true", "rule": { "and": [true, true] }, "data": null, "result": true }, { "description": "false and true should be false", "rule": { "and": [false, true] }, "data": null, "result": false }, { "description": "true and false should be false", "rule": { "and": [true, false] }, "data": null, "result": false }, { "description": "Two false values should be false", "rule": { "and": [false, false] }, "data": null, "result": false }, { "description": "All true values should be true", "rule": { "and": [true, true, true] }, "data": null, "result": true }, { "description": "Any false value should be false", "rule": { "and": [true, true, false] }, "data": null, "result": false }, { "description": "And with a single false value should be false", "rule": { "and": [false] }, "data": null, "result": false }, { "description": "When all values are truthy, the last truthy value should be returned", "rule": { "and": [1, 2, 3] }, "data": null, "result": 3 }, { "description": "When all values are truthy, the last truthy value should be returned (2)", "rule": { "and": [true, 1, {}] }, "data": null, "result": {} }, { "description": "And with a single falsey value should be return the falsy value", "rule": { "and": [[]] }, "data": null, "result": [] }, { "description": "And with a single falsey value should be return the falsy value (2)", "rule": { "and": [0] }, "data": null, "result": 0 }, { "description": "And with a single falsey value should be return the falsy value (3)", "rule": { "and": [""] }, "data": null, "result": "" }, { "description": "And with a single true value should be true", "rule": { "and": [true] }, "data": null, "result": true }, { "description": "And with 2 truthy values should return the last truthy value", "rule": { "and": [1, 3] }, "data": null, "result": 3 }, { "description": "And with a truthy value and a false value should return the false value", "rule": { "and": [3, false] }, "data": null, "result": false }, { "description": "And with a truthy value and a false value should return the false value (2)", "rule": { "and": [false, 3] }, "data": null, "result": false }, { "description": "Empty array is falsy, so it is returned", "rule": { "and": [[], true] }, "data": null, "result": [] }, { "description": "0 is falsy, so it is returned", "rule": { "and": [0, true] }, "data": null, "result": 0 }, { "description": "Empty string is falsy, so it is returned", "rule": { "and": ["", true] }, "data": null, "result": "" }, { "description": "0 as a string is truthy, so the last truthy value is returned", "rule": { "and": ["0", true] }, "data": null, "result": true }, { "description": "And with no arguments should return null", "rule": { "and": [] }, "data": null, "result": null }, "Valid Arguments Checks", { "description": "And with non-array arguments should throw", "rule": { "and": true }, "data": null, "error": { "type": "Invalid Arguments" } }, "Short Circuiting Checks", { "description": "And will not interpret the second argument if the first is false", "rule": { "and": [false, { "throw": "Not Lazy" }] }, "data": null, "result": false }, { "description": "And will not interpret the second argument if the first is falsy", "rule": { "and": [0, { "throw": "Not Lazy" }] }, "data": null, "result": 0 }, { "description": "And will not interpret the nth argument if any value before it is false", "rule": { "and": [true, 1, 2, 3, 4, [], { "throw": "Not Lazy" }] }, "data": null, "result": [] } ]or[ "Basic Checks", { "description": "Two true values should be true", "rule": { "or": [true, true] }, "data": null, "result": true }, { "description": "false or true should be true", "rule": { "or": [false, true] }, "data": null, "result": true }, { "description": "true or false should be true", "rule": { "or": [true, false] }, "data": null, "result": true }, { "description": "Two false values should be false", "rule": { "or": [false, false] }, "data": null, "result": false }, { "description": "All true values should be true", "rule": { "or": [true, true, true] }, "data": null, "result": true }, { "description": "Any true value should be true", "rule": { "or": [true, true, false] }, "data": null, "result": true }, { "description": "Or with a single true value should be true", "rule": { "or": [true] }, "data": null, "result": true }, { "description": "When all values are truthy, the first truthy value should be returned", "rule": { "or": [1, 2, 3] }, "data": null, "result": 1 }, { "description": "When all values are truthy, the first truthy value should be returned (2)", "rule": { "or": [true, 1, {}] }, "data": null, "result": true }, { "description": "Or with a single falsey value should be return the falsy value", "rule": { "or": [[]] }, "data": null, "result": [] }, { "description": "Or with a single falsey value should be return the falsy value (2)", "rule": { "or": [0] }, "data": null, "result": 0 }, { "description": "Or with a single falsey value should be return the falsy value (3)", "rule": { "or": [""] }, "data": null, "result": "" }, { "description": "Or with a single false value should be false", "rule": { "or": [false] }, "data": null, "result": false }, { "description": "Or with 2 truthy values should return the first truthy value", "rule": { "or": [1, 3] }, "data": null, "result": 1 }, { "description": "Or with a truthy value and a false value should return the truthy value", "rule": { "or": [3, false] }, "data": null, "result": 3 }, { "description": "Or with a truthy value and a false value should return the truthy value (2)", "rule": { "or": [false, 3] }, "data": null, "result": 3 }, { "description": "Empty array is falsy, so it is not returned if the second argument is truthy", "rule": { "or": [[], true] }, "data": null, "result": true }, { "description": "0 is falsy, so it is not returned if the second argument is truthy", "rule": { "or": [0, true] }, "data": null, "result": true }, { "description": "Empty string is falsy, so it is not returned if the second argument is truthy", "rule": { "or": ["", true] }, "data": null, "result": true }, { "description": "0 as a string is truthy, so the first truthy value is returned", "rule": { "or": ["0", true] }, "data": null, "result": "0" }, { "description": "Or with no arguments should return null", "rule": { "or": [] }, "data": null, "result": null }, "Valid Arguments Checks", { "description": "Or with non-array arguments should throw", "rule": { "or": true }, "data": null, "error": { "type": "Invalid Arguments" } }, "Short Circuiting Checks", { "description": "Or will not interpret the second argument if the first is false", "rule": { "or": [true, { "throw": "Not Lazy" }] }, "data": null, "result": true }, { "description": "Or will not interpret the second argument if the first is falsy", "rule": { "or": [1, { "throw": "Not Lazy" }] }, "data": null, "result": 1 }, { "description": "Or will not interpret the nth argument if any value before it is false", "rule": { "or": [false, 0, null, { "val": [] }, [], 4, { "throw": "Not Lazy" }] }, "data": null, "result": 4 } ]Beta Was this translation helpful? Give feedback.
All reactions