jwadhams / json-logic

Build complex rules and serialize them to JSON
MIT License
114 stars 13 forks source link

Add a "length" operation. #4

Open jwadhams opened 6 years ago

jwadhams commented 6 years ago

For strings, returns their length in characters. (Note there can be oddities in a language's string length calculation, like JavaScript's "🤔 ".length === 2)

For arrays, returns the number of elements.

For non-countables (null, boolean, objects, numbers) returns 0 (zero)

Should internally use the widest idiomatic counting solution in the target language (e.g. the length magic parameter in JavaScript, the count() method and Countable interface in PHP, the len function and __len__ special method in Python, etc.)

Note, this is going to have a really hard relationship with the unary sugar. This could be ambiguous {"length":["apple"]} -- am I counting a one-element-array or a five-letter-word? I think we have to side with "assume the rule author is not using unary syntax." which means arrays have to be written {"length":[ [1,2,3] ]}

jwadhams commented 6 years ago

Proposed tests, in the common test format from http://jsonlogic.com/tests.json like

[ test, data, expected result ]

"Unary syntax sugar, interpreted as one string arg",
[ {"length":"apple"}, null, 5], 
"Normal syntax, interpreted as one string arg",
[ {"length":["apple"]}, null, 5],
"Interpreted as one argument, an array with one element",
[ {"length":[ ["apple"] ]}, null, 1],

"Interpreted as two string arguments, second is ignored.",
[ {"length":["apple", "banana"]}, null, 5],
"Interpreted as one array argument",
[ {"length":[ ["apple", "banana"] ]}, null, 2],

"Unlengthable",
[ {"length":null}, null, 0],
[ {"length":[null]}, null, 0],
[ {"length":false}, null, 0],
[ {"length":[false]}, null, 0],
[ {"length":true}, null, 0],
[ {"length":[true]}, null, 0],
[ {"length":42}, null, 0],
[ {"length":[42]}, null, 0],
[ {"length":{"var":"a"}}, {"a":{"b":"banana"}}, 0],
[ {"length":[{"var":"a"}]}, {"a":{"b":"banana"}}, 0],
MatissJanis commented 6 years ago

Yes, please 👍

ilons commented 6 years ago

Yes, this would be quite useful. In the meantime, one could do this to count elements in an array:

{
    "reduce": [
        {"map": [[1, 2, 3, 4], {"if": [{"var": ""}, 1, 0]}]},
        {"+": [{"var": "current"}, {"var": "accumulator"}]},
        0
    ]
}
atulagrawal commented 5 years ago

May i know what is pending for this Pull Request?

edene commented 4 years ago

FYI, the simpler way to get the length of an array would be:

{
    "reduce": [
        [1, 2, 3, 4],
        {"+": [1, {"var": "accumulator"}]},
        0
    ]
}
danielwolf1 commented 2 years ago

Are there plans to add this operation?

xStoryTeller commented 4 months ago

Has there been any updates to this? I see work-arounds for arrays but we have a use case where we need this for strings. So for example, a string needs to have at least 5 characters ( length >= 5 ).

evenflow58 commented 2 months ago

I may have this wrong but it seems to work in my tests bed. You can check string length by just using the length property of a string. Something like

{ ">=": [ "var": "some.string.object.here.length" ], 100}