trigger

package module
v0.0.19 Latest Latest
Warning

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

Go to latest
Published: Jan 16, 2021 License: Apache-2.0 Imports: 31 Imported by: 2

README

trigger

https://graphikdb.github.io/trigger/

GoDoc

a decision & trigger framework backed by Google's Common Expression Language used in graphikDB

  • Full Text Search Expression Macros/Functions(startsWith, endsWith, contains)
  • RegularExp Expression Macros/Functions(matches)
  • Geographic Expression Macros/Functions(geoDistance)
  • Cryptographic Expression Macros/Functions(encrypt, decrypt, sha1, sha256, sha3)
  • JWT Expression Macros/Functions(parseClaims, parseHeader, parseSignature)
  • Collection Expression Macros/Functions(in, map, filter, exists)
  • String Manipulation Expression Macros/Functions(replace, join, titleCase, lowerCase, upperCase, trimSpace, trimPrefix, trimSuffix, render)
  • URL Introspection Expression Macros/Functions(parseHost, parseScheme, parseQuery, parsePath)

Use Case:

Since this expression language requires just input data(map[string]interface) and an expression string, Go programs may use it to embed flexible logic that may be changed at runtime without having to recompile.

  • Authorization Middleware/Policy Evaluation/Rule Engine

  • Database or API "triggers" for mutating data before its commited

  • Search Engine(filter something based on a decision)

Examples

restrict access based on domain
	decision, err := trigger.NewDecision("this.email.endsWith('acme.com')")
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	err = decision.Eval(map[string]interface{}{
		"email": "bob@gmail.com",
	})
	fmt.Println(err == trigger.ErrDecisionDenied) 
    // Output: true 
create a trigger based on signup event that adds updated_at timestamp & hashes a password
	// create a trigger based on the new decision that hashes a password and creates an updated_at timestamp
	// this would in theory be applied to a newly created user after signup
	trigg, err := trigger.NewArrowTrigger(`
	this.event == 'signup' && has(this.email) =>
	{
		'updated_at': now(),
		'password': this.password.sha1()
	}
`)
	if err != nil {
		fmt.Println(err.Error())
		return
	}

	user := map[string]interface{}{
		"event": "signup",
		"name":  "bob",
		"email": "bob@acme.com",
		"password": "123456",
	}
	data, err := trigg.Trigger(user)
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	fmt.Println(data["updated_at"].(int64) > 0, data["password"])
	// Output: true 7c4a8d09ca3762af61e59520943dc26494f8941b

CEL Macro Extensions

Additional details on the standard CEL spec/library may be found here

function notation description
now now() int64 current timestamp in unix secods
uuid uuid() string random uuidv4 string
sha1 sha1(string) string sha1 hash of the input string
sha256 sha256(string) string sha256 hash of the input string
sha3 sha3(string) string sha3 hash of the input string
base64Encode base64Encode(string) string base64 encoded version of the input
base64Decode base64Decode(string) string base64 decoded version of the input
jsonEncode jsonEncode(string) string json encoded version of the input
jsonDecode jsonDecode(string) string json decoded version of the input
replace replace(text string, old string, new string) string full string replacement of the old value with the new value
join join(arr list(string), sep string) string joins the array into a single string with the given separator
titleCase titleCase(string) string converts the input into title case string
lowerCase lowerCase(string) string converts the input into lower case string
upperCase upperCase(string) string converts the input into upper case string
trimSpace trimSpace(string) string removes white spaces from the input string
trimPrefix trimPrefix(string) string removes prefix from the input string
trimSuffix trimSuffix(string) string removes suffix from the input string
geoDistance geoDistance(this list(float64), that list(float64)) float64 haversine distance between two coordinates [lat,lng]
render render(tmplate string, data map[string]interface) string renders the input template with the provided data map
parseClaims parseClaims(jwt string) map[string]interface) returns the payload of the jwt as a map
parseHeader parseHeader(jwt string) map[string]interface returns the header of the jwt as a map
parseSignature parseSignature(jwt string) string returns the signature of the jwt as a string
typeOf typeOf(any) string returns the go type of the input
encrypt encrypt(secret string, msg string) string aes encrypt a message with a given secret
decrypt decrypt(secret string, msg string) string aes decrypt a message with a given secret

Documentation

Index

Examples

Constants

View Source
const ArrowOperator = "=>"

Variables

