tagexpr

package module
v1.1.0 Latest Latest
Warning

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

Go to latest
Published: Jan 28, 2019 License: Apache-2.0 Imports: 10 Imported by: 0

README

go-tagexpr report card GoDoc

An interesting go struct tag expression syntax for field validation, etc.

Usage

Validator: A powerful validator that supports struct tag expression

Example

package tagexpr_test

import (
	"fmt"

	tagexpr "github.com/bytedance/go-tagexpr"
)

func Example() {
	type T struct {
		A  int             `tagexpr:"$<0||$>=100"`
		B  string          `tagexpr:"len($)>1 && regexp('^\\w*$')"`
		C  bool            `tagexpr:"{expr1:(f.g)$>0 && $}{expr2:'C must be true when T.f.g>0'}"`
		d  []string        `tagexpr:"{@:len($)>0 && $[0]=='D'} {msg:sprintf('Invalid d: %v',$)}"`
		e  map[string]int  `tagexpr:"len($)==$['len']"`
		e2 map[string]*int `tagexpr:"len($)==$['len']"`
		f  struct {
			g int `tagexpr:"$"`
		}
	}

	vm := tagexpr.New("tagexpr")
	err := vm.WarmUp(new(T))
	if err != nil {
		panic(err)
	}

	t := &T{
		A:  107,
		B:  "abc",
		C:  true,
		d:  []string{"x", "y"},
		e:  map[string]int{"len": 1},
		e2: map[string]*int{"len": new(int)},
		f: struct {
			g int `tagexpr:"$"`
		}{1},
	}

	tagExpr, err := vm.Run(t)
	if err != nil {
		panic(err)
	}

	fmt.Println(tagExpr.Eval("A@"))
	fmt.Println(tagExpr.Eval("B@"))
	fmt.Println(tagExpr.Eval("C@expr1"))
	fmt.Println(tagExpr.Eval("C@expr2"))
	if !tagExpr.Eval("d@").(bool) {
		fmt.Println(tagExpr.Eval("d@msg"))
	}
	fmt.Println(tagExpr.Eval("e@"))
	fmt.Println(tagExpr.Eval("e2@"))
	fmt.Println(tagExpr.Eval("f.g@"))

	// Output:
	// true
	// true
	// true
	// C must be true when T.f.g>0
	// Invalid d: [x y]
	// true
	// false
	// 1
}

Syntax

Struct tag syntax spec:

type T struct {
	// Single model
    Field1 T1 `tagName:"expression"`
	// Multiple model
    Field2 T2 `tagName:"{exprName:expression} [{exprName2:expression2}]..."`
    ...
}

NOTE: The exprName under the same struct field cannot be the same!

Operator or Expression example Explain
true bool "true"
false bool "false"
1 float64 "1"
1.0 float64 "1.0"
'S' String "S"
+ Digital addition or string splicing
- Digital subtraction or negative
* Digital multiplication
/ Digital division
% division remainder, as: float64(int64(a)%int64(b))
== eq
!= ne
> gt
>= ge
< lt
<= le
&& Logic and
|| Logic or
() Expression group
(X)$ Struct field value named X
(X.Y)$ Struct field value named X.Y
$ Shorthand for (X)$, omit (X) to indicate current struct field value
(X)$['A'] Map value with key A in the struct field X
(X)$[0] The 0th element of the struct field X(type: map, slice, array)
len((X)$) Built-in function len, the length of struct field X
len() Built-in function len, the length of the current struct field
regexp('^\\w*$', (X)$) Regular match the struct field X, return boolean
regexp('^\\w*$') Regular match the current struct field, return boolean
sprintf('X value: %v', (X)$) fmt.Sprintf, format the value of struct field X

Operator priority(high -> low):

  • () bool string float64 !
  • * / %
  • + -
  • < <= > >=
  • == !=
  • &&
  • ||

Selector

If expession is multiple model and exprName is not @:

field_lv1.field_lv2...field_lvn@exprName

If expession is single model or exprName is @:

field_lv1.field_lv2...field_lvn@

Benchmark

goos: darwin
goarch: amd64
pkg: github.com/bytedance/go-tagexpr
BenchmarkTagExpr-4   	10000000	       195 ns/op	      40 B/op	       4 allocs/op
BenchmarkReflect-4   	10000000	       208 ns/op	      16 B/op	       2 allocs/op
PASS

Go to test code

Documentation

Overview

Package tagexpr is an interesting go struct tag expression syntax for field validation, etc.

Copyright 2019 Bytedance Inc. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Example
package main

import (
	"fmt"

	tagexpr "github.com/bytedance/go-tagexpr"
)

func main() {
	type T struct {
		A  int             `tagexpr:"$<0||$>=100"`
		B  string          `tagexpr:"len($)>1 && regexp('^\\w*$')"`
		C  bool            `tagexpr:"{expr1:(f.g)$>0 && $}{expr2:'C must be true when T.f.g>0'}"`
		d  []string        `tagexpr:"{@:len($)>0 && $[0]=='D'} {msg:sprintf('Invalid d: %v',$)}"`
		e  map[string]int  `tagexpr:"len($)==$['len']"`
		e2 map[string]*int `tagexpr:"len($)==$['len']"`
		f  struct {
			g int `tagexpr:"$"`
		}
	}

	vm := tagexpr.New("tagexpr")
	err := vm.WarmUp(new(T))
	if err != nil {
		panic(err)
	}

	t := &T{
		A:  107,
		B:  "abc",
		C:  true,
		d:  []string{"x", "y"},
		e:  map[string]int{"len": 1},
		e2: map[string]*int{"len": new(int)},
		f: struct {
			g int `tagexpr:"$"`
		}{1},
	}

	tagExpr, err := vm.Run(t)
	if err != nil {
		panic(err)
	}

	fmt.Println(tagExpr.Eval("A@"))
	fmt.Println(tagExpr.Eval("B@"))
	fmt.Println(tagExpr.Eval("C@expr1"))
	fmt.Println(tagExpr.Eval("C@expr2"))
	if !tagExpr.Eval("d@").(bool) {
		fmt.Println(tagExpr.Eval("d@msg"))
	}
	fmt.Println(tagExpr.Eval("e@"))
	fmt.Println(tagExpr.Eval("e2@"))
	fmt.Println(tagExpr.Eval("f.g@"))

}
Output:

true
true
true
C must be true when T.f.g>0
Invalid d: [x y]
true
false
1

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Expr

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

Expr expression

type ExprNode

type ExprNode interface {
	SetParent(ExprNode)
	Parent() ExprNode
	LeftOperand() ExprNode
	RightOperand() ExprNode
	SetLeftOperand(ExprNode)
	SetRightOperand(ExprNode)
	Run(string, *TagExpr) interface{}
}

ExprNode expression interface

type Field

type Field struct {
	reflect.StructField
	// contains filtered or unexported fields
}

Field tag expression set of struct field

type Struct

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

Struct tag expression set of struct

type TagExpr

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

TagExpr struct tag expression evaluator

func (*TagExpr) Eval

func (t *TagExpr) Eval(selector string) interface{}

Eval evaluate the value of the struct tag expression by the selector expression. NOTE:

format: fieldName, fieldName.exprName, fieldName1.fieldName2.exprName1
result types: float64, string, bool, nil

func (*TagExpr) EvalBool added in v1.1.0

func (t *TagExpr) EvalBool(selector string) bool

EvalBool evaluate the value of the struct tag expression by the selector expression. NOTE:

If the expression value type is not bool, return false.

func (*TagExpr) EvalFloat added in v1.1.0

func (t *TagExpr) EvalFloat(selector string) float64

EvalFloat evaluate the value of the struct tag expression by the selector expression. NOTE:

If the expression value type is not float64, return 0.

func (*TagExpr) EvalString added in v1.1.0

func (t *TagExpr) EvalString(selector string) string

EvalString evaluate the value of the struct tag expression by the selector expression. NOTE:

If the expression value type is not string, return "".

func (*TagExpr) Range

func (t *TagExpr) Range(fn func(selector string, eval func() interface{}) bool)

Range loop through each tag expression NOTE:

eval result types: float64, string, bool, nil

type VM

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

VM struct tag expression interpreter

func New

func New(tagName string) *VM

New creates a tag expression interpreter that uses @tagName as the tag name.

func (*VM) Run

func (vm *VM) Run(structPtr interface{}) (*TagExpr, error)

Run returns the tag expression handler of the @structPtr. NOTE:

If the structure type has not been warmed up,
it will be slower when it is first called.

func (*VM) WarmUp

func (vm *VM) WarmUp(structOrStructPtr interface{}) error

WarmUp warms up the interpreter of the struct type to improve the performance of the vm.Run .

Directories

Path Synopsis
Package validator is a powerful validator that supports struct tag expression.
Package validator is a powerful validator that supports struct tag expression.

Jump to

Keyboard shortcuts

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