Documentation ¶
Overview ¶
Package regula provides a rules engine implementation.
Usage of this package revolves around the concept of rulesets.
A ruleset can be represented as a list of rules that can be evaluated against a set of parameters given by a caller. Each rule is evaluated in order and if one matches with the given parameters it returns a result and the evaluation stops. All the rules of a ruleset always return the same type.
rs, err := regula.NewStringRuleset( rule.New( rule.Eq( rule.StringParam("group"), rule.StringValue("admin"), ), rule.StringValue("first rule matched"), ), rule.New( rule.In( rule.Int64Param("score"), rule.Int64Value(10), rule.Int64Value(20), rule.Int64Value(30), ), rule.StringValue("second rule matched"), ), rule.New( rule.True(), rule.StringValue("default rule matched"), ), ) if err != nil { log.Fatal(err) } ret, err := rs.Eval(regula.Params{ "group": "staff", "score": int64(20), })
To query and evaluate rulesets with a set of parameters, the engine must be used. An engine takes an evaluator which is responsible of evaluating rulesets on demand and return a value, the engine then parses the value into a type safe result and return it to the caller.
While the evaluator is stateful and can hold rulesets in-memory, fetch them over the network or read them from a file, the engine is stateless and simply deleguates the evaluation to the evaluator.
engine := regula.NewEngine(evaluator) s, res, err := engine.GetString("path/to/string/ruleset/key", regula.Params{ "user-id": 123, "email": "example@provider.com", }) i, res, err := engine.GetInt64("path/to/int/ruleset/key", regula.Params{ "user-id": 123, "email": "example@provider.com", })
Index ¶
- Variables
- type Engine
- func (e *Engine) GetBool(ctx context.Context, path string, params rule.Params, opts ...Option) (bool, *EvalResult, error)
- func (e *Engine) GetFloat64(ctx context.Context, path string, params rule.Params, opts ...Option) (float64, *EvalResult, error)
- func (e *Engine) GetInt64(ctx context.Context, path string, params rule.Params, opts ...Option) (int64, *EvalResult, error)
- func (e *Engine) GetString(ctx context.Context, path string, params rule.Params, opts ...Option) (string, *EvalResult, error)
- func (e *Engine) LoadStruct(ctx context.Context, to interface{}, params rule.Params) error
- type EvalResult
- type Evaluator
- type Option
- type Params
- type Ruleset
- type RulesetBuffer
- func (b *RulesetBuffer) Add(path, version string, r *Ruleset)
- func (b *RulesetBuffer) Eval(ctx context.Context, path string, params rule.Params) (*EvalResult, error)
- func (b *RulesetBuffer) EvalVersion(ctx context.Context, path, version string, params rule.Params) (*EvalResult, error)
- func (b *RulesetBuffer) GetVersion(path, version string) (*Ruleset, error)
- func (b *RulesetBuffer) Latest(path string) (*Ruleset, string, error)
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrTypeMismatch is returned when the evaluated rule doesn't return the expected result type. ErrTypeMismatch = errors.New("type returned by rule doesn't match") // ErrRulesetNotFound must be returned when no ruleset is found for a given key. ErrRulesetNotFound = errors.New("ruleset not found") // ErrRulesetIncoherentType is returned when a ruleset contains rules of different types. ErrRulesetIncoherentType = errors.New("types in ruleset are incoherent") )
Functions ¶
This section is empty.
Types ¶
type Engine ¶
type Engine struct {
// contains filtered or unexported fields
}
Engine is used to evaluate a ruleset against a group of parameters. It provides a list of type safe methods to evaluate a ruleset and always returns the expected type to the caller. The engine is stateless and relies on the given evaluator to evaluate a ruleset. It is safe for concurrent use.
Example ¶
package main import ( "context" "fmt" "github.com/heetch/regula/rule" "github.com/heetch/regula" ) var ev regula.Evaluator func main() { engine := regula.NewEngine(ev) str, res, err := engine.GetString(context.Background(), "/a/b/c", regula.Params{ "product-id": "1234", "user-id": "5678", }) if err != nil { switch err { case regula.ErrRulesetNotFound: // when the ruleset doesn't exist case regula.ErrTypeMismatch: // when the ruleset returns the bad type case rule.ErrNoMatch: // when the ruleset doesn't match default: // something unexpected happened } } fmt.Println(str) fmt.Println(res.Version) // Output // some-string // 5b4cbdf307bb5346a6c42ac3 }
Output:
func (*Engine) GetBool ¶
func (e *Engine) GetBool(ctx context.Context, path string, params rule.Params, opts ...Option) (bool, *EvalResult, error)
GetBool evaluates a ruleset and returns the result as a bool.
Example ¶
package main import ( "context" "fmt" "log" "github.com/heetch/regula" ) var ev regula.Evaluator func main() { engine := regula.NewEngine(ev) b, res, err := engine.GetBool(context.Background(), "/path/to/bool/key", regula.Params{ "product-id": "1234", "user-id": "5678", }) if err != nil { log.Fatal(err) } fmt.Println(b) fmt.Println(res.Version) // Output // true // 5b4cbdf307bb5346a6c42ac3 }
Output:
func (*Engine) GetFloat64 ¶
func (e *Engine) GetFloat64(ctx context.Context, path string, params rule.Params, opts ...Option) (float64, *EvalResult, error)
GetFloat64 evaluates a ruleset and returns the result as a float64.
Example ¶
package main import ( "context" "fmt" "log" "github.com/heetch/regula" ) var ev regula.Evaluator func main() { engine := regula.NewEngine(ev) f, res, err := engine.GetFloat64(context.Background(), "/path/to/float64/key", regula.Params{ "product-id": "1234", "user-id": "5678", }) if err != nil { log.Fatal(err) } fmt.Println(f) fmt.Println(res.Version) // Output // 3.14 // 5b4cbdf307bb5346a6c42ac3 }
Output:
func (*Engine) GetInt64 ¶
func (e *Engine) GetInt64(ctx context.Context, path string, params rule.Params, opts ...Option) (int64, *EvalResult, error)
GetInt64 evaluates a ruleset and returns the result as an int64.
Example ¶
package main import ( "context" "fmt" "log" "github.com/heetch/regula" ) var ev regula.Evaluator func main() { engine := regula.NewEngine(ev) i, res, err := engine.GetInt64(context.Background(), "/path/to/int64/key", regula.Params{ "product-id": "1234", "user-id": "5678", }) if err != nil { log.Fatal(err) } fmt.Println(i) fmt.Println(res.Version) // Output // 10 // 5b4cbdf307bb5346a6c42ac3 }
Output:
func (*Engine) GetString ¶
func (e *Engine) GetString(ctx context.Context, path string, params rule.Params, opts ...Option) (string, *EvalResult, error)
GetString evaluates a ruleset and returns the result as a string.
Example ¶
package main import ( "context" "fmt" "log" "github.com/heetch/regula" ) var ev regula.Evaluator func main() { engine := regula.NewEngine(ev) s, res, err := engine.GetString(context.Background(), "/path/to/string/key", regula.Params{ "product-id": "1234", "user-id": "5678", }) if err != nil { log.Fatal(err) } fmt.Println(s) fmt.Println(res.Version) // Output // some-string // 5b4cbdf307bb5346a6c42ac3 }
Output:
func (*Engine) LoadStruct ¶
LoadStruct takes a pointer to struct and params and loads rulesets into fields tagged with the "ruleset" struct tag.
Example ¶
package main import ( "context" "fmt" "log" "time" "github.com/heetch/regula" ) var ev regula.Evaluator func main() { type Values struct { A string `ruleset:"/path/to/string/key"` B int64 `ruleset:"/path/to/int64/key,required"` C time.Duration `ruleset:"/path/to/duration/key"` } var v Values engine := regula.NewEngine(ev) err := engine.LoadStruct(context.Background(), &v, regula.Params{ "product-id": "1234", "user-id": "5678", }) if err != nil { log.Fatal(err) } fmt.Println(v.A) fmt.Println(v.B) fmt.Println(v.C) }
Output: some-string 10 3s
type EvalResult ¶
type EvalResult struct { // Result of the evaluation Value *rule.Value // Version of the ruleset that generated this value Version string }
EvalResult is the product of an evaluation. It contains the value generated as long as some metadata.
type Evaluator ¶
type Evaluator interface { // Eval evaluates a ruleset using the given params. // If no ruleset is found for a given path, the implementation must return ErrRulesetNotFound. Eval(ctx context.Context, path string, params rule.Params) (*EvalResult, error) // EvalVersion evaluates a specific version of a ruleset using the given params. // If no ruleset is found for a given path, the implementation must return ErrRulesetNotFound. EvalVersion(ctx context.Context, path string, version string, params rule.Params) (*EvalResult, error) }
An Evaluator provides methods to evaluate rulesets from any location. Long running implementations must listen to the given context for timeout and cancelation.
type Params ¶
type Params map[string]interface{}
Params is a map based rule.Params implementation.
func (Params) EncodeValue ¶
EncodeValue returns the string representation of the selected value.
func (Params) GetFloat64 ¶
GetFloat64 extracts a float64 parameter corresponding to the given key.
type Ruleset ¶
A Ruleset is list of rules that must return the same type.
Example ¶
package main import ( "fmt" "log" "github.com/heetch/regula/rule" "github.com/heetch/regula" ) func main() { rs, err := regula.NewStringRuleset( rule.New( rule.Eq( rule.StringParam("group"), rule.StringValue("admin"), ), rule.StringValue("first rule matched"), ), rule.New( rule.In( rule.Int64Param("score"), rule.Int64Value(10), rule.Int64Value(20), rule.Int64Value(30), ), rule.StringValue("second rule matched"), ), rule.New( rule.True(), rule.StringValue("default rule matched"), ), ) if err != nil { log.Fatal(err) } ret, err := rs.Eval(regula.Params{ "group": "staff", "score": int64(20), }) if err != nil { log.Fatal(err) } fmt.Println(ret.Data) // Output // second rule matched }
Output:
func NewBoolRuleset ¶
NewBoolRuleset creates a ruleset which rules all return a bool otherwise ErrRulesetIncoherentType is returned.
func NewFloat64Ruleset ¶
NewFloat64Ruleset creates a ruleset which rules all return an float64 otherwise ErrRulesetIncoherentType is returned.
func NewInt64Ruleset ¶
NewInt64Ruleset creates a ruleset which rules all return an int64 otherwise ErrRulesetIncoherentType is returned.
func NewStringRuleset ¶
NewStringRuleset creates a ruleset which rules all return a string otherwise ErrRulesetIncoherentType is returned.
func (*Ruleset) Eval ¶
Eval evaluates every rule of the ruleset until one matches. It returns rule.ErrNoMatch if no rule matches the given context.
func (*Ruleset) Params ¶
Params returns a list of all the parameters used in all the underlying rules.
func (*Ruleset) UnmarshalJSON ¶
UnmarshalJSON implements the json.Unmarshaler interface.
type RulesetBuffer ¶
type RulesetBuffer struct {
// contains filtered or unexported fields
}
RulesetBuffer can hold a group of rulesets in memory and can be used as an evaluator. It is safe for concurrent use.
func NewRulesetBuffer ¶
func NewRulesetBuffer() *RulesetBuffer
NewRulesetBuffer creates a ready to use RulesetBuffer.
func (*RulesetBuffer) Add ¶
func (b *RulesetBuffer) Add(path, version string, r *Ruleset)
Add adds the given ruleset version to a list for a specific path. The last added ruleset is treated as the latest version.
func (*RulesetBuffer) Eval ¶
func (b *RulesetBuffer) Eval(ctx context.Context, path string, params rule.Params) (*EvalResult, error)
Eval evaluates the latest added ruleset or returns ErrRulesetNotFound if not found.
func (*RulesetBuffer) EvalVersion ¶
func (b *RulesetBuffer) EvalVersion(ctx context.Context, path, version string, params rule.Params) (*EvalResult, error)
EvalVersion evaluates the selected ruleset version or returns ErrRulesetNotFound if not found.
func (*RulesetBuffer) GetVersion ¶
func (b *RulesetBuffer) GetVersion(path, version string) (*Ruleset, error)
GetVersion returns a ruleset associated with the given path and version.