bexpr

package module
v0.1.14 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 15, 2024 License: MPL-2.0 Imports: 9 Imported by: 61

README

bexpr - Boolean Expression Evaluator GoDoc CircleCI

bexpr is a Go (golang) library to provide generic boolean expression evaluation and filtering for Go data structures and maps. Under the hood, bexpr uses pointerstructure, meaning that any path within a map or structure that can be expressed via that library can be used with bexpr. This also means that you can use the custom bexpr dotted syntax (kept mainly for backwards compatibility) to select values in expressions, or, by enclosing the selectors in quotes, you can use JSON Pointer syntax to select values in expressions.

Usage (Reflection)

This example program is available in examples/simple

package main

import (
   "fmt"
   "github.com/hashicorp/go-bexpr"
)

type Example struct {
   X int

   // Can rename a field with the struct tag
   Y string `bexpr:"y"`
   Z bool `bexpr:"foo"`

   // Tag with "-" to prevent allowing this field from being used
   Hidden string `bexpr:"-"`

   // Unexported fields are not available for evaluation
   unexported string
}

func main() {
   value := map[string]Example{
      "foo": Example{X: 5, Y: "foo", Z: true, Hidden: "yes", unexported: "no"},
      "bar": Example{X: 42, Y: "bar", Z: false, Hidden: "no", unexported: "yes"},
   }

   expressions := []string{
		"foo.X == 5",
		"bar.y == bar",
		"foo.baz == true",

		// will error in evaluator creation
		"bar.Hidden != yes",

		// will error in evaluator creation
		"foo.unexported == no",
	}

   for _, expression := range expressions {
      eval, err := bexpr.CreateEvaluator(expression)

      if err != nil {
         fmt.Printf("Failed to create evaluator for expression %q: %v\n", expression, err)
         continue
      }

      result, err := eval.Evaluate(value)
      if err != nil {
         fmt.Printf("Failed to run evaluation of expression %q: %v\n", expression, err)
         continue
      }

      fmt.Printf("Result of expression %q evaluation: %t\n", expression, result)
   }
}

This will output:

Result of expression "foo.X == 5" evaluation: true
Result of expression "bar.y == bar" evaluation: true
Result of expression "foo.baz == true" evaluation: true
Failed to run evaluation of expression "bar.Hidden != yes": error finding value in datum: /bar/Hidden at part 1: struct field "Hidden" is ignored and cannot be used
Failed to run evaluation of expression "foo.unexported == no": error finding value in datum: /foo/unexported at part 1: couldn't find struct field with name "unexported"

Testing

The Makefile contains 3 main targets to aid with testing:

  1. make test - runs the standard test suite
  2. make coverage - runs the test suite gathering coverage information
  3. make bench - this will run benchmarks. You can use the benchcmp tool to compare subsequent runs of the tool to compare performance. There are a few arguments you can provide to the make invocation to alter the behavior a bit
    • BENCHFULL=1 - This will enable running all the benchmarks. Some could be fairly redundant but could be useful when modifying specific sections of the code.
    • BENCHTIME=5s - By default the -benchtime paramater used for the go test invocation is 2s. 1s seemed like too little to get results consistent enough for comparison between two runs. For the highest degree of confidence that performance has remained steady increase this value even further. The time it takes to run the bench testing suite grows linearly with this value.
    • BENCHTESTS=BenchmarkEvaluate - This is used to run a particular benchmark including all of its sub-benchmarks. This is just an example and "BenchmarkEvaluate" can be replaced with any benchmark functions name.

Documentation

Overview

Package bexpr is an implementation of a generic boolean expression evaluator. The general goal is to be able to evaluate some expression against some arbitrary data and get back a boolean indicating if the data was matched by the expression

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CoerceBool

func CoerceBool(value string) (interface{}, error)

CoerceBool conforms to the FieldValueCoercionFn signature and can be used to convert the raw string value of an expression into a `bool`

