github.com/bytedance/go-tagexpr@v2.7.5-0.20210114074101-de5b8743ad85+incompatible/validator/README.md (about)

     1  # validator [![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat-square)](http://godoc.org/github.com/bytedance/go-tagexpr/validator)
     2  
     3  A powerful validator that supports struct tag expression.
     4  
     5  ## Feature
     6  
     7  - Support for a variety of common operator
     8  - Support for accessing arrays, slices, members of the dictionary
     9  - Support access to any field in the current structure
    10  - Support access to nested fields, non-exported fields, etc.
    11  - Support registers validator function expression
    12  - Built-in len, sprintf, regexp, email, phone functions
    13  - Support simple mode, or specify error message mode
    14  - Use offset pointers to directly take values, better performance
    15  - Required go version ≥1.9
    16  
    17  ## Example
    18  
    19  ```go
    20  package validator_test
    21  
    22  import (
    23  	"fmt"
    24  
    25  	vd "github.com/bytedance/go-tagexpr/validator"
    26  )
    27  
    28  func Example() {
    29  	type InfoRequest struct {
    30  		Name         string `vd:"($!='Alice'||(Age)$==18) && regexp('\\w')"`
    31  		Age          int    `vd:"$>0"`
    32  		Email        string `vd:"email($)"`
    33  		Phone1       string `vd:"phone($)"`
    34  		Phone2       string `vd:"phone($,'CN')"`
    35  		*InfoRequest `vd:"?"`
    36  		Info1        *InfoRequest `vd:"?"`
    37  		Info2        *InfoRequest `vd:"-"`
    38  	}
    39  	info := InfoRequest{
    40  		Name:   "Alice",
    41  		Age:    18,
    42  		Email:  "henrylee2cn@gmail.com",
    43  		Phone1: "+8618812345678",
    44  		Phone2: "18812345678",
    45  	}
    46  	fmt.Println(vd.Validate(info) == nil)
    47  
    48  	type A struct {
    49  		A    int `vd:"$<0||$>=100"`
    50  		Info interface{}
    51  	}
    52  	info.Email = "xxx"
    53  	a := &A{A: 107, Info: info}
    54  	fmt.Println(vd.Validate(a))
    55  
    56  	type B struct {
    57  		B string `vd:"len($)>1 && regexp('^\\w*$')"`
    58  	}
    59  	b := &B{"abc"}
    60  	fmt.Println(vd.Validate(b) == nil)
    61  
    62  	type C struct {
    63  		C bool `vd:"@:(S.A)$>0 && !$; msg:'C must be false when S.A>0'"`
    64  		S *A
    65  	}
    66  	c := &C{C: true, S: a}
    67  	fmt.Println(vd.Validate(c))
    68  
    69  	type D struct {
    70  		d []string `vd:"@:len($)>0 && $[0]=='D'; msg:sprintf('invalid d: %v',$)"`
    71  	}
    72  	d := &D{d: []string{"x", "y"}}
    73  	fmt.Println(vd.Validate(d))
    74  
    75  	type E struct {
    76  		e map[string]int `vd:"len($)==$['len']"`
    77  	}
    78  	e := &E{map[string]int{"len": 2}}
    79  	fmt.Println(vd.Validate(e))
    80  
    81  	// Customizes the factory of validation error.
    82  	vd.SetErrorFactory(func(failPath, msg string) error {
    83  		return fmt.Errorf(`{"succ":false, "error":"validation failed: %s"}`, failPath)
    84  	})
    85  
    86  	type F struct {
    87  		f struct {
    88  			g int `vd:"$%3==0"`
    89  		}
    90  	}
    91  	f := &F{}
    92  	f.f.g = 10
    93  	fmt.Println(vd.Validate(f))
    94  
    95  	fmt.Println(vd.Validate(map[string]*F{"a": f}))
    96  	fmt.Println(vd.Validate(map[*F]int{f: 1}))
    97  	fmt.Println(vd.Validate([][1]*F{{f}}))
    98  	fmt.Println(vd.Validate((*F)(nil)))
    99  	fmt.Println(vd.Validate(map[string]*F{}))
   100  	fmt.Println(vd.Validate([]*F{}))
   101  
   102  	// Output:
   103  	// true
   104  	// invalid parameter: Info.Email
   105  	// true
   106  	// C must be false when S.A>0
   107  	// invalid d: [x y]
   108  	// invalid parameter: e
   109  	// {"succ":false, "error":"validation failed: f.g"}
   110  	// {"succ":false, "error":"validation failed: {K:a}.f.g"}
   111  	// {"succ":false, "error":"validation failed: {}.f.g"}
   112  	// {"succ":false, "error":"validation failed: [0][0].f.g"}
   113  	// unsupport data: nil
   114  	// <nil>
   115  	// <nil>
   116  }
   117  ```
   118  
   119  ## Syntax
   120  
   121  Struct tag syntax spec:
   122  
   123  ```
   124  type T struct {
   125  	// Simple model
   126      Field1 T1 `tagName:"expression"`
   127  	// Specify error message mode
   128      Field2 T2 `tagName:"@:expression; msg:expression2"`
   129  	// Omit it
   130      Field3 T3 `tagName:"-"`
   131      // Omit it when it is nil
   132      Field4 T4 `tagName:"?"`
   133      ...
   134  }
   135  ```
   136  
   137  |Operator or Operand|Explain|
   138  |-----|---------|
   139  |`true` `false`|boolean|
   140  |`0` `0.0`|float64 "0"|
   141  |`''`|String|
   142  |`\\'`| Escape `'` delims in string|
   143  |`\"`| Escape `"` delims in string|
   144  |`nil`|nil, undefined|
   145  |`!`|not, suitable for `bool`, `string`, `float64`, `nil`, `$` and `()`|
   146  |`+`|Digital addition or string splicing|
   147  |`-`|Digital subtraction or negative|
   148  |`*`|Digital multiplication|
   149  |`/`|Digital division|
   150  |`%`|division remainder, as: `float64(int64(a)%int64(b))`|
   151  |`==`|`eq`|
   152  |`!=`|`ne`|
   153  |`>`|`gt`|
   154  |`>=`|`ge`|
   155  |`<`|`lt`|
   156  |`<=`|`le`|
   157  |`&&`|Logic `and`|
   158  |`\|\|`|Logic `or`|
   159  |`()`|Expression group|
   160  |`(X)$`|Struct field value named X|
   161  |`(X.Y)$`|Struct field value named X.Y|
   162  |`$`|Shorthand for `(X)$`, omit `(X)` to indicate current struct field value|
   163  |`(X)$['A']`|Map value with key A or struct A sub-field in the struct field X|
   164  |`(X)$[0]`|The 0th element or sub-field of the struct field X(type: map, slice, array, struct)|
   165  |`len((X)$)`|Built-in function `len`, the length of struct field X|
   166  |`regexp('^\\w*$', (X)$)`|Regular match the struct field X, return boolean|
   167  |`regexp('^\\w*$')`|Regular match the current struct field, return boolean|
   168  |`sprintf('X value: %v', (X)$)`|`fmt.Sprintf`, format the value of struct field X|
   169  |`email((X)$)`|Regular match the struct field X, return true if it is email|
   170  |`phone((X)$,<'defaultRegion'>)`|Regular match the struct field X, return true if it is phone|
   171  |`in((X)$, enum_1, ...enum_n)`|Check if the first parameter is one of the enumerated parameters|
   172  
   173  <!-- |`(X)$k`|Traverse each element key of the struct field X(type: map, slice, array)|
   174  |`(X)$v`|Traverse each element value of the struct field X(type: map, slice, array)| -->
   175  
   176  <!-- |`&`|Integer bitwise `and`|
   177  |`\|`|Integer bitwise `or`|
   178  |`^`|Integer bitwise `not` or `xor`|
   179  |`&^`|Integer bitwise `clean`|
   180  |`<<`|Integer bitwise `shift left`|
   181  |`>>`|Integer bitwise `shift right`| -->
   182  
   183  Operator priority(high -> low):
   184  
   185  * `()` `!` `bool` `float64` `string` `nil`
   186  * `*` `/` `%`
   187  * `+` `-`
   188  * `<` `<=` `>` `>=`
   189  * `==` `!=`
   190  * `&&`
   191  * `||`