View Source
var (
	ErrDecisionDenied   = errors.New("trigger: evaluation = false")
	ErrEmptyExpressions = errors.New("trigger: empty expressions")
)
View Source
var ErrArrowOperator = errors.Errorf("arrow operator: expecting syntax ${decision} %s ${mutation}", ArrowOperator)
View Source
var Functions = FuncMap{
	"now": {
		// contains filtered or unexported fields
	},
	"uuid": {
		// contains filtered or unexported fields
	},
	"sha1": {
		// contains filtered or unexported fields
	},
	"sha256": {
		// contains filtered or unexported fields
	},
	"sha3": {
		// contains filtered or unexported fields
	},
	"base64Encode": {
		// contains filtered or unexported fields
	},
	"base64Decode": {
		// contains filtered or unexported fields
	},
	"jsonEncode": {
		// contains filtered or unexported fields
	},
	"jsonDecode": {
		// contains filtered or unexported fields
	},
	"replace": {
		// contains filtered or unexported fields
	},
	"join": {
		// contains filtered or unexported fields
	},
	"titleCase": {
		// contains filtered or unexported fields
	},
	"lowerCase": {
		// contains filtered or unexported fields
	},
	"upperCase": {
		// contains filtered or unexported fields
	},
	"trimSpace": {
		// contains filtered or unexported fields
	},
	"trimPrefix": {
		// contains filtered or unexported fields
	},
	"trimSuffix": {
		// contains filtered or unexported fields
	},
	"geoDistance": {
		// contains filtered or unexported fields
	},
	"render": {
		// contains filtered or unexported fields
	},
	"parseClaims": {
		// contains filtered or unexported fields
	},
	"parseHeader": {
		// contains filtered or unexported fields
	},
	"parseSignature": {
		// contains filtered or unexported fields
	},
	"typeOf": {
		// contains filtered or unexported fields
	},
	"encrypt": {
		// contains filtered or unexported fields
	},
	"decrypt": {
		// contains filtered or unexported fields
	},
	"parseHost": {
		// contains filtered or unexported fields
	},
	"parseQuery": {
		// contains filtered or unexported fields
	},
	"parsePath": {
		// contains filtered or unexported fields
	},
	"parseScheme": {
		// contains filtered or unexported fields
	},
	"split": {
		// contains filtered or unexported fields
	},
	"trimRight": {
		// contains filtered or unexported fields
	},
	"trimLeft": {
		// contains filtered or unexported fields
	},
}

Functions

This section is empty.

Types

type Decision

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

Decision is used to evaluate boolean expressions

func NewDecision

func NewDecision(expression string) (*Decision, error)

NewDecision creates a new Decision with the given boolean CEL expressions

Example
package main

import (
	"fmt"
	"github.com/graphikDB/trigger"
)

func main() {
	decision, err := trigger.NewDecision("this.email.endsWith('acme.com')")
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	err = decision.Eval(map[string]interface{}{
		"email": "bob@gmail.com",
	})
	fmt.Println(err == trigger.ErrDecisionDenied)
}
Output:

true

func (*Decision) Eval

func (n *Decision) Eval(data map[string]interface{}) error

Eval evaluates the boolean CEL expressions against the Mapper

func (*Decision) Expression

func (e *Decision) Expression() string

Expressions returns the decsions raw expression

type FuncMap added in v0.0.10

type FuncMap map[string]*Function

type Function added in v0.0.10

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

func NewFunction added in v0.0.10

func NewFunction(decl *expr.Decl, overload *functions.Overload) *Function

type Trigger

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

Trigger creates values as map[string]interface{} if it's decisider returns no errors against a Mapper

func NewArrowTrigger added in v0.0.14

func NewArrowTrigger(arrowExpression string) (*Trigger, error)

NewArrowTrigger creates a trigger from arrow syntax ${decision} => ${mutation}

func NewTrigger

func NewTrigger(decision *Decision, triggerExpression string) (*Trigger, error)

NewTrigger creates a new trigger instance from the decision & trigger expressions

Example
package main

import (
	"fmt"
	"github.com/graphikDB/trigger"
)

func main() {
	// create a trigger based on the new decision that hashes a password and creates an updated_at timestamp
	// this would in theory be applied to a newly created user after signup
	trigg, err := trigger.NewArrowTrigger(`
	this.event == 'signup' && has(this.email) =>
	{
		'updated_at': now(),
		'password': this.password.sha1()
	}
`)
	if err != nil {
		fmt.Println(err.Error())
		return
	}

	user := map[string]interface{}{
		"event":    "signup",
		"name":     "bob",
		"email":    "bob@acme.com",
		"password": "123456",
	}
	data, err := trigg.Trigger(user)
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	fmt.Println(data["updated_at"].(int64) > 0, data["password"])
}
Output:

true 7c4a8d09ca3762af61e59520943dc26494f8941b

func (*Trigger) Expression

func (e *Trigger) Expression() string

Expression returns the triggers raw CEL expressions

func (*Trigger) Trigger

func (t *Trigger) Trigger(data map[string]interface{}) (map[string]interface{}, error)

Trigger executes it's decision against the Mapper and then overwrites the

Jump to

Keyboard shortcuts

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