package
2.5.0+incompatible
Repository: https://github.com/mfcab/go-tagexpr.git
Documentation: pkg.go.dev
# README
validator 
A powerful validator that supports struct tag expression.
Feature
- Support for a variety of common operator
- Support for accessing arrays, slices, members of the dictionary
- Support access to any field in the current structure
- Support access to nested fields, non-exported fields, etc.
- Support registers validator function expression
- Built-in len, sprintf, regexp, email, phone functions
- Support simple mode, or specify error message mode
- Use offset pointers to directly take values, better performance
- Required go version ≥1.9
Example
package validator_test
import (
"fmt"
vd "github.com/bytedance/go-tagexpr/validator"
)
func Example() {
type InfoRequest struct {
Name string `vd:"($!='Alice'||(Age)$==18) && regexp('\\w')"`
Age int `vd:"$>0"`
Email string `vd:"email($)"`
Phone1 string `vd:"phone($)"`
Phone2 string `vd:"phone($,'CN')"`
*InfoRequest `vd:"?"`
Info1 *InfoRequest `vd:"?"`
Info2 *InfoRequest `vd:"-"`
}
info := InfoRequest{
Name: "Alice",
Age: 18,
Email: "[email protected]",
Phone1: "+8618812345678",
Phone2: "18812345678",
}
fmt.Println(vd.Validate(info) == nil)
type A struct {
A int `vd:"$<0||$>=100"`
Info interface{}
}
info.Email = "xxx"
a := &A{A: 107, Info: info}
fmt.Println(vd.Validate(a))
type B struct {
B string `vd:"len($)>1 && regexp('^\\w*$')"`
}
b := &B{"abc"}
fmt.Println(vd.Validate(b) == nil)
type C struct {
C bool `vd:"@:(S.A)$>0 && !$; msg:'C must be false when S.A>0'"`
S *A
}
c := &C{C: true, S: a}
fmt.Println(vd.Validate(c))
type D struct {
d []string `vd:"@:len($)>0 && $[0]=='D'; msg:sprintf('invalid d: %v',$)"`
}
d := &D{d: []string{"x", "y"}}
fmt.Println(vd.Validate(d))
type E struct {
e map[string]int `vd:"len($)==$['len']"`
}
e := &E{map[string]int{"len": 2}}
fmt.Println(vd.Validate(e))
// Customizes the factory of validation error.
vd.SetErrorFactory(func(failPath, msg string) error {
return fmt.Errorf(`{"succ":false, "error":"validation failed: %s"}`, failPath)
})
type F struct {
f struct {
g int `vd:"$%3==0"`
}
}
f := &F{}
f.f.g = 10
fmt.Println(vd.Validate(f))
fmt.Println(vd.Validate(map[string]*F{"a": f}))
fmt.Println(vd.Validate(map[*F]int{f: 1}))
fmt.Println(vd.Validate([][1]*F{{f}}))
fmt.Println(vd.Validate((*F)(nil)))
fmt.Println(vd.Validate(map[string]*F{}))
fmt.Println(vd.Validate([]*F{}))
// Output:
// true
// invalid parameter: Info.Email
// true
// C must be false when S.A>0
// invalid d: [x y]
// invalid parameter: e
// {"succ":false, "error":"validation failed: f.g"}
// {"succ":false, "error":"validation failed: {K:a}.f.g"}
// {"succ":false, "error":"validation failed: {}.f.g"}
// {"succ":false, "error":"validation failed: [0][0].f.g"}
// unsupport data: nil
// <nil>
// <nil>
}
Syntax
Struct tag syntax spec:
type T struct {
// Simple model
Field1 T1 `tagName:"expression"`
// Specify error message mode
Field2 T2 `tagName:"@:expression; msg:expression2"`
// Omit it
Field3 T3 `tagName:"-"`
// Omit it when it is nil
Field4 T4 `tagName:"?"`
...
}
Operator or Operand | Explain |
---|---|
true false | boolean |
0 0.0 | float64 "0" |
'' | String |
\\' | Escape ' delims in string |
\" | Escape " delims in string |
nil | nil, undefined |
! | not, suitable for bool , string , float64 , nil , $ and () |
+ | 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 or struct A sub-field in the struct field X |
(X)$[0] | The 0th element or sub-field of the struct field X(type: map, slice, array, struct) |
len((X)$) | Built-in function len , the length of struct field X |
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 |
email((X)$) | Regular match the struct field X, return true if it is email |
phone((X)$,<'defaultRegion'>) | Regular match the struct field X, return true if it is phone |
Operator priority(high -> low):
()
!
bool
float64
string
nil
*
/
%
+
-
<
<=
>
>=
==
!=
&&
||