qualify

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Nov 29, 2018 License: Apache-2.0 Imports: 2 Imported by: 0

README

Qualify!

Build Status GoDoc Go Report Card License

Library for fast rules evaluation for Go. Qualify is able to quickly match a fact against large number of pre-defined rules.

Example:
import (
	"fmt"

	"github.com/bsm/qualify"
)

// Fact is an example fact
type Fact struct {
  Country string
  Browser string
  OS      string
  Attrs   []int
}

// Enumeration of our fact features
const (
  FieldCountry qualify.Field = iota
  FieldBrowser
  FieldOS
  FieldAttrs
)

// factReader is a wrapper around facts to
// make them comply with qualify.Fact
type factReader struct {
  Dict qualify.StrDict
  Fact
}

func (r *factReader) AppendFieldValues(x []int, f qualify.Field) []int {
  switch f {
  case FieldCountry:
    return r.Dict.Lookup(x, r.Country)
  case FieldBrowser:
    return r.Dict.Lookup(x, r.Browser)
  case FieldOS:
    return r.Dict.Lookup(x, r.OS)
  case FieldAttrs:
    return append(x, r.Attrs...)
  }
  return x
}

func main() package qualify_test

import (
	"fmt"

	"github.com/bsm/qualify"
)

func ExampleQualifier() {
	// We can use dictionary encoding to translate
	// string values into numerics
	dict := qualify.NewStrDict()

	// Init a new builder popute with rules
	// for each outcome.
	builder := qualify.NewBuilder()

	// Outcome #34 requires:
	//  * Country to be GBR or FRA, and
	//  * Attrs to contain 101 or 102, and
	//  * Attrs to contain 202 or 203
	builder.Require(34, FieldCountry,
		qualify.OneOf(dict.Add("GBR"), dict.Add("FRA")))
	builder.Require(34, FieldAttrs,
		qualify.OneOf(101, 102))
	builder.Require(34, FieldAttrs,
		qualify.OneOf(202, 203))

	// Outcome #35 requires:
	//  * Country NOT to be NLD nor GER, and
	//  * Browser NOT to be Safari, and
	//  * OS to be either Android or iOS
	builder.Require(35, FieldCountry,
		qualify.NoneOf(dict.Add("NLD"), dict.Add("GER")))
	builder.Require(35, FieldBrowser,
		qualify.NoneOf(dict.Add("Safari")))
	builder.Require(35, FieldOS,
		qualify.OneOf(dict.Add("Android"), dict.Add("iOS")))

	// Setup the qualifier
	qfy := builder.Compile()

	// Init result set
	var res []int

	// Matches outcome #34
	res = qfy.Qualify(res[:0], &factReader{Dict: dict, Fact: Fact{Country: "GBR", Attrs: []int{101, 202}}})
	fmt.Println(res)

	// Matches outcome #35
	res = qfy.Qualify(res[:0], &factReader{Dict: dict, Fact: Fact{Country: "IRE", OS: "iOS"}})
	fmt.Println(res)

	// Matches nothing
	res = qfy.Qualify(res[:0], &factReader{Dict: dict, Fact: Fact{Country: "NLD"}})
	fmt.Println(res)

}

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Builder

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

Builder instances are used to map sets of rules to outcomes.

func NewBuilder

func NewBuilder() *Builder

NewBuilder inits a new builder

func (*Builder) Compile

func (b *Builder) Compile() *Qualifier

Compile compiles a qualifier. The builder will become read-only as soon as this method is called.

func (*Builder) Require

func (b *Builder) Require(outcome int, field Field, cond Condition) bool

Require adds a requirement condition for a particular outcome. Returns true if the requirement was acknowledged.

type Condition

type Condition interface {
	// contains filtered or unexported methods
}

Condition represents a rule requirement

func NoneOf

func NoneOf(values ...int) Condition

NoneOf returns a condition that requires none of the values to be present

func OneOf

func OneOf(values ...int) Condition

