JsonLogic.Net icon indicating copy to clipboard operation
JsonLogic.Net copied to clipboard

Different behaviour than on jsonLogic.com for some operators

Open kph21 opened this issue 6 years ago • 2 comments

Hi, my team and I recently discovered that the "+" and "*" operators don't work exactly as documented on the jsonLogic site. It appears like your implementation avoids having null values when working with these operators and tries to return a non-null value while the jsonLogic site returns null.

i.e. for 0 + null, jsonLogic site returns null while this library returns 0.

However, we have a use case to return null when evaluating the logic and have thus implemented the following operators:

operators.DeleteOperator("+");
operators.AddOperator("+", (p, args, data) => Min2From(args.Select(a => p.Apply(a, data))).Aggregate((prev, next) =>
            {
                try { return prev != null ? (double?)(Convert.ToDouble(prev) + Convert.ToDouble(next)) : null; }
                catch { return prev.ToString() + next.ToString(); }
            }));

operators.DeleteOperator("*");
operators.AddOperator("*", ReduceDoubleArgs(null, (prev, next) => (next == null) ? null : prev * next));

Perhaps this support for returning null values can be added as part of some settings, should you see fit.

kph21 avatar Sep 19 '19 09:09 kph21

@kph21, Thanks for providing code sample for the expected behavior. I will review the differences. Meanwhile, if you do a pull request with the tests and the fix, we might get it patched up in nuget faster. :)

yavuztor avatar Oct 05 '19 16:10 yavuztor

Hello, I might have run into something similar.

The following rule results in a NullReferenceException. {">=": [null, 60]}"

The javascript version seems to treats null as 0. For compatibility reasons I have this workaround. Not sure if this is the correct way of solving it or if there are more edge cases. Perhaps something to consider adding to the library.

operators.AddOperator(">=", DoubleArgsSatisfy2((a, b) => a >= b));
operators.AddOperator("<=", DoubleArgsSatisfy2((a, b) => a <= b));
...

public static bool IsNull(this JToken token)
    {
        return (token == null) ||
               (token.Type == JTokenType.Object && !token.HasValues) ||
               (token.Type == JTokenType.Null);
    }

private static Func<IProcessJsonLogic, JToken[], object, object> DoubleArgsSatisfy2(Func<double, double, bool> criteria)
        {
            return (p, args, data) => {
                var values = args.Select(a => ((a == null) || a.IsNull()) ? 0d : Double.Parse(p.Apply(a, data).ToString())).ToArray();
                for (int i = 1; i < values.Length; i++) {
                    if (!criteria(values[i-1], values[i])) return false;
                }
                return true;
            };
        }

Thanks

samvik avatar Jan 13 '20 09:01 samvik