json-logic-js icon indicating copy to clipboard operation
json-logic-js copied to clipboard

Not possible to use 0 in if/or/and?

Open dextervanroo opened this issue 4 years ago • 6 comments

Hello. I'm trying to write a code for a data interval check and I was having trouble at first with the nested-if logic. After reading #69 I think got it right. What I'm trying to do is the following:

  1. if data.km or km is false, return erro1
  2. elif 0 <= data.km or km <= 2.352, return aqui
  3. elif 4.916 <= data.km or km <= 16.846, return embaixo
  4. else return errei
{
	"if": [{
		"or": [{
			"===": [{
				"var": "data.km"
			}, false]
		}, {
			"===": [{
				"var": "km"
			}, false]
		}]
	}, "erro1", {
		"or": [{
			"and": [{
				"**>=**": [{
					"var": "data.km"
				}, 0]
			}, {
				"<=": [{
					"var": "data.km"
				}, 2.352]
			}]
		}, {
			"and": [{
				"**>=**": [{
					"var": "km"
				}, 0]
			}, {
				"<=": [{
					"var": "km"
				}, 2.352]
			}]
		}]
	}, "aqui", {
		"or": [{
			"and": [{
				">=": [{
					"var": "data.km"
				}, 4.916]
			}, {
				"<=": [{
					"var": "data.km"
				}, 16.846]
			}]
		}, {
			"and": [{
				">=": [{
					"var": "km"
				}, 4.916]
			}, {
				"<=": [{
					"var": "km"
				}, 16.846]
			}]
		}]
	}, "embaixo", "errei"]
}

The problem is that this logic only works if I remove the = part of the highlighted >=. Am I doing something wrong or is this intended behavior?

dextervanroo avatar Jan 08 '21 21:01 dextervanroo

@dextervanroo, in case this issue is still something that you are struggling with, could you please provide an example of a data object that you are using in your tests that causes this issue. I've performed a few quick tests and it looks like that everything works as expected. I suspect this is due to the data object that I'm using for my tests.

shupoval avatar Mar 13 '21 14:03 shupoval

@shupoval If I use {"km":10} in the data test, it should return embaixo, but it returns aqui. If I remove the = part in the highlighted terms, it correctly returns embaixo.

dextervanroo avatar Mar 17 '21 21:03 dextervanroo

@dextervanroo, thank you for the clarification. It is clear now.

The long story short, in case {"var": "data.km"} and data.km is not defined, JsonLogic's var operator defaults it to the null value (if no default value was specified in the logic's expression). Btw, it is possible to specify default value by using the following syntax {"var": ["data.km", DEFAULT_VALUE_GOES_HERE]}. After that JavaScript's NULL Comparison takes place and this is true for all comparison operators (not only >= or <=).

@jwadhams, shouldn't we come up with something similar to the Truthy and Falsy in case of comparison operators in order to make JsonLogic's rules return the same results when executed by different languages?

@dextervanroo, I'd like to suggest you to switch from the {"var": "SOME_DATA_PATH"} to the {"var": ["SOME_DATA_PATH", DEFAULT_VALUE_GOES_HERE]} syntax in order to have consitant and predictable results in case of undefined/missed data represented by "SOME_DATA_PATH" reference.

shupoval avatar Mar 18 '21 04:03 shupoval

Seems like this issue is related to #44 and #60

shupoval avatar Mar 18 '21 10:03 shupoval

@shupoval But why is it that the code works just by removing the = signs, like this:

{
	"if": [{
		"or": [{
			"===": [{
				"var": "data.km"
			}, false]
		}, {
			"===": [{
				"var": "km"
			}, false]
		}]
	}, "erro1", {
		"or": [{
			"and": [{
				"**>=**": [{
					"var": "data.km"
				}, 0]
			}, {
				"<=": [{
					"var": "data.km"
				}, 2.352]
			}]
		}, {
			"and": [{
				"**>=**": [{
					"var": "km"
				}, 0]
			}, {
				"<=": [{
					"var": "km"
				}, 2.352]
			}]
		}]
	}, "aqui", {
		"or": [{
			"and": [{
				">=": [{
					"var": "data.km"
				}, 4.916]
			}, {
				"<=": [{
					"var": "data.km"
				}, 16.846]
			}]
		}, {
			"and": [{
				">=": [{
					"var": "km"
				}, 4.916]
			}, {
				"<=": [{
					"var": "km"
				}, 16.846]
			}]
		}]
	}, "embaixo", "errei"]
}

Same test parameter ({"km":10})

dextervanroo avatar Mar 26 '21 00:03 dextervanroo

@dextervanroo, the reason is due to how javascript evaluates NULL comparison:

  • null > 0 evaluates into false
  • null >= 0 evaluates into true

In your case when data is {"km":10} which means {"var": "data.km"} evaluates into null and that is why the second if evaluetes into true and "aqui" string is printed out due to the following expression:

if((null >= 0 && null <= 2.352) || (10 >= 0 && 10 <= 2.352)) 
    console.log("aqui");

shupoval avatar Mar 26 '21 17:03 shupoval