OneOf returns a condition that requires any of the values to be present

type Fact

type Fact interface {

	// AppendFieldValues must append of values for a given field to dst
	AppendFieldValues(dst []int, field Field) []int
}

Fact instances must implement a simple interface

type Field

type Field int

Field identifies a particular fact field

type Qualifier

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

Qualifier instances can be used to determine qualified outcomes for any given fact.

Example
package main

import (
	"fmt"

	"github.com/bsm/qualify"
)

func main() {
	// We can use dictionary encoding to translate
	// string values into numerics
	dict := qualify.NewStrDict()

	// Init a new builder popute with rules
	// for each outcome.
	builder := qualify.NewBuilder()

	// Outcome #34 requires:
	//  * Country to be GBR or FRA, and
	//  * Attrs to contain 101 or 102, and
	//  * Attrs to contain 202 or 203
	builder.Require(34, FieldCountry,
		qualify.OneOf(dict.Add("GBR"), dict.Add("FRA")))
	builder.Require(34, FieldAttrs,
		qualify.OneOf(101, 102))
	builder.Require(34, FieldAttrs,
		qualify.OneOf(202, 203))

	// Outcome #35 requires:
	//  * Country NOT to be NLD nor GER, and
	//  * Browser NOT to be Safari, and
	//  * OS to be either Android or iOS
	builder.Require(35, FieldCountry,
		qualify.NoneOf(dict.Add("NLD"), dict.Add("GER")))
	builder.Require(35, FieldBrowser,
		qualify.NoneOf(dict.Add("Safari")))
	builder.Require(35, FieldOS,
		qualify.OneOf(dict.Add("Android"), dict.Add("iOS")))

	// Setup the qualifier
	qfy := builder.Compile()

	// Init result set
	var res []int

	// Matches outcome #34
	res = qfy.Qualify(res[:0], &factReader{Dict: dict, Fact: Fact{Country: "GBR", Attrs: []int{101, 202}}})
	fmt.Println(res)

	// Matches outcome #35
	res = qfy.Qualify(res[:0], &factReader{Dict: dict, Fact: Fact{Country: "IRE", OS: "iOS"}})
	fmt.Println(res)

	// Matches nothing
	res = qfy.Qualify(res[:0], &factReader{Dict: dict, Fact: Fact{Country: "NLD"}})
	fmt.Println(res)

}

// --------------------------------------------------------------------

// Fact is an example fact
type Fact struct {
	Country string
	Browser string
	OS      string
	Attrs   []int
}

// Enumeration of our fact features
const (
	FieldCountry qualify.Field = iota
	FieldBrowser
	FieldOS
	FieldAttrs
)

// factReader is a wrapper around facts to
// make them comply with qualify.Fact
type factReader struct {
	Dict qualify.StrDict
	Fact
}

func (r *factReader) AppendFieldValues(x []int, f qualify.Field) []int {
	switch f {
	case FieldCountry:
		return r.Dict.Lookup(x, r.Country)
	case FieldBrowser:
		return r.Dict.Lookup(x, r.Browser)
	case FieldOS:
		return r.Dict.Lookup(x, r.OS)
	case FieldAttrs:
		return append(x, r.Attrs...)
	}
	return x
}
Output:

[34]
[35]
[]

func (*Qualifier) Qualify

func (q *Qualifier) Qualify(dst []int, fact Fact) []int

Qualify will find outcomes matching the given fact and append them to dst

type StrDict

type StrDict map[string]int

StrDict can be used to convert string values to integers usingdictionary encoding.

func NewStrDict

func NewStrDict() StrDict

NewStrDict inits a new dictionary

func (StrDict) Add

func (m StrDict) Add(s string) int

Add adds a string to the dictionary returning the numeric value/index. Returns the previous index value if the string has been added before.

func (StrDict) Lookup

func (m StrDict) Lookup(dst []int, strs ...string) []int

Lookup performs a lookup of multiple strings and appends the results to dst returning it

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

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