Mutai Mwiti
Mutai Mwiti

Reputation: 487

How can I compile and evaluate logical operators and operands specified on an object?

Is there a compiler or an easy way I can compile and evaluate logical operators and operands specified on an object. This is to akin to mongodb $or and $and operators. For example:

return {
  $or: [
    foo: [...],
    bar: [...]
  ]
}

When the compiler encounters foo it will call a corresponding function with the value provided for the same. The same goes for bar. It will then logical OR the results of the two operations. I want to handle $and and $or operators. I would do simple checks for such a simple example but I want to have the ability to nest the logical operators. A complex example:

return {
  $or: [
    { 
      $and: [
        { foo: [...] }, 
        { bar: [...] }
      ] 
    }, 
    { baz: [...] }, 
    () => m < n
  ]
}

Simplified definition of foo, bar and baz:

export const evalFoo = items => {
  return items.indexOf("foo") >= 0;
};

export const evalBar = items => {
  return items.indexOf("bar") >= 0;
};

export const evalBaz = items => {
  return items.indexOf("baz") >= 0;
};

Sample data:

Set 1

m = 4; n = 1; foo: ['foo', 'x']; bar: ['bar', 'y']; baz: ['baz', 'z']

RESULT = true; // because $and results to true.

Set 2

m = 4; n = 1; foo: ['x']; bar: ['y']; baz: ['x']

RESULT = false; // because m > n and $and results to false.

Set 3

m = 1; n = 3; foo: ['x']; bar: ['y']; baz: ['x']

RESULT = true; // because m < n.

Set 4

m = 3; n = 1; foo: ['x']; bar: ['bar']; baz: ['z']

RESULT = true; // because m > n, baz() is false and x and $and is false.

Upvotes: 3

Views: 199

Answers (1)

Nina Scholz
Nina Scholz

Reputation: 386650

You could take something like this, where you differentiate between $and and $or or the functions.

It works by taking an object with the keys for array methods like Array#every, which acts like a logical and by testing the values in an object and return true if all items with their callbacks return a truthy value. Analogous works Array#some, but there is only one item necessary which callback returns a truthy value.

The other object contains functions and allows to access them by using the key.

The first par checks if the parameter is a function and if so, it returns the result of the call.

Then the parameter gets a check and if falsy, like null or if the value is not an object, the function terminates with false.

For taking a key/value pair a destructuring assignment takes place with the first entry from the object.

If key is in the operator object, the value is taken as method for iterating the value and returned.

If key is in the functions object, then the function is called with value as parameter and returned.

Finally a false is returned, because no other check was true and the condition can not be resolved.

function evaluate(object) {
    var operators = { $or: 'some', $and: 'every' },
        fns = {
            foo: items => items.indexOf("foo") >= 0,
            bar: items => items.indexOf("bar") >= 0,
            baz: items => items.indexOf("baz") >= 0
        },
        key,
        value;

    if (typeof object === 'function') return object();
    if (!object || typeof object !== 'object') return false;

    [key, value] = Object.entries(object)[0];

    if (key in operators) return value[operators[key]](evaluate);
    if (key in fns) return fns[key](value);
    return false;
}

var m = 4,
    n = 1,
    object = {
        $or: [
            {
                $and: [
                    { foo: ['foo', 'x'] },
                    { bar: ['bar', 'y'] }
                ]
            },
            { baz: ['baz', 'z'] },
            () => m < n
        ]
    },
    result = evaluate(object);

console.log(result);

Upvotes: 1

Related Questions