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": "[email protected]",
})
i, res, err := engine.GetInt64("path/to/int/ruleset/key", regula.Params{
"user-id": 123,
"email": "[email protected]",
})
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
}
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
}
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
}
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
}
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
}
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
}
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.