jruizgit / rules

Durable Rules Engine
MIT License
1.14k stars 207 forks source link

Cannot access previous object in sequence from array rule #252

Open mrehse opened 5 years ago

mrehse commented 5 years ago

Hey there!

I came across this strange quirk:

I cannot use a previous fact/event in a ruleset when I'm evaluating rules in an array. Here is an example:

const rules = {
    ruleset: {
        add:{
            all:[
                {add:{type:"add"}},
                {check:{$and:[{$s:1},{$iall:{stuff:{$neq:{$i:{add:"value"}}}}}]}}
            ],
            run: "add"
        }
    }
};

const d = require('durable');

let host = d.getHost();

host.getAction = function (actionName) {
    return (c)=>{
        let stuff = c.s.stuff;
        stuff.push(c.add.value);
        d.updateState("ruleset", Object.assign(c.s, {stuff:stuff}));
    }
};

host.setRulesets(rules, (err) => {
    if(err){
        console.log(err);
        return;
    }
    d.updateState("ruleset", {stuff:[]});
    d.post("ruleset", {type: "add", value: "first"});
    d.post("ruleset", {type: "add", where: "second"});
    d.post("ruleset", {type: "add", where: "third"});
    d.post("ruleset", {type: "add", where: "second"});
});

All I'm doing here is creating an array in state, then adding values to the array as long as they don't already exist in there. I get the error:

Error: Could not create ruleset, error code: 102

If I change the second part of the sequence to:

{check:{$and:[{$s:1},{$iall:{stuff:{$neq:{$i:"third"}}}}]}}

Then I no longer get the 102 error. (I AM getting a problem where I can't update the state, but that's another issue since the example is contrived... though I would love to know why it happens).

Thanks!

mrehse commented 5 years ago

The problem seems to be here:

if (operator == OP_IANY || operator == OP_IALL) {
        CHECK_RESULT(findAlpha(tree, 
                               parentOffset, 
                               operator, 
                               first,
                               linkToArray, 
                               betaOffset, 
                               newOffset));

        unsigned int inner_offset = *newOffset;
        CHECK_PARSE_RESULT(readNextName(first, 
                                        &first, 
                                        &last, 
                                        &hash));

        CHECK_PARSE_RESULT(readNextValue(last, 
                                         &first, 
                                         &last, 
                                         &type));

        CHECK_RESULT(createAlpha(tree, 
                                 first, 
                                 1,
                                 betaOffset, 
                                 0, 
                                 &inner_offset));

        node *newAlpha = &tree->nodePool[inner_offset];
        if (newAlpha->value.a.expression.right.type != JSON_IDENTIFIER && newAlpha->value.a.expression.right.type != JSON_EXPRESSION) {
            return linkAlpha(tree,
                            0, 
                            *newOffset, 
                            nextOffset);
        } else {
            return ERR_UNEXPECTED_TYPE;
        }
    }

Which is inside createAlpha... validation seems fine, but it runs into this while creating the Alpha network. It seems to be that conditional (the line is 1292)--since it's a JSON object, I assume it's triggering that conditional and throwing the ERR_UNEXPECTED_TYPE.

I haven't gotten it all set up to debug any further or gotten my head entirely around your implementation of RETE, but this was what I was able to find in a quick pass over the code.

Should this be making a Beta node instead in the case of a JSON object, since it's not a constant? Again, haven't really wrapped my head around your implementation...

jruizgit commented 5 years ago

Hi, thanks for looking into this. This is actually a missing feature: array expressions don't support references to other values. I need to add support for reading the expressions, constructing the tree and evaluating the references.

mrehse commented 5 years ago

Any idea when that might be implemented? I'd offer to do it myself, but it's been a while since I wrote any C code, and never since I've worked on a Rete implementation.