hyperjumptech/grule-rule-engine

Maps don't work accross different rules

Opened this issue · 4 comments

Describe the bug
Neither any map, nor a struct wrapper around a map work - it can receive the value in "then" section, but can in no way be retrieved in "when" section of of another rule.

To Reproduce
Steps to reproduce the behavior:

  1. Try adding these objects to DataContext:
obj := make(map[string]interface{})

or

obj := make(map[string]string)

or

type MapTool struct {
	Map map[string]interface{}
}
func (mt *MapTool) GetString(key string) string {
	return mt.Map[key].(string)
}
func (mt *MapTool) Set(key string, val interface{}) {
	mt.Map[key] = val
}

or even a basic map wrapper like

type MapTool struct {
	Map map[string]string
}
  1. When a value is added to the map in one rule ("then"), the same value is not available in "when" section of any other rule.
    Funnily, this value is retained in the object and after all rules are executed.

  2. In "when" section the object variable either defaults to zero value of that variable (and "when" is never true) or fails with panic: "panic: interface conversion: interface {} is nil, not string"

Expected behavior
Map variables should be available for "when" evaluation.

Additional context
I'm really struggling to make use of grule because of this: there's no sensible way for having a "memory" layer throughout the execution of individual rules. Meaning, one often requires to put some variable into this "memory", so that it is available for evaluation/modification/retrieval in other rules.

A single way that has worked for me is to have a helper struct and add it to DataContext, something like this:

type Helper struct {
	I1 int64
	I2 int64
	F1 float64
	F2 float64
	S1 string
	S2 string
	B1 bool
	B2 bool
}

But this is horrible and very difficult to use. Everything else fails, I tried. Help, this looks like a really promising product! (And I don't want to mess with Drule).

newm4n commented

@daugminas ,

I undestand your frustration, This issue been on my radar for a month or so and I still trying to figure out. You can see another issue like yours, #316 where the map behavior is not as I expected. Using reflection to modify map content seems to work but its not altering to original map content. Im still struggling to find time to really focus on this issue.

Appreciate it! Have you managed to find time to get this working?

Bump

ivoshm commented

Just an idea - after changing the map member in the "then" section, mark the whole map with the Changed()/Forget() function and then I assume the above example can work correctly.