json-logic-js
json-logic-js copied to clipboard
Data is not used by "some"
I expected the following to evaluate to true
:
Data:
{"input": "x"}
Rule:
{
"and": [
{
"some": [
[
"x",
"y"
],
{
"===": [
{
"var": ""
},
{
"var": "input"
}
]
}
]
}
]
}
If I use a literal value instead of "var": "input"
, it does evaluate to true
:
{
"and": [
{
"some": [
[
"x",
"y"
],
{
"===": [
{
"var": ""
},
"x"
]
}
]
}
]
}
thaaaat sucks. That's a design flaw, all the example cases I considered only used literal and the value being tested inside the test.
I'm open to suggestion on how to design a fix for this. One way would be to make the data being used inside the test actually a copy-and-extend of data. Like if data = {"input":"x"}
then data inside the filter function is {"item":"x","input":"x"}
on the first iteration and {"item":"y","input":"x"}
on the second. If I patched filter
like:
}else if(op === 'filter'){
scopedData = jsonLogic.apply(values[0], data);
scopedLogic = values[1];
if ( ! Array.isArray(scopedData)) {
return [];
}
// Return only the elements from the array in the first argument,
// that return truthy when passed to the logic in the second argument.
return scopedData.filter(function(item){
var item_and_globals = beget(data);
item_and_globals.item = item;
return jsonLogic.truthy( jsonLogic.apply(scopedLogic, item_and_globals));
});
(Beget implementation is something like function beget(o){ return jQuery.extend({}, o); }
)
and your rule changed to:
{
"and": [
{
"some": [
[
"x",
"y"
],
{
"===": [
{
"var": "item"
},
{
"var": "input"
}
]
}
]
}
]
}
This is based in part on how reduce uses named parameters current
and accumulator
(For parity I'd also be open to using current
instead of item
in filter, I just wrote all my test code without considering that 🙃)
This seems reasonable to me. I don’t really have a horse in the game as to whether the API should expect current
or item
. Assuming you choose current
(as you say, for parity), it would probably be nice if all functor operations – e.g., map
– also accepted {"var": "current"}
to mean “the entire array element within the test.”
Thanks for the speedy response!
One other thought: I do like the terseness of {"var": ""}
. Perhaps, instead of current
or whatever, the API might expect something nearly as terse. Maybe {"var": "_"}
?
Or wouldn’t you get the same effect yet be able to use {"var": ""}
with the following?
return scopedData.filter(function(item){
var item_and_globals = beget(data);
item_and_globals[''] = item;
Seems like you should be able to explicitly name the iterator. That way you could do multiple levels of nesting. Here's the operation for "non-empty intersection":
{ some: ['i', [1, 2, 3, 4, 5],
{ some: ['j', [5, 6, 7, 8, 9],
{ '===': [{ var: 'i' }, { var: 'j' }]}
]}
]}
@mhelvens does it work for you? Or it's just a concept for improvements?
I am running into this exact problem as well. I see that this issue is still open, has anyone been able to come up with a workaround (other than defining custom operators)?