podman

Форк
0
709 строк · 23.8 Кб
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

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.