go mod init <myprojectname>
go get -v -u github.com/hyperjumptech/grule-rule-engine
// main.go
package main
import (
"time"
"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/logger"
"github.com/hyperjumptech/grule-rule-engine/pkg"
)
type testCar struct {
SpeedUp bool
Speed int
MaxSpeed int
SpeedIncrement int
}
type distanceRecord struct {
TotalDistance int
}
const JSON_RULE = `
[{
"name": "SpeedUp",
"desc": "When testcar is speeding up we increase the speed.",
"salience": 10,
"when": {
"and": [
{"eq": [{"obj": "TestCar.SpeedUp"}, {"const": true}]},
{"lt": [{"obj": "TestCar.Speed"}, {"obj": "TestCar.MaxSpeed"}]}
]
},
"then": [
{"set": [{"obj": "TestCar.Speed"}, {"plus": [{"obj": "TestCar.Speed"}, {"obj": "TestCar.SpeedIncrement"}]}]},
{"set": [{"obj": "TestCar.SpeedUp"}, {"const": false}]},
{"set": [{"obj": "DistanceRecord.TotalDistance"}, {"plus": [{"obj": "DistanceRecord.TotalDistance"}, {"obj": "TestCar.Speed"}]}]},
{"call": ["Log", {"const": "Speed increased"}]}
]
}]
`
const RULE_INSTANCE_NAME = "rule-engine-instance-name"
const RULE_INSTANCE_VERSION = "0.0.1"
func main() {
// grule variable declaration
var gruleKnowledgeLib = ast.NewKnowledgeLibrary()
var gruleBuilder = builder.NewRuleBuilder(gruleKnowledgeLib)
var gruleEngine = engine.NewGruleEngine()
var gruleKnowledgeBase *ast.KnowledgeBase
// dataCtx is literally data context used within rule evaluation
var dataCtx = ast.NewDataContext()
gruleRuleset, err := pkg.ParseJSONRuleset([]byte(JSON_RULE))
if nil != err {
logger.Log.WithError(err).Panicf("failed to parse jsonruleset")
}
if err := gruleBuilder.BuildRuleFromResource(RULE_INSTANCE_NAME, RULE_INSTANCE_VERSION, pkg.NewBytesResource([]byte(gruleRuleset))); nil != err {
logger.Log.WithError(err).Panicf("failed to build rule from resource")
}
gruleKnowledgeBase = gruleKnowledgeLib.NewKnowledgeBaseInstance(RULE_INSTANCE_NAME, RULE_INSTANCE_VERSION)
// custom variable
car := &testCar{MaxSpeed: 100, SpeedIncrement: 10}
distRecord := &distanceRecord{TotalDistance: 1000}
// custom variable must come along with dataCtx for rule to be evaluated
dataCtx.Add("TestCar", car)
dataCtx.Add("DistanceRecord", distRecord)
// just for simple debug purpose
executedNo := 1
for {
logger.Log.WithField("car", car).WithField("distanceRecord", distRecord).Infof("engine executed %d times", executedNo)
executedNo++
err = gruleEngine.Execute(dataCtx, gruleKnowledgeBase)
if nil != err {
logger.Log.WithError(err).Panicf("failed to execute engine")
}
if 30 < car.Speed {
car.SpeedUp = false
} else {
car.SpeedUp = true
}
time.Sleep(time.Second * 1)
}
}
Reference
- http://hyperjumptech.viewdocs.io/grule-rule-engine/GRL_JSON_en/