func CoerceFloat32

func CoerceFloat32(value string) (interface{}, error)

CoerceFloat32 conforms to the FieldValueCoercionFn signature and can be used to convert the raw string value of an expression into an `float32`

func CoerceFloat64

func CoerceFloat64(value string) (interface{}, error)

CoerceFloat64 conforms to the FieldValueCoercionFn signature and can be used to convert the raw string value of an expression into an `float64`

func CoerceInt64

func CoerceInt64(value string) (interface{}, error)

CoerceInt64 conforms to the FieldValueCoercionFn signature and can be used to convert the raw string value of an expression into an `int64`

func CoerceUint64

func CoerceUint64(value string) (interface{}, error)

CoerceUint64 conforms to the FieldValueCoercionFn signature and can be used to convert the raw string value of an expression into an `int64`

Types

type Evaluator

type Evaluator struct {
	// contains filtered or unexported fields
}

func CreateEvaluator

func CreateEvaluator(expression string, opts ...Option) (*Evaluator, error)

CreateEvaluator is used to create and configure a new Evaluator, the expression will be used by the evaluator when evaluating against any supplied datum. The following Option types are supported: WithHookFn, WithMaxExpressions, WithTagName, WithUnknownValue.

func (*Evaluator) Evaluate

func (eval *Evaluator) Evaluate(datum interface{}) (bool, error)

Evaluate attempts to match the configured expression against the supplied datum. It returns a value indicating if a match was found and any error that occurred. If an error is returned, the value indicating a match will be false.

func (*Evaluator) Expression added in v0.1.14

func (eval *Evaluator) Expression() string

Expression can be used to return the initial expression used to create the Evaluator.

type Filter

type Filter struct {
	// contains filtered or unexported fields
}

func CreateFilter

func CreateFilter(expression string) (*Filter, error)

Creates a filter to operate on the given data type. The data type passed can be either be a container type (map, slice or array) or the element type. For example, if you want to filter a []Foo then the data type to pass here is either []Foo or just Foo. If no expression is provided the nil filter will be returned but is not an error. This is done to allow for executing the nil filter which is just a no-op

func (*Filter) Execute

func (f *Filter) Execute(data interface{}) (interface{}, error)

Execute the filter. If called on a nil filter this is a no-op and will return the original data

type Option

type Option func(*options)

Option - how Options are passed as arguments

func WithHookFn added in v0.1.7

func WithHookFn(fn ValueTransformationHookFn) Option

WithHookFn sets a HookFn to be called on the Go data under evaluation and all subfields, indexes, and values recursively. That makes it easier for the JSON Pointer to not match exactly the Go value being evaluated (for example, when using protocol buffers' well-known types).

func WithLocalVariable added in v0.1.13

func WithLocalVariable(name string, path []string, value any) Option

WithLocalVariable add a local variable that can either point to another path that will be resolved when the local variable is referenced or to a known value that will be used directly.

func WithMaxExpressions added in v0.1.3

func WithMaxExpressions(maxExprCnt uint64) Option

func WithTagName added in v0.1.5

func WithTagName(tagName string) Option

WithTagName indictes what tag to use instead of the default "bexpr"

func WithUnknownValue added in v0.1.11

func WithUnknownValue(val interface{}) Option

WithUnknownValue sets a value that is used for any unknown keys. Normally, bexpr will error on any expressions with unknown keys. This can be set to instead use a specificed value whenever an unknown key is found. For example, this might be set to the empty string "".

type ValueTransformationHookFn added in v0.1.7

type ValueTransformationHookFn = pointerstructure.ValueTransformationHookFn

ValueTransformationHookFn provides a way to translate one reflect.Value to another during evaluation by bexpr. This facilitates making Go structures appear in a way that matches the expected JSON Pointers used for evaluation. This is helpful, for example, when working with protocol buffers' well-known types.

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL