hyperjumptech / grule-rule-engine

Rule engine implementation in Golang
Other
2.22k stars 346 forks source link

Missing field in JSON fact should not result in error while evaluating when and then of rule #429

Open ninjulkar opened 10 months ago

ninjulkar commented 10 months ago

Describe the bug When JSON fact is used, and when has some condition on a field which is missing in JSON, rule should consider that condition unmatched instead of erroring out entire execution. If my condition is Event.Username == "john" || Event.Surname == "doe", if Event does not have Username field the execution fails with error like

got left hand expression error. got left hand expression error. got json field 'Username' is undefined" lib=grule-rule-engine package=ast

Instead here, it should consider Event.Username == "john" as false and evaluate Event.Surname == "doe" and match if it is true.

To Reproduce Steps to reproduce the behavior:

  1. I create code for this and that

    rule Rule_90  "MatchingEquals1" salience 1 {
    when
    Event.Username == "john" || Event.Surname == "doe"
    then
    Output.Matched(Event.Surname, Event.Surname);
    Retract("Rule_90");
    Complete();
    }
  2. With a test for this and that

package benchmark_grule_engine

import (
    "encoding/json"
    "fmt"
    "github.com/hyperjumptech/grule-rule-engine/ast"
    "github.com/hyperjumptech/grule-rule-engine/builder"
    "github.com/hyperjumptech/grule-rule-engine/engine"
    "github.com/hyperjumptech/grule-rule-engine/pkg"
    "testing"
)

var jsonRule = `rule Rule_90  "MatchingEquals1" salience 1 {
    when
    Event.Username == "john" || Event.Surname == "doe"
    then
    Output.Matched(Event.Surname, Event.Surname);
    Retract("Rule_90");
    Complete();
}`

func TestMissingJsonField(t *testing.T) {
    kl, err := buildKnowledgeLibrary(jsonRule)
    if err != nil {
        t.Error("Failed to add rule")
    }
    eng := engine.NewGruleEngine()

    kb := kl.NewKnowledgeBaseInstance("MyRules", "v1.0")
    ev := JsonEvent{Surname: "doe"}
    dc := ast.NewDataContext()
    j, err := json.Marshal(ev)
    if err != nil {
        panic(err)
    }
    o := Output{}
    err = dc.AddJSON("Event", j)
    if err != nil {
        panic(err)
    }
    err = dc.Add("Output", &o)
    if err != nil {
        panic(err)
    }

    err = eng.Execute(dc, kb)
    if err != nil {
        panic(err)
    }
    fmt.Println("Exec done....")

}

type JsonEvent struct {
    Username string `json:"Username,omitempty"`
    Surname  string `json:"Surname,omitempty"`
}

type Output struct {
}

func (receiver Output) Matched(username string, surname string) {
    fmt.Println("Matched", username, surname)
}

func buildKnowledgeLibrary(ruleQuery string) (*ast.KnowledgeLibrary, error) {
    kl := ast.NewKnowledgeLibrary()
    rb := builder.NewRuleBuilder(kl)
    ruleDef := pkg.NewBytesResource([]byte(ruleQuery))
    err := rb.BuildRuleFromResource("MyRules", "v1.0", ruleDef)
    return kl, err
}
  1. Instead of seeng this Matching the rule

  2. I see that Error while evaluating rule Rule_90, got left hand expression error. got left hand expression error. got json field 'Username' is undefined" lib=grule-rule-engine package=ast time="2024-01-04T13:46:04+05:30

Expected behavior Rule should match as next OR expression matches without error.

Additional context It also fails if we are using missing field in then as well.

ninjulkar commented 10 months ago

@newm4n any plans to fix this ?