github.com/bytedance/go-tagexpr/v2@v2.9.8/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/v2/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/v2/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  		OtherPhones  []string `vd:"range($, phone(#v,'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  		OtherPhones: []string{"18812345679", "18812345680"},
    45  	}
    46  	fmt.Println(vd.Validate(info))
    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  	type B struct {
    56  		B string `vd:"len($)>1 && regexp('^\\w*$')"`
    57  	}
    58  	b := &B{"abc"}
    59  	fmt.Println(vd.Validate(b) == nil)
    60  
    61  	type C struct {
    62  		C bool `vd:"@:(S.A)$>0 && !$; msg:'C must be false when S.A>0'"`
    63  		S *A
    64  	}
    65  	c := &C{C: true, S: a}
    66  	fmt.Println(vd.Validate(c))
    67  
    68  	type D struct {
    69  		d []string `vd:"@:len($)>0 && $[0]=='D'; msg:sprintf('invalid d: %v',$)"`
    70  	}
    71  	d := &D{d: []string{"x", "y"}}
    72  	fmt.Println(vd.Validate(d))
    73  
    74  	type E struct {
    75  		e map[string]int `vd:"len($)==$['len']"`
    76  	}
    77  	e := &E{map[string]int{"len": 2}}
    78  	fmt.Println(vd.Validate(e))
    79  
    80  	// Customizes the factory of validation error.
    81  	vd.SetErrorFactory(func(failPath, msg string) error {
    82  		return fmt.Errorf(`{"succ":false, "error":"validation failed: %s"}`, failPath)
    83  	})
    84  
    85  	type F struct {
    86  		f struct {
    87  			g int `vd:"$%3==0"`
    88  		}
    89  	}
    90  	f := &F{}
    91  	f.f.g = 10
    92  	fmt.Println(vd.Validate(f))
    93  
    94  	fmt.Println(vd.Validate(map[string]*F{"a": f}))
    95  	fmt.Println(vd.Validate(map[string]map[string]*F{"a": {"b": f}}))
    96  	fmt.Println(vd.Validate([]map[string]*F{{"a": f}}))
    97  	fmt.Println(vd.Validate(struct {
    98  		A []map[string]*F
    99  	}{A: []map[string]*F{{"x": f}}}))
   100  	fmt.Println(vd.Validate(map[*F]int{f: 1}))
   101  	fmt.Println(vd.Validate([][1]*F{{f}}))
   102  	fmt.Println(vd.Validate((*F)(nil)))
   103  	fmt.Println(vd.Validate(map[string]*F{}))
   104  	fmt.Println(vd.Validate(map[string]map[string]*F{}))
   105  	fmt.Println(vd.Validate([]map[string]*F{}))
   106  	fmt.Println(vd.Validate([]*F{}))
   107  
   108  	// Output:
   109  	// <nil>
   110  	// email format is incorrect
   111  	// true
   112  	// C must be false when S.A>0
   113  	// invalid d: [x y]
   114  	// invalid parameter: e
   115  	// {"succ":false, "error":"validation failed: f.g"}
   116  	// {"succ":false, "error":"validation failed: {v for k=a}.f.g"}
   117  	// {"succ":false, "error":"validation failed: {v for k=a}{v for k=b}.f.g"}
   118  	// {"succ":false, "error":"validation failed: [0]{v for k=a}.f.g"}
   119  	// {"succ":false, "error":"validation failed: A[0]{v for k=x}.f.g"}
   120  	// {"succ":false, "error":"validation failed: {k}.f.g"}
   121  	// {"succ":false, "error":"validation failed: [0][0].f.g"}
   122  	// unsupport data: nil
   123  	// <nil>
   124  	// <nil>
   125  	// <nil>
   126  	// <nil>
   127  }
   128  ```
   129  
   130  ## Syntax
   131  
   132  Struct tag syntax spec:
   133  
   134  ```
   135  type T struct {
   136  	// Simple model
   137      Field1 T1 `tagName:"expression"`
   138  	// Specify error message mode
   139      Field2 T2 `tagName:"@:expression; msg:expression2"`
   140  	// Omit it
   141      Field3 T3 `tagName:"-"`
   142      // Omit it when it is nil
   143      Field4 T4 `tagName:"?"`
   144      ...
   145  }
   146  ```
   147  
   148  |Operator or Operand|Explain|
   149  |-----|---------|
   150  |`true` `false`|boolean|
   151  |`0` `0.0`|float64 "0"|
   152  |`''`|String|
   153  |`\\'`| Escape `'` delims in string|
   154  |`\"`| Escape `"` delims in string|
   155  |`nil`|nil, undefined|
   156  |`!`|not|
   157  |`+`|Digital addition or string splicing|
   158  |`-`|Digital subtraction or negative|
   159  |`*`|Digital multiplication|
   160  |`/`|Digital division|
   161  |`%`|division remainder, as: `float64(int64(a)%int64(b))`|
   162  |`==`|`eq`|
   163  |`!=`|`ne`|
   164  |`>`|`gt`|
   165  |`>=`|`ge`|
   166  |`<`|`lt`|
   167  |`<=`|`le`|
   168  |`&&`|Logic `and`|
   169  |`\|\|`|Logic `or`|
   170  |`()`|Expression group|
   171  |`(X)$`|Struct field value named X|
   172  |`(X.Y)$`|Struct field value named X.Y|
   173  |`$`|Shorthand for `(X)$`, omit `(X)` to indicate current struct field value|
   174  |`(X)$['A']`|Map value with key A or struct A sub-field in the struct field X|
   175  |`(X)$[0]`|The 0th element or sub-field of the struct field X(type: map, slice, array, struct)|
   176  |`len((X)$)`|Built-in function `len`, the length of struct field X|
   177  |`mblen((X)$)`|the length of string field X (character number)|
   178  |`regexp('^\\w*$', (X)$)`|Regular match the struct field X, return boolean|
   179  |`regexp('^\\w*$')`|Regular match the current struct field, return boolean|
   180  |`sprintf('X value: %v', (X)$)`|`fmt.Sprintf`, format the value of struct field X|
   181  |`range(KvExpr, forEachExpr)`|Iterate over an array, slice, or dictionary <br> - `#k` is the element key var <br> - `#v` is the element value var <br> - `##` is the number of elements <br> - e.g. [example](../spec_range_test.go)|
   182  |`in((X)$, enum_1, ...enum_n)`|Check if the first parameter is one of the enumerated parameters|
   183  |`email((X)$)`|Regular match the struct field X, return true if it is email|
   184  |`phone((X)$,<'defaultRegion'>)`|Regular match the struct field X, return true if it is phone|
   185  
   186  <!-- |`(X)$k`|Traverse each element key of the struct field X(type: map, slice, array)|
   187  |`(X)$v`|Traverse each element value of the struct field X(type: map, slice, array)| -->
   188  
   189  <!-- |`&`|Integer bitwise `and`|
   190  |`\|`|Integer bitwise `or`|
   191  |`^`|Integer bitwise `not` or `xor`|
   192  |`&^`|Integer bitwise `clean`|
   193  |`<<`|Integer bitwise `shift left`|
   194  |`>>`|Integer bitwise `shift right`| -->
   195  
   196  Operator priority(high -> low):
   197  
   198  * `()` `!` `bool` `float64` `string` `nil`
   199  * `*` `/` `%`
   200  * `+` `-`
   201  * `<` `<=` `>` `>=`
   202  * `==` `!=`
   203  * `&&`
   204  * `||`