Quick Start
Installation
To install the library into your project please run:
Quick start
The library exposes a simple API to create conditions, rules, ruleset, facts and run the evaluation.
Ruleset definition
The following snippets illustrates how to create a ruleset for the next definition:
Termination rules
Note that so far the engine only supports termination rules, that means: the THEN part of the rule only can return a string that will be sent to the activation function
The code should be written like:
- Activation function that receives the
then
value of the activated rule and the contextctx
with all facts. - Error handler function receives the error and you can log it or do something else based on it.
Activation function
This function is a callback function that will be called each time that a rule returns true
when a fact or facts are
updated.
The function receives the then
value of the activated rule and a pointer to the evaluated context having available all
registered facts and objects into this one.
Facts inference
Sometimes is needed performing an inference due to a facts change. The given context
into the onActivation
handler
will let you update facts in a thread-safe manner calling the cnotext method Feedback
.
Please refer to Context section for more details.
Error handler
If for some reason the evaluation ran into an error this callback function will be called letting you know about the error.
Facts as struct fields
Following the previous example we have an object User
with 3 fields plan
miles
and status
.
Those attributes are the facts and can be defined into your go program as:
Where the struct name (User) matches with the fact object and the field name matches with the fact attribute. Also the data type must be set using the Goldfish-RE data types in order to trigger an evaluation each time that a value is updated.
Go annotation
The library also supports Go tags to configure your facts. The tag must be written as:
- object: defines the object name for the given fact, useful to overwrite the struct name.
- attribute: sets the attribute name for the given fact if you need a name different to the struct field
- value: the default value which the fact will be initialized. Possible values
- String:
value=some string value
- Number:
value=234
- Float:
value=73.2
- Boolean:
value=true
- Date:
value=1984-12-24T00:00:00
- String:
Exported fields
In order to use the Go tags to configure the facts, is mandatory exporting the fields otherwise the context registration will fail.
Context
Once that you have a ruleset
what do you need is a context
to eval your facts against the ruleset. That means:
- A context is created from a ruleset:
rs.Context()
- Each ruleset has only one context
- The facts are thread-safe into the same context via
ctx.Update
method - The facts are not thread-safe between different context
Register facts
In order to run evaluations against the ruleset each time that a Fact is updated, is required to register the facts into a Context.
Register methods do not run a ruleset evaluation. Only register the facts with their zero
/default
values into the context.
The evaluation happens when a context.Update
is called and the facts are modified via a transaction Tx
To do this the Context struct has some methods:
Register a full struct
ctx.Register(obj interface{})
: This method is the most useful when you have a struct with facts to be registered.
Also fetchs the tags and applies its configuration. Returns an error if the registration process fails.
For instance:
Register field by field
In addition to the Register
method it is possible registering individual field with its data type:
RegisterString(object interface{}, attribute String)
RegisterNumber(object interface{}, attribute Number)
RegisterFloat(object interface{}, attribute Float)
RegisterBoolean(object interface{}, attribute Boolean)
RegisterDate(object interface{}, attribute Date)
For instance:
Update facts
Each time that a fact or facts are updated a ruleset evaluation must be run in order to check if some variation activates any rule.
The context object exposes a method to execute fact updates in a thread-safe mode. Each call is a locking call and returns the control
when the success function (onActivation
) has finished.
Improving performance
To improve performance your success function could be executed as a go routine. Have into account to copy the context facts if you need it because, to avoid degrade performance, are pointers to the main ruleset context.
Calling context.Update
you can update multiples facts at once in a transactional way and after that the evaluation will be trigger.
The ctx.Update
executes a function where a tx *gre.Tx
is a transaction object and let you perform transactional
updates to your facts and exposes a tx.Error
method in case that you would like to return a custom error to avoid run
the ruleset evaluation.
When an error
is returned the transaction is not applied that means: fact changes are not updated (committed).
If you need updating only one fact, the context object exposes individual methods for each data type.
SetString(attribute interface{}, value string) error
SetNumber(attribute interface{}, value int64) error
SetFloat(attribute interface{}, value float64) error
SetBoolean(attribute interface{}, value bool) error
SetDate(attribute interface{}, value time.Time) error
For instance:
Blocking method
The previous methods (SetString, SetNumber, SetFloat, SetBoolean, SetDate
) are blocking methods that executes into a
transaction meaning that in case of error the new value is not applied.
Context into onActivation handler
The context into the activation handler contains all the previous registered facts, so all facts are accessible to read it or to write it. Also, the parent object to each fact can be accessed via the context.
The exposed API methods are described below:
Fact Getters:
These methods are useful to fetch a fact object given the fact name.
Get(fact string) (interface{}, bool)
GetString(fact string) (String, error)
GetNumber(fact string) (Number, error)
GetFloat(fact string) (Float, error)
GetBoolean(fact string) (Boolean, error)
GetDate(fact string) (Date, error)
Iteration over all facts into the context
This method is useful when you need to run an iteration over all facts into the context. An iteration function must be provided with
2 parameters: fact
which is the fact name like User.plan
and its value which in this case is an interface to match with all possible data types.
ForEach(fn func(fact string, value interface{}))
Parent Object Getter
This method fetch the parent object that contains a fact.
GetObject(object string) (interface{}, bool)
Fact Inference (feedback)
Sometimes when we are working with a ruleset where some facts depend on other facts is needed an inference mechanism. In this case we called
Feedback
due to each feedback will trigger a ruleset re-evaluation. The Feedback
function is transactional, thread-safe, and it is called
from the context.Update
life cycle. If the tx.Error()
is executed into the Feedback method
the error will be accessible as outcome of context.Update
.
Feedback(func(tx *Tx))
Advanced example
Please check the advanced example app into the goldfish-re repo to see it in action!