45

GitHub - bytedance/go-tagexpr: An interesting go struct tag expression syntax fo...

 5 years ago
source link: https://github.com/bytedance/go-tagexpr
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

README.md

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK