...

Source file src/github.com/go-playground/validator/v10/validator_instance.go

Documentation: github.com/go-playground/validator/v10

     1  package validator
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"reflect"
     8  	"strings"
     9  	"sync"
    10  	"time"
    11  
    12  	ut "github.com/go-playground/universal-translator"
    13  )
    14  
    15  const (
    16  	defaultTagName        = "validate"
    17  	utf8HexComma          = "0x2C"
    18  	utf8Pipe              = "0x7C"
    19  	tagSeparator          = ","
    20  	orSeparator           = "|"
    21  	tagKeySeparator       = "="
    22  	structOnlyTag         = "structonly"
    23  	noStructLevelTag      = "nostructlevel"
    24  	omitempty             = "omitempty"
    25  	omitnil               = "omitnil"
    26  	isdefault             = "isdefault"
    27  	requiredWithoutAllTag = "required_without_all"
    28  	requiredWithoutTag    = "required_without"
    29  	requiredWithTag       = "required_with"
    30  	requiredWithAllTag    = "required_with_all"
    31  	requiredIfTag         = "required_if"
    32  	requiredUnlessTag     = "required_unless"
    33  	skipUnlessTag         = "skip_unless"
    34  	excludedWithoutAllTag = "excluded_without_all"
    35  	excludedWithoutTag    = "excluded_without"
    36  	excludedWithTag       = "excluded_with"
    37  	excludedWithAllTag    = "excluded_with_all"
    38  	excludedIfTag         = "excluded_if"
    39  	excludedUnlessTag     = "excluded_unless"
    40  	skipValidationTag     = "-"
    41  	diveTag               = "dive"
    42  	keysTag               = "keys"
    43  	endKeysTag            = "endkeys"
    44  	requiredTag           = "required"
    45  	namespaceSeparator    = "."
    46  	leftBracket           = "["
    47  	rightBracket          = "]"
    48  	restrictedTagChars    = ".[],|=+()`~!@#$%^&*\\\"/?<>{}"
    49  	restrictedAliasErr    = "Alias '%s' either contains restricted characters or is the same as a restricted tag needed for normal operation"
    50  	restrictedTagErr      = "Tag '%s' either contains restricted characters or is the same as a restricted tag needed for normal operation"
    51  )
    52  
    53  var (
    54  	timeDurationType = reflect.TypeOf(time.Duration(0))
    55  	timeType         = reflect.TypeOf(time.Time{})
    56  
    57  	byteSliceType = reflect.TypeOf([]byte{})
    58  
    59  	defaultCField = &cField{namesEqual: true}
    60  )
    61  
    62  // FilterFunc is the type used to filter fields using
    63  // StructFiltered(...) function.
    64  // returning true results in the field being filtered/skipped from
    65  // validation
    66  type FilterFunc func(ns []byte) bool
    67  
    68  // CustomTypeFunc allows for overriding or adding custom field type handler functions
    69  // field = field value of the type to return a value to be validated
    70  // example Valuer from sql drive see https://golang.org/src/database/sql/driver/types.go?s=1210:1293#L29
    71  type CustomTypeFunc func(field reflect.Value) interface{}
    72  
    73  // TagNameFunc allows for adding of a custom tag name parser
    74  type TagNameFunc func(field reflect.StructField) string
    75  
    76  type internalValidationFuncWrapper struct {
    77  	fn                FuncCtx
    78  	runValidatinOnNil bool
    79  }
    80  
    81  // Validate contains the validator settings and cache
    82  type Validate struct {
    83  	tagName               string
    84  	pool                  *sync.Pool
    85  	tagNameFunc           TagNameFunc
    86  	structLevelFuncs      map[reflect.Type]StructLevelFuncCtx
    87  	customFuncs           map[reflect.Type]CustomTypeFunc
    88  	aliases               map[string]string
    89  	validations           map[string]internalValidationFuncWrapper
    90  	transTagFunc          map[ut.Translator]map[string]TranslationFunc // map[<locale>]map[<tag>]TranslationFunc
    91  	rules                 map[reflect.Type]map[string]string
    92  	tagCache              *tagCache
    93  	structCache           *structCache
    94  	hasCustomFuncs        bool
    95  	hasTagNameFunc        bool
    96  	requiredStructEnabled bool
    97  }
    98  
    99  // New returns a new instance of 'validate' with sane defaults.
   100  // Validate is designed to be thread-safe and used as a singleton instance.
   101  // It caches information about your struct and validations,
   102  // in essence only parsing your validation tags once per struct type.
   103  // Using multiple instances neglects the benefit of caching.
   104  func New(options ...Option) *Validate {
   105  
   106  	tc := new(tagCache)
   107  	tc.m.Store(make(map[string]*cTag))
   108  
   109  	sc := new(structCache)
   110  	sc.m.Store(make(map[reflect.Type]*cStruct))
   111  
   112  	v := &Validate{
   113  		tagName:     defaultTagName,
   114  		aliases:     make(map[string]string, len(bakedInAliases)),
   115  		validations: make(map[string]internalValidationFuncWrapper, len(bakedInValidators)),
   116  		tagCache:    tc,
   117  		structCache: sc,
   118  	}
   119  
   120  	// must copy alias validators for separate validations to be used in each validator instance
   121  	for k, val := range bakedInAliases {
   122  		v.RegisterAlias(k, val)
   123  	}
   124  
   125  	// must copy validators for separate validations to be used in each instance
   126  	for k, val := range bakedInValidators {
   127  
   128  		switch k {
   129  		// these require that even if the value is nil that the validation should run, omitempty still overrides this behaviour
   130  		case requiredIfTag, requiredUnlessTag, requiredWithTag, requiredWithAllTag, requiredWithoutTag, requiredWithoutAllTag,
   131  			excludedIfTag, excludedUnlessTag, excludedWithTag, excludedWithAllTag, excludedWithoutTag, excludedWithoutAllTag,
   132  			skipUnlessTag:
   133  			_ = v.registerValidation(k, wrapFunc(val), true, true)
   134  		default:
   135  			// no need to error check here, baked in will always be valid
   136  			_ = v.registerValidation(k, wrapFunc(val), true, false)
   137  		}
   138  	}
   139  
   140  	v.pool = &sync.Pool{
   141  		New: func() interface{} {
   142  			return &validate{
   143  				v:        v,
   144  				ns:       make([]byte, 0, 64),
   145  				actualNs: make([]byte, 0, 64),
   146  				misc:     make([]byte, 32),
   147  			}
   148  		},
   149  	}
   150  
   151  	for _, o := range options {
   152  		o(v)
   153  	}
   154  	return v
   155  }
   156  
   157  // SetTagName allows for changing of the default tag name of 'validate'
   158  func (v *Validate) SetTagName(name string) {
   159  	v.tagName = name
   160  }
   161  
   162  // ValidateMapCtx validates a map using a map of validation rules and allows passing of contextual
   163  // validation information via context.Context.
   164  func (v Validate) ValidateMapCtx(ctx context.Context, data map[string]interface{}, rules map[string]interface{}) map[string]interface{} {
   165  	errs := make(map[string]interface{})
   166  	for field, rule := range rules {
   167  		if ruleObj, ok := rule.(map[string]interface{}); ok {
   168  			if dataObj, ok := data[field].(map[string]interface{}); ok {
   169  				err := v.ValidateMapCtx(ctx, dataObj, ruleObj)
   170  				if len(err) > 0 {
   171  					errs[field] = err
   172  				}
   173  			} else if dataObjs, ok := data[field].([]map[string]interface{}); ok {
   174  				for _, obj := range dataObjs {
   175  					err := v.ValidateMapCtx(ctx, obj, ruleObj)
   176  					if len(err) > 0 {
   177  						errs[field] = err
   178  					}
   179  				}
   180  			} else {
   181  				errs[field] = errors.New("The field: '" + field + "' is not a map to dive")
   182  			}
   183  		} else if ruleStr, ok := rule.(string); ok {
   184  			err := v.VarCtx(ctx, data[field], ruleStr)
   185  			if err != nil {
   186  				errs[field] = err
   187  			}
   188  		}
   189  	}
   190  	return errs
   191  }
   192  
   193  // ValidateMap validates map data from a map of tags
   194  func (v *Validate) ValidateMap(data map[string]interface{}, rules map[string]interface{}) map[string]interface{} {
   195  	return v.ValidateMapCtx(context.Background(), data, rules)
   196  }
   197  
   198  // RegisterTagNameFunc registers a function to get alternate names for StructFields.
   199  //
   200  // eg. to use the names which have been specified for JSON representations of structs, rather than normal Go field names:
   201  //
   202  //	validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
   203  //	    name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
   204  //	    // skip if tag key says it should be ignored
   205  //	    if name == "-" {
   206  //	        return ""
   207  //	    }
   208  //	    return name
   209  //	})
   210  func (v *Validate) RegisterTagNameFunc(fn TagNameFunc) {
   211  	v.tagNameFunc = fn
   212  	v.hasTagNameFunc = true
   213  }
   214  
   215  // RegisterValidation adds a validation with the given tag
   216  //
   217  // NOTES:
   218  // - if the key already exists, the previous validation function will be replaced.
   219  // - this method is not thread-safe it is intended that these all be registered prior to any validation
   220  func (v *Validate) RegisterValidation(tag string, fn Func, callValidationEvenIfNull ...bool) error {
   221  	return v.RegisterValidationCtx(tag, wrapFunc(fn), callValidationEvenIfNull...)
   222  }
   223  
   224  // RegisterValidationCtx does the same as RegisterValidation on accepts a FuncCtx validation
   225  // allowing context.Context validation support.
   226  func (v *Validate) RegisterValidationCtx(tag string, fn FuncCtx, callValidationEvenIfNull ...bool) error {
   227  	var nilCheckable bool
   228  	if len(callValidationEvenIfNull) > 0 {
   229  		nilCheckable = callValidationEvenIfNull[0]
   230  	}
   231  	return v.registerValidation(tag, fn, false, nilCheckable)
   232  }
   233  
   234  func (v *Validate) registerValidation(tag string, fn FuncCtx, bakedIn bool, nilCheckable bool) error {
   235  	if len(tag) == 0 {
   236  		return errors.New("function Key cannot be empty")
   237  	}
   238  
   239  	if fn == nil {
   240  		return errors.New("function cannot be empty")
   241  	}
   242  
   243  	_, ok := restrictedTags[tag]
   244  	if !bakedIn && (ok || strings.ContainsAny(tag, restrictedTagChars)) {
   245  		panic(fmt.Sprintf(restrictedTagErr, tag))
   246  	}
   247  	v.validations[tag] = internalValidationFuncWrapper{fn: fn, runValidatinOnNil: nilCheckable}
   248  	return nil
   249  }
   250  
   251  // RegisterAlias registers a mapping of a single validation tag that
   252  // defines a common or complex set of validation(s) to simplify adding validation
   253  // to structs.
   254  //
   255  // NOTE: this function is not thread-safe it is intended that these all be registered prior to any validation
   256  func (v *Validate) RegisterAlias(alias, tags string) {
   257  
   258  	_, ok := restrictedTags[alias]
   259  
   260  	if ok || strings.ContainsAny(alias, restrictedTagChars) {
   261  		panic(fmt.Sprintf(restrictedAliasErr, alias))
   262  	}
   263  
   264  	v.aliases[alias] = tags
   265  }
   266  
   267  // RegisterStructValidation registers a StructLevelFunc against a number of types.
   268  //
   269  // NOTE:
   270  // - this method is not thread-safe it is intended that these all be registered prior to any validation
   271  func (v *Validate) RegisterStructValidation(fn StructLevelFunc, types ...interface{}) {
   272  	v.RegisterStructValidationCtx(wrapStructLevelFunc(fn), types...)
   273  }
   274  
   275  // RegisterStructValidationCtx registers a StructLevelFuncCtx against a number of types and allows passing
   276  // of contextual validation information via context.Context.
   277  //
   278  // NOTE:
   279  // - this method is not thread-safe it is intended that these all be registered prior to any validation
   280  func (v *Validate) RegisterStructValidationCtx(fn StructLevelFuncCtx, types ...interface{}) {
   281  
   282  	if v.structLevelFuncs == nil {
   283  		v.structLevelFuncs = make(map[reflect.Type]StructLevelFuncCtx)
   284  	}
   285  
   286  	for _, t := range types {
   287  		tv := reflect.ValueOf(t)
   288  		if tv.Kind() == reflect.Ptr {
   289  			t = reflect.Indirect(tv).Interface()
   290  		}
   291  
   292  		v.structLevelFuncs[reflect.TypeOf(t)] = fn
   293  	}
   294  }
   295  
   296  // RegisterStructValidationMapRules registers validate map rules.
   297  // Be aware that map validation rules supersede those defined on a/the struct if present.
   298  //
   299  // NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation
   300  func (v *Validate) RegisterStructValidationMapRules(rules map[string]string, types ...interface{}) {
   301  	if v.rules == nil {
   302  		v.rules = make(map[reflect.Type]map[string]string)
   303  	}
   304  
   305  	deepCopyRules := make(map[string]string)
   306  	for i, rule := range rules {
   307  		deepCopyRules[i] = rule
   308  	}
   309  
   310  	for _, t := range types {
   311  		typ := reflect.TypeOf(t)
   312  
   313  		if typ.Kind() == reflect.Ptr {
   314  			typ = typ.Elem()
   315  		}
   316  
   317  		if typ.Kind() != reflect.Struct {
   318  			continue
   319  		}
   320  		v.rules[typ] = deepCopyRules
   321  	}
   322  }
   323  
   324  // RegisterCustomTypeFunc registers a CustomTypeFunc against a number of types
   325  //
   326  // NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation
   327  func (v *Validate) RegisterCustomTypeFunc(fn CustomTypeFunc, types ...interface{}) {
   328  
   329  	if v.customFuncs == nil {
   330  		v.customFuncs = make(map[reflect.Type]CustomTypeFunc)
   331  	}
   332  
   333  	for _, t := range types {
   334  		v.customFuncs[reflect.TypeOf(t)] = fn
   335  	}
   336  
   337  	v.hasCustomFuncs = true
   338  }
   339  
   340  // RegisterTranslation registers translations against the provided tag.
   341  func (v *Validate) RegisterTranslation(tag string, trans ut.Translator, registerFn RegisterTranslationsFunc, translationFn TranslationFunc) (err error) {
   342  
   343  	if v.transTagFunc == nil {
   344  		v.transTagFunc = make(map[ut.Translator]map[string]TranslationFunc)
   345  	}
   346  
   347  	if err = registerFn(trans); err != nil {
   348  		return
   349  	}
   350  
   351  	m, ok := v.transTagFunc[trans]
   352  	if !ok {
   353  		m = make(map[string]TranslationFunc)
   354  		v.transTagFunc[trans] = m
   355  	}
   356  
   357  	m[tag] = translationFn
   358  
   359  	return
   360  }
   361  
   362  // Struct validates a structs exposed fields, and automatically validates nested structs, unless otherwise specified.
   363  //
   364  // It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
   365  // You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
   366  func (v *Validate) Struct(s interface{}) error {
   367  	return v.StructCtx(context.Background(), s)
   368  }
   369  
   370  // StructCtx validates a structs exposed fields, and automatically validates nested structs, unless otherwise specified
   371  // and also allows passing of context.Context for contextual validation information.
   372  //
   373  // It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
   374  // You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
   375  func (v *Validate) StructCtx(ctx context.Context, s interface{}) (err error) {
   376  
   377  	val := reflect.ValueOf(s)
   378  	top := val
   379  
   380  	if val.Kind() == reflect.Ptr && !val.IsNil() {
   381  		val = val.Elem()
   382  	}
   383  
   384  	if val.Kind() != reflect.Struct || val.Type().ConvertibleTo(timeType) {
   385  		return &InvalidValidationError{Type: reflect.TypeOf(s)}
   386  	}
   387  
   388  	// good to validate
   389  	vd := v.pool.Get().(*validate)
   390  	vd.top = top
   391  	vd.isPartial = false
   392  	// vd.hasExcludes = false // only need to reset in StructPartial and StructExcept
   393  
   394  	vd.validateStruct(ctx, top, val, val.Type(), vd.ns[0:0], vd.actualNs[0:0], nil)
   395  
   396  	if len(vd.errs) > 0 {
   397  		err = vd.errs
   398  		vd.errs = nil
   399  	}
   400  
   401  	v.pool.Put(vd)
   402  
   403  	return
   404  }
   405  
   406  // StructFiltered validates a structs exposed fields, that pass the FilterFunc check and automatically validates
   407  // nested structs, unless otherwise specified.
   408  //
   409  // It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
   410  // You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
   411  func (v *Validate) StructFiltered(s interface{}, fn FilterFunc) error {
   412  	return v.StructFilteredCtx(context.Background(), s, fn)
   413  }
   414  
   415  // StructFilteredCtx validates a structs exposed fields, that pass the FilterFunc check and automatically validates
   416  // nested structs, unless otherwise specified and also allows passing of contextual validation information via
   417  // context.Context
   418  //
   419  // It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
   420  // You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
   421  func (v *Validate) StructFilteredCtx(ctx context.Context, s interface{}, fn FilterFunc) (err error) {
   422  	val := reflect.ValueOf(s)
   423  	top := val
   424  
   425  	if val.Kind() == reflect.Ptr && !val.IsNil() {
   426  		val = val.Elem()
   427  	}
   428  
   429  	if val.Kind() != reflect.Struct || val.Type().ConvertibleTo(timeType) {
   430  		return &InvalidValidationError{Type: reflect.TypeOf(s)}
   431  	}
   432  
   433  	// good to validate
   434  	vd := v.pool.Get().(*validate)
   435  	vd.top = top
   436  	vd.isPartial = true
   437  	vd.ffn = fn
   438  	// vd.hasExcludes = false // only need to reset in StructPartial and StructExcept
   439  
   440  	vd.validateStruct(ctx, top, val, val.Type(), vd.ns[0:0], vd.actualNs[0:0], nil)
   441  
   442  	if len(vd.errs) > 0 {
   443  		err = vd.errs
   444  		vd.errs = nil
   445  	}
   446  
   447  	v.pool.Put(vd)
   448  
   449  	return
   450  }
   451  
   452  // StructPartial validates the fields passed in only, ignoring all others.
   453  // Fields may be provided in a namespaced fashion relative to the  struct provided
   454  // eg. NestedStruct.Field or NestedArrayField[0].Struct.Name
   455  //
   456  // It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
   457  // You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
   458  func (v *Validate) StructPartial(s interface{}, fields ...string) error {
   459  	return v.StructPartialCtx(context.Background(), s, fields...)
   460  }
   461  
   462  // StructPartialCtx validates the fields passed in only, ignoring all others and allows passing of contextual
   463  // validation information via context.Context
   464  // Fields may be provided in a namespaced fashion relative to the  struct provided
   465  // eg. NestedStruct.Field or NestedArrayField[0].Struct.Name
   466  //
   467  // It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
   468  // You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
   469  func (v *Validate) StructPartialCtx(ctx context.Context, s interface{}, fields ...string) (err error) {
   470  	val := reflect.ValueOf(s)
   471  	top := val
   472  
   473  	if val.Kind() == reflect.Ptr && !val.IsNil() {
   474  		val = val.Elem()
   475  	}
   476  
   477  	if val.Kind() != reflect.Struct || val.Type().ConvertibleTo(timeType) {
   478  		return &InvalidValidationError{Type: reflect.TypeOf(s)}
   479  	}
   480  
   481  	// good to validate
   482  	vd := v.pool.Get().(*validate)
   483  	vd.top = top
   484  	vd.isPartial = true
   485  	vd.ffn = nil
   486  	vd.hasExcludes = false
   487  	vd.includeExclude = make(map[string]struct{})
   488  
   489  	typ := val.Type()
   490  	name := typ.Name()
   491  
   492  	for _, k := range fields {
   493  
   494  		flds := strings.Split(k, namespaceSeparator)
   495  		if len(flds) > 0 {
   496  
   497  			vd.misc = append(vd.misc[0:0], name...)
   498  			// Don't append empty name for unnamed structs
   499  			if len(vd.misc) != 0 {
   500  				vd.misc = append(vd.misc, '.')
   501  			}
   502  
   503  			for _, s := range flds {
   504  
   505  				idx := strings.Index(s, leftBracket)
   506  
   507  				if idx != -1 {
   508  					for idx != -1 {
   509  						vd.misc = append(vd.misc, s[:idx]...)
   510  						vd.includeExclude[string(vd.misc)] = struct{}{}
   511  
   512  						idx2 := strings.Index(s, rightBracket)
   513  						idx2++
   514  						vd.misc = append(vd.misc, s[idx:idx2]...)
   515  						vd.includeExclude[string(vd.misc)] = struct{}{}
   516  						s = s[idx2:]
   517  						idx = strings.Index(s, leftBracket)
   518  					}
   519  				} else {
   520  
   521  					vd.misc = append(vd.misc, s...)
   522  					vd.includeExclude[string(vd.misc)] = struct{}{}
   523  				}
   524  
   525  				vd.misc = append(vd.misc, '.')
   526  			}
   527  		}
   528  	}
   529  
   530  	vd.validateStruct(ctx, top, val, typ, vd.ns[0:0], vd.actualNs[0:0], nil)
   531  
   532  	if len(vd.errs) > 0 {
   533  		err = vd.errs
   534  		vd.errs = nil
   535  	}
   536  
   537  	v.pool.Put(vd)
   538  
   539  	return
   540  }
   541  
   542  // StructExcept validates all fields except the ones passed in.
   543  // Fields may be provided in a namespaced fashion relative to the  struct provided
   544  // i.e. NestedStruct.Field or NestedArrayField[0].Struct.Name
   545  //
   546  // It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
   547  // You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
   548  func (v *Validate) StructExcept(s interface{}, fields ...string) error {
   549  	return v.StructExceptCtx(context.Background(), s, fields...)
   550  }
   551  
   552  // StructExceptCtx validates all fields except the ones passed in and allows passing of contextual
   553  // validation information via context.Context
   554  // Fields may be provided in a namespaced fashion relative to the  struct provided
   555  // i.e. NestedStruct.Field or NestedArrayField[0].Struct.Name
   556  //
   557  // It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
   558  // You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
   559  func (v *Validate) StructExceptCtx(ctx context.Context, s interface{}, fields ...string) (err error) {
   560  	val := reflect.ValueOf(s)
   561  	top := val
   562  
   563  	if val.Kind() == reflect.Ptr && !val.IsNil() {
   564  		val = val.Elem()
   565  	}
   566  
   567  	if val.Kind() != reflect.Struct || val.Type().ConvertibleTo(timeType) {
   568  		return &InvalidValidationError{Type: reflect.TypeOf(s)}
   569  	}
   570  
   571  	// good to validate
   572  	vd := v.pool.Get().(*validate)
   573  	vd.top = top
   574  	vd.isPartial = true
   575  	vd.ffn = nil
   576  	vd.hasExcludes = true
   577  	vd.includeExclude = make(map[string]struct{})
   578  
   579  	typ := val.Type()
   580  	name := typ.Name()
   581  
   582  	for _, key := range fields {
   583  
   584  		vd.misc = vd.misc[0:0]
   585  
   586  		if len(name) > 0 {
   587  			vd.misc = append(vd.misc, name...)
   588  			vd.misc = append(vd.misc, '.')
   589  		}
   590  
   591  		vd.misc = append(vd.misc, key...)
   592  		vd.includeExclude[string(vd.misc)] = struct{}{}
   593  	}
   594  
   595  	vd.validateStruct(ctx, top, val, typ, vd.ns[0:0], vd.actualNs[0:0], nil)
   596  
   597  	if len(vd.errs) > 0 {
   598  		err = vd.errs
   599  		vd.errs = nil
   600  	}
   601  
   602  	v.pool.Put(vd)
   603  
   604  	return
   605  }
   606  
   607  // Var validates a single variable using tag style validation.
   608  // eg.
   609  // var i int
   610  // validate.Var(i, "gt=1,lt=10")
   611  //
   612  // WARNING: a struct can be passed for validation eg. time.Time is a struct or
   613  // if you have a custom type and have registered a custom type handler, so must
   614  // allow it; however unforeseen validations will occur if trying to validate a
   615  // struct that is meant to be passed to 'validate.Struct'
   616  //
   617  // It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
   618  // You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
   619  // validate Array, Slice and maps fields which may contain more than one error
   620  func (v *Validate) Var(field interface{}, tag string) error {
   621  	return v.VarCtx(context.Background(), field, tag)
   622  }
   623  
   624  // VarCtx validates a single variable using tag style validation and allows passing of contextual
   625  // validation information via context.Context.
   626  // eg.
   627  // var i int
   628  // validate.Var(i, "gt=1,lt=10")
   629  //
   630  // WARNING: a struct can be passed for validation eg. time.Time is a struct or
   631  // if you have a custom type and have registered a custom type handler, so must
   632  // allow it; however unforeseen validations will occur if trying to validate a
   633  // struct that is meant to be passed to 'validate.Struct'
   634  //
   635  // It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
   636  // You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
   637  // validate Array, Slice and maps fields which may contain more than one error
   638  func (v *Validate) VarCtx(ctx context.Context, field interface{}, tag string) (err error) {
   639  	if len(tag) == 0 || tag == skipValidationTag {
   640  		return nil
   641  	}
   642  
   643  	ctag := v.fetchCacheTag(tag)
   644  
   645  	val := reflect.ValueOf(field)
   646  	vd := v.pool.Get().(*validate)
   647  	vd.top = val
   648  	vd.isPartial = false
   649  	vd.traverseField(ctx, val, val, vd.ns[0:0], vd.actualNs[0:0], defaultCField, ctag)
   650  
   651  	if len(vd.errs) > 0 {
   652  		err = vd.errs
   653  		vd.errs = nil
   654  	}
   655  	v.pool.Put(vd)
   656  	return
   657  }
   658  
   659  // VarWithValue validates a single variable, against another variable/field's value using tag style validation
   660  // eg.
   661  // s1 := "abcd"
   662  // s2 := "abcd"
   663  // validate.VarWithValue(s1, s2, "eqcsfield") // returns true
   664  //
   665  // WARNING: a struct can be passed for validation eg. time.Time is a struct or
   666  // if you have a custom type and have registered a custom type handler, so must
   667  // allow it; however unforeseen validations will occur if trying to validate a
   668  // struct that is meant to be passed to 'validate.Struct'
   669  //
   670  // It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
   671  // You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
   672  // validate Array, Slice and maps fields which may contain more than one error
   673  func (v *Validate) VarWithValue(field interface{}, other interface{}, tag string) error {
   674  	return v.VarWithValueCtx(context.Background(), field, other, tag)
   675  }
   676  
   677  // VarWithValueCtx validates a single variable, against another variable/field's value using tag style validation and
   678  // allows passing of contextual validation validation information via context.Context.
   679  // eg.
   680  // s1 := "abcd"
   681  // s2 := "abcd"
   682  // validate.VarWithValue(s1, s2, "eqcsfield") // returns true
   683  //
   684  // WARNING: a struct can be passed for validation eg. time.Time is a struct or
   685  // if you have a custom type and have registered a custom type handler, so must
   686  // allow it; however unforeseen validations will occur if trying to validate a
   687  // struct that is meant to be passed to 'validate.Struct'
   688  //
   689  // It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
   690  // You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
   691  // validate Array, Slice and maps fields which may contain more than one error
   692  func (v *Validate) VarWithValueCtx(ctx context.Context, field interface{}, other interface{}, tag string) (err error) {
   693  	if len(tag) == 0 || tag == skipValidationTag {
   694  		return nil
   695  	}
   696  	ctag := v.fetchCacheTag(tag)
   697  	otherVal := reflect.ValueOf(other)
   698  	vd := v.pool.Get().(*validate)
   699  	vd.top = otherVal
   700  	vd.isPartial = false
   701  	vd.traverseField(ctx, otherVal, reflect.ValueOf(field), vd.ns[0:0], vd.actualNs[0:0], defaultCField, ctag)
   702  
   703  	if len(vd.errs) > 0 {
   704  		err = vd.errs
   705  		vd.errs = nil
   706  	}
   707  	v.pool.Put(vd)
   708  	return
   709  }
   710  

View as plain text