Codebase list golang-github-go-playground-validator-v10 / v9.5.0
Add contextual validation support via context.Context (#296) * Add contextual validation support via context.Context Added: - RegisterValidationCtx - RegisterStructValidationCtx - StructCtx - StructFilteredCtx - StructPartialCtx - StructExceptCtx - VarCtx - VarWithValueCtx Dean Karn authored 6 years ago GitHub committed 6 years ago
7 changed file(s) with 260 addition(s) and 105 deletion(s). Raw diff Collapse all Expand all
6464
6565 Benchmarks
6666 ------
67 ###### Run on i5-7600 16 GB DDR4-2400 using Go version go1.8 linux/amd64
67 ###### Run on Dell XPS 15 i7-7700HQ 32GB Go version go1.8.3 linux/amd64
6868 ```go
69 BenchmarkFieldSuccess-4 20000000 74.3 ns/op 0 B/op 0 allocs/op
70 BenchmarkFieldSuccessParallel-4 50000000 31.5 ns/op 0 B/op 0 allocs/op
71 BenchmarkFieldFailure-4 3000000 556 ns/op 208 B/op 4 allocs/op
72 BenchmarkFieldFailureParallel-4 20000000 88.7 ns/op 208 B/op 4 allocs/op
73 BenchmarkFieldDiveSuccess-4 2000000 630 ns/op 201 B/op 11 allocs/op
74 BenchmarkFieldDiveSuccessParallel-4 10000000 173 ns/op 201 B/op 11 allocs/op
75 BenchmarkFieldDiveFailure-4 1000000 1350 ns/op 412 B/op 16 allocs/op
76 BenchmarkFieldDiveFailureParallel-4 5000000 250 ns/op 412 B/op 16 allocs/op
77 BenchmarkFieldCustomTypeSuccess-4 10000000 202 ns/op 32 B/op 2 allocs/op
78 BenchmarkFieldCustomTypeSuccessParallel-4 20000000 63.5 ns/op 32 B/op 2 allocs/op
79 BenchmarkFieldCustomTypeFailure-4 5000000 568 ns/op 208 B/op 4 allocs/op
80 BenchmarkFieldCustomTypeFailureParallel-4 20000000 87.5 ns/op 208 B/op 4 allocs/op
81 BenchmarkFieldOrTagSuccess-4 2000000 703 ns/op 16 B/op 1 allocs/op
82 BenchmarkFieldOrTagSuccessParallel-4 3000000 447 ns/op 16 B/op 1 allocs/op
83 BenchmarkFieldOrTagFailure-4 3000000 604 ns/op 224 B/op 5 allocs/op
84 BenchmarkFieldOrTagFailureParallel-4 5000000 353 ns/op 224 B/op 5 allocs/op
85 BenchmarkStructLevelValidationSuccess-4 10000000 190 ns/op 32 B/op 2 allocs/op
86 BenchmarkStructLevelValidationSuccessParallel-4 30000000 59.9 ns/op 32 B/op 2 allocs/op
87 BenchmarkStructLevelValidationFailure-4 2000000 705 ns/op 304 B/op 8 allocs/op
88 BenchmarkStructLevelValidationFailureParallel-4 10000000 146 ns/op 304 B/op 8 allocs/op
89 BenchmarkStructSimpleCustomTypeSuccess-4 5000000 361 ns/op 32 B/op 2 allocs/op
90 BenchmarkStructSimpleCustomTypeSuccessParallel-4 20000000 101 ns/op 32 B/op 2 allocs/op
91 BenchmarkStructSimpleCustomTypeFailure-4 1000000 1210 ns/op 424 B/op 9 allocs/op
92 BenchmarkStructSimpleCustomTypeFailureParallel-4 10000000 196 ns/op 440 B/op 10 allocs/op
93 BenchmarkStructFilteredSuccess-4 2000000 757 ns/op 288 B/op 9 allocs/op
94 BenchmarkStructFilteredSuccessParallel-4 10000000 167 ns/op 288 B/op 9 allocs/op
95 BenchmarkStructFilteredFailure-4 3000000 619 ns/op 256 B/op 7 allocs/op
96 BenchmarkStructFilteredFailureParallel-4 10000000 134 ns/op 256 B/op 7 allocs/op
97 BenchmarkStructPartialSuccess-4 2000000 687 ns/op 256 B/op 6 allocs/op
98 BenchmarkStructPartialSuccessParallel-4 10000000 159 ns/op 256 B/op 6 allocs/op
99 BenchmarkStructPartialFailure-4 1000000 1281 ns/op 480 B/op 11 allocs/op
100 BenchmarkStructPartialFailureParallel-4 10000000 218 ns/op 480 B/op 11 allocs/op
101 BenchmarkStructExceptSuccess-4 1000000 1041 ns/op 496 B/op 12 allocs/op
102 BenchmarkStructExceptSuccessParallel-4 10000000 140 ns/op 240 B/op 5 allocs/op
103 BenchmarkStructExceptFailure-4 1000000 1014 ns/op 464 B/op 10 allocs/op
104 BenchmarkStructExceptFailureParallel-4 10000000 201 ns/op 464 B/op 10 allocs/op
105 BenchmarkStructSimpleCrossFieldSuccess-4 5000000 364 ns/op 72 B/op 3 allocs/op
106 BenchmarkStructSimpleCrossFieldSuccessParallel-4 20000000 103 ns/op 72 B/op 3 allocs/op
107 BenchmarkStructSimpleCrossFieldFailure-4 2000000 789 ns/op 304 B/op 8 allocs/op
108 BenchmarkStructSimpleCrossFieldFailureParallel-4 10000000 174 ns/op 304 B/op 8 allocs/op
109 BenchmarkStructSimpleCrossStructCrossFieldSuccess-4 3000000 522 ns/op 80 B/op 4 allocs/op
110 BenchmarkStructSimpleCrossStructCrossFieldSuccessParallel-4 10000000 146 ns/op 80 B/op 4 allocs/op
111 BenchmarkStructSimpleCrossStructCrossFieldFailure-4 2000000 879 ns/op 320 B/op 9 allocs/op
112 BenchmarkStructSimpleCrossStructCrossFieldFailureParallel-4 10000000 225 ns/op 320 B/op 9 allocs/op
113 BenchmarkStructSimpleSuccess-4 10000000 223 ns/op 0 B/op 0 allocs/op
114 BenchmarkStructSimpleSuccessParallel-4 20000000 63.3 ns/op 0 B/op 0 allocs/op
115 BenchmarkStructSimpleFailure-4 2000000 1097 ns/op 424 B/op 9 allocs/op
116 BenchmarkStructSimpleFailureParallel-4 10000000 182 ns/op 424 B/op 9 allocs/op
117 BenchmarkStructComplexSuccess-4 1000000 1362 ns/op 128 B/op 8 allocs/op
118 BenchmarkStructComplexSuccessParallel-4 5000000 359 ns/op 128 B/op 8 allocs/op
119 BenchmarkStructComplexFailure-4 300000 6446 ns/op 3040 B/op 53 allocs/op
120 BenchmarkStructComplexFailureParallel-4 1000000 1203 ns/op 3040 B/op 53 allocs/op
69 go test -run=XXX -bench=. -benchmem=true
70 BenchmarkFieldSuccess-8 20000000 88.3 ns/op 0 B/op 0 allocs/op
71 BenchmarkFieldSuccessParallel-8 50000000 30.4 ns/op 0 B/op 0 allocs/op
72 BenchmarkFieldFailure-8 3000000 428 ns/op 208 B/op 4 allocs/op
73 BenchmarkFieldFailureParallel-8 20000000 96.0 ns/op 208 B/op 4 allocs/op
74 BenchmarkFieldDiveSuccess-8 2000000 695 ns/op 201 B/op 11 allocs/op
75 BenchmarkFieldDiveSuccessParallel-8 10000000 205 ns/op 201 B/op 11 allocs/op
76 BenchmarkFieldDiveFailure-8 1000000 1083 ns/op 412 B/op 16 allocs/op
77 BenchmarkFieldDiveFailureParallel-8 5000000 278 ns/op 413 B/op 16 allocs/op
78 BenchmarkFieldCustomTypeSuccess-8 10000000 229 ns/op 32 B/op 2 allocs/op
79 BenchmarkFieldCustomTypeSuccessParallel-8 20000000 72.4 ns/op 32 B/op 2 allocs/op
80 BenchmarkFieldCustomTypeFailure-8 5000000 377 ns/op 208 B/op 4 allocs/op
81 BenchmarkFieldCustomTypeFailureParallel-8 20000000 93.0 ns/op 208 B/op 4 allocs/op
82 BenchmarkFieldOrTagSuccess-8 2000000 767 ns/op 16 B/op 1 allocs/op
83 BenchmarkFieldOrTagSuccessParallel-8 3000000 425 ns/op 16 B/op 1 allocs/op
84 BenchmarkFieldOrTagFailure-8 2000000 548 ns/op 224 B/op 5 allocs/op
85 BenchmarkFieldOrTagFailureParallel-8 3000000 411 ns/op 224 B/op 5 allocs/op
86 BenchmarkStructLevelValidationSuccess-8 10000000 219 ns/op 32 B/op 2 allocs/op
87 BenchmarkStructLevelValidationSuccessParallel-8 20000000 69.2 ns/op 32 B/op 2 allocs/op
88 BenchmarkStructLevelValidationFailure-8 2000000 628 ns/op 304 B/op 8 allocs/op
89 BenchmarkStructLevelValidationFailureParallel-8 10000000 165 ns/op 304 B/op 8 allocs/op
90 BenchmarkStructSimpleCustomTypeSuccess-8 3000000 411 ns/op 32 B/op 2 allocs/op
91 BenchmarkStructSimpleCustomTypeSuccessParallel-8 10000000 122 ns/op 32 B/op 2 allocs/op
92 BenchmarkStructSimpleCustomTypeFailure-8 1000000 1022 ns/op 424 B/op 9 allocs/op
93 BenchmarkStructSimpleCustomTypeFailureParallel-8 10000000 228 ns/op 440 B/op 10 allocs/op
94 BenchmarkStructFilteredSuccess-8 2000000 737 ns/op 288 B/op 9 allocs/op
95 BenchmarkStructFilteredSuccessParallel-8 10000000 192 ns/op 288 B/op 9 allocs/op
96 BenchmarkStructFilteredFailure-8 3000000 583 ns/op 256 B/op 7 allocs/op
97 BenchmarkStructFilteredFailureParallel-8 10000000 152 ns/op 256 B/op 7 allocs/op
98 BenchmarkStructPartialSuccess-8 2000000 731 ns/op 256 B/op 6 allocs/op
99 BenchmarkStructPartialSuccessParallel-8 10000000 173 ns/op 256 B/op 6 allocs/op
100 BenchmarkStructPartialFailure-8 1000000 1164 ns/op 480 B/op 11 allocs/op
101 BenchmarkStructPartialFailureParallel-8 5000000 253 ns/op 480 B/op 11 allocs/op
102 BenchmarkStructExceptSuccess-8 1000000 1337 ns/op 496 B/op 12 allocs/op
103 BenchmarkStructExceptSuccessParallel-8 10000000 153 ns/op 240 B/op 5 allocs/op
104 BenchmarkStructExceptFailure-8 2000000 954 ns/op 464 B/op 10 allocs/op
105 BenchmarkStructExceptFailureParallel-8 5000000 234 ns/op 464 B/op 10 allocs/op
106 BenchmarkStructSimpleCrossFieldSuccess-8 3000000 420 ns/op 72 B/op 3 allocs/op
107 BenchmarkStructSimpleCrossFieldSuccessParallel-8 10000000 125 ns/op 72 B/op 3 allocs/op
108 BenchmarkStructSimpleCrossFieldFailure-8 2000000 790 ns/op 304 B/op 8 allocs/op
109 BenchmarkStructSimpleCrossFieldFailureParallel-8 10000000 205 ns/op 304 B/op 8 allocs/op
110 BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 2000000 611 ns/op 80 B/op 4 allocs/op
111 BenchmarkStructSimpleCrossStructCrossFieldSuccessParallel-8 10000000 172 ns/op 80 B/op 4 allocs/op
112 BenchmarkStructSimpleCrossStructCrossFieldFailure-8 1000000 1112 ns/op 320 B/op 9 allocs/op
113 BenchmarkStructSimpleCrossStructCrossFieldFailureParallel-8 5000000 258 ns/op 320 B/op 9 allocs/op
114 BenchmarkStructSimpleSuccess-8 5000000 263 ns/op 0 B/op 0 allocs/op
115 BenchmarkStructSimpleSuccessParallel-8 20000000 83.1 ns/op 0 B/op 0 allocs/op
116 BenchmarkStructSimpleFailure-8 2000000 964 ns/op 424 B/op 9 allocs/op
117 BenchmarkStructSimpleFailureParallel-8 10000000 212 ns/op 424 B/op 9 allocs/op
118 BenchmarkStructComplexSuccess-8 1000000 1504 ns/op 128 B/op 8 allocs/op
119 BenchmarkStructComplexSuccessParallel-8 3000000 427 ns/op 128 B/op 8 allocs/op
120 BenchmarkStructComplexFailure-8 300000 7585 ns/op 3041 B/op 53 allocs/op
121 BenchmarkStructComplexFailureParallel-8 1000000 1387 ns/op 3041 B/op 53 allocs/op
121122 ```
122123
123124 Complementary Software
00 package validator
11
22 import (
3 "context"
34 "fmt"
45 "net"
56 "net/url"
910 "unicode/utf8"
1011 )
1112
12 // Func accepts all values needed for file and cross field validation
13 // fl = FieldLevel validation helper
14 // field = field value for validation
15 // fieldType = fields
16 // param = parameter used in validation i.e. gt=0 param would be 0
13 // Func accepts a FieldLevel interface for all validation needs
1714 type Func func(fl FieldLevel) bool
15
16 // FuncCtx accepts a context.Context and FieldLevel interface for all validation needs
17 type FuncCtx func(ctx context.Context, fl FieldLevel) bool
18
19 // wrapFunc wraps noramal Func makes it compatible with FuncCtx
20 func wrapFunc(fn Func) FuncCtx {
21 if fn == nil {
22 return nil // be sure not to wrap a bad function.
23 }
24 return func(ctx context.Context, fl FieldLevel) bool {
25 return fn(fl)
26 }
27 }
1828
1929 var (
2030 restrictedTags = map[string]struct{}{
7070 type cStruct struct {
7171 name string
7272 fields []*cField
73 fn StructLevelFunc
73 fn StructLevelFuncCtx
7474 }
7575
7676 type cField struct {
8989 hasAlias bool
9090 typeof tagType
9191 hasTag bool
92 fn Func
92 fn FuncCtx
9393 next *cTag
9494 }
9595
00 package validator
11
2 import "reflect"
2 import (
3 "context"
4 "reflect"
5 )
36
47 // StructLevelFunc accepts all values needed for struct level validation
58 type StructLevelFunc func(sl StructLevel)
9
10 // StructLevelFuncCtx accepts all values needed for struct level validation
11 // but also allows passing of contextual validation information vi context.Context.
12 type StructLevelFuncCtx func(ctx context.Context, sl StructLevel)
13
14 // wrapStructLevelFunc wraps noramal StructLevelFunc makes it compatible with StructLevelFuncCtx
15 func wrapStructLevelFunc(fn StructLevelFunc) StructLevelFuncCtx {
16 return func(ctx context.Context, sl StructLevel) {
17 fn(sl)
18 }
19 }
620
721 // StructLevel contains all the information and helper functions
822 // to validate a struct
2034 Parent() reflect.Value
2135
2236 // returns the current struct.
23 // this is not needed when implementing 'Validatable' interface,
24 // only when a StructLevel is registered
2537 Current() reflect.Value
2638
2739 // ExtractType gets the actual underlying type of field value.
00 package validator
11
22 import (
3 "context"
34 "fmt"
45 "reflect"
56 "strconv"
3334 }
3435
3536 // parent and current will be the same the first run of validateStruct
36 func (v *validate) validateStruct(parent reflect.Value, current reflect.Value, typ reflect.Type, ns []byte, structNs []byte, ct *cTag) {
37 func (v *validate) validateStruct(ctx context.Context, parent reflect.Value, current reflect.Value, typ reflect.Type, ns []byte, structNs []byte, ct *cTag) {
3738
3839 cs, ok := v.v.structCache.Get(typ)
3940 if !ok {
7778 }
7879 }
7980
80 v.traverseField(parent, current.Field(f.idx), ns, structNs, f, f.cTags)
81 v.traverseField(ctx, parent, current.Field(f.idx), ns, structNs, f, f.cTags)
8182 }
8283 }
8384
9192 v.ns = ns
9293 v.actualNs = structNs
9394
94 cs.fn(v)
95 cs.fn(ctx, v)
9596 }
9697 }
9798
9899 // traverseField validates any field, be it a struct or single field, ensures it's validity and passes it along to be validated via it's tag options
99 func (v *validate) traverseField(parent reflect.Value, current reflect.Value, ns []byte, structNs []byte, cf *cField, ct *cTag) {
100 func (v *validate) traverseField(ctx context.Context, parent reflect.Value, current reflect.Value, ns []byte, structNs []byte, cf *cField, ct *cTag) {
100101
101102 var typ reflect.Type
102103 var kind reflect.Kind
191192 structNs = append(append(structNs, cf.name...), '.')
192193 }
193194
194 v.validateStruct(current, current, typ, ns, structNs, ct)
195 v.validateStruct(ctx, current, current, typ, ns, structNs, ct)
195196 return
196197 }
197198 }
260261 reusableCF.altName = string(v.misc)
261262 }
262263
263 v.traverseField(parent, current.Index(i), ns, structNs, reusableCF, ct)
264 v.traverseField(ctx, parent, current.Index(i), ns, structNs, reusableCF, ct)
264265 }
265266
266267 case reflect.Map:
290291 reusableCF.altName = string(v.misc)
291292 }
292293
293 v.traverseField(parent, current.MapIndex(key), ns, structNs, reusableCF, ct)
294 v.traverseField(ctx, parent, current.MapIndex(key), ns, structNs, reusableCF, ct)
294295 }
295296
296297 default:
313314 v.cf = cf
314315 v.ct = ct
315316
316 if ct.fn(v) {
317 if ct.fn(ctx, v) {
317318
318319 // drain rest of the 'or' values, then continue or leave
319320 for {
406407 // v.ns = ns
407408 // v.actualNs = structNs
408409
409 if !ct.fn(v) {
410 if !ct.fn(ctx, v) {
410411
411412 v.str1 = string(append(ns, cf.altName...))
412413
00 package validator
11
22 import (
3 "context"
34 "errors"
45 "fmt"
56 "reflect"
5758 hasCustomFuncs bool
5859 hasTagNameFunc bool
5960 tagNameFunc TagNameFunc
60 structLevelFuncs map[reflect.Type]StructLevelFunc
61 structLevelFuncs map[reflect.Type]StructLevelFuncCtx
6162 customFuncs map[reflect.Type]CustomTypeFunc
6263 aliases map[string]string
63 validations map[string]Func
64 validations map[string]FuncCtx
6465 transTagFunc map[ut.Translator]map[string]TranslationFunc // map[<locale>]map[<tag>]TranslationFunc
6566 tagCache *tagCache
6667 structCache *structCache
7879 v := &Validate{
7980 tagName: defaultTagName,
8081 aliases: make(map[string]string, len(bakedInAliases)),
81 validations: make(map[string]Func, len(bakedInValidators)),
82 validations: make(map[string]FuncCtx, len(bakedInValidators)),
8283 tagCache: tc,
8384 structCache: sc,
8485 }
9192 // must copy validators for separate validations to be used in each instance
9293 for k, val := range bakedInValidators {
9394
94 // no need to error check here, baked in will alwaays be valid
95 v.registerValidation(k, val, true)
95 // no need to error check here, baked in will always be valid
96 v.registerValidation(k, wrapFunc(val), true)
9697 }
9798
9899 v.pool = &sync.Pool{
127128 // - if the key already exists, the previous validation function will be replaced.
128129 // - this method is not thread-safe it is intended that these all be registered prior to any validation
129130 func (v *Validate) RegisterValidation(tag string, fn Func) error {
131 return v.RegisterValidationCtx(tag, wrapFunc(fn))
132 }
133
134 // RegisterValidationCtx does the same as RegisterValidation on accepts a FuncCtx validation
135 // allowing context.Context validation support.
136 func (v *Validate) RegisterValidationCtx(tag string, fn FuncCtx) error {
130137 return v.registerValidation(tag, fn, false)
131138 }
132139
133 func (v *Validate) registerValidation(tag string, fn Func, bakedIn bool) error {
140 func (v *Validate) registerValidation(tag string, fn FuncCtx, bakedIn bool) error {
134141
135142 if len(tag) == 0 {
136143 return errors.New("Function Key cannot be empty")
176183 // a struct out of your control's validation to be overridden
177184 // - this method is not thread-safe it is intended that these all be registered prior to any validation
178185 func (v *Validate) RegisterStructValidation(fn StructLevelFunc, types ...interface{}) {
186 v.RegisterStructValidationCtx(wrapStructLevelFunc(fn), types...)
187 }
188
189 // RegisterStructValidationCtx registers a StructLevelFuncCtx against a number of types and allows passing
190 // of contextual validation information via context.Context.
191 // This is akin to implementing a 'Validatable' interface, but for structs for which
192 // you may not have access or rights to change.
193 //
194 // NOTES:
195 // - if this and the 'Validatable' interface are implemented the Struct Level takes precedence as to enable
196 // a struct out of your control's validation to be overridden
197 // - this method is not thread-safe it is intended that these all be registered prior to any validation
198 func (v *Validate) RegisterStructValidationCtx(fn StructLevelFuncCtx, types ...interface{}) {
179199
180200 if v.structLevelFuncs == nil {
181 v.structLevelFuncs = make(map[reflect.Type]StructLevelFunc)
201 v.structLevelFuncs = make(map[reflect.Type]StructLevelFuncCtx)
182202 }
183203
184204 for _, t := range types {
228248 //
229249 // It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
230250 // You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
231 func (v *Validate) Struct(s interface{}) (err error) {
251 func (v *Validate) Struct(s interface{}) error {
252 return v.StructCtx(context.Background(), s)
253 }
254
255 // StructCtx validates a structs exposed fields, and automatically validates nested structs, unless otherwise specified
256 // and also allows passing of context.Context for contextual validation information.
257 //
258 // It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
259 // You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
260 func (v *Validate) StructCtx(ctx context.Context, s interface{}) (err error) {
232261
233262 val := reflect.ValueOf(s)
234263 top := val
247276 vd.isPartial = false
248277 // vd.hasExcludes = false // only need to reset in StructPartial and StructExcept
249278
250 vd.validateStruct(top, val, val.Type(), vd.ns[0:0], vd.actualNs[0:0], nil)
279 vd.validateStruct(ctx, top, val, val.Type(), vd.ns[0:0], vd.actualNs[0:0], nil)
251280
252281 if len(vd.errs) > 0 {
253282 err = vd.errs
264293 //
265294 // It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
266295 // You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
267 func (v *Validate) StructFiltered(s interface{}, fn FilterFunc) (err error) {
268
296 func (v *Validate) StructFiltered(s interface{}, fn FilterFunc) error {
297 return v.StructFilteredCtx(context.Background(), s, fn)
298 }
299
300 // StructFilteredCtx validates a structs exposed fields, that pass the FilterFunc check and automatically validates
301 // nested structs, unless otherwise specified and also allows passing of contextual validation information via
302 // context.Context
303 //
304 // It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
305 // You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
306 func (v *Validate) StructFilteredCtx(ctx context.Context, s interface{}, fn FilterFunc) (err error) {
269307 val := reflect.ValueOf(s)
270308 top := val
271309
284322 vd.ffn = fn
285323 // vd.hasExcludes = false // only need to reset in StructPartial and StructExcept
286324
287 vd.validateStruct(top, val, val.Type(), vd.ns[0:0], vd.actualNs[0:0], nil)
325 vd.validateStruct(context.Background(), top, val, val.Type(), vd.ns[0:0], vd.actualNs[0:0], nil)
288326
289327 if len(vd.errs) > 0 {
290328 err = vd.errs
302340 //
303341 // It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
304342 // You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
305 func (v *Validate) StructPartial(s interface{}, fields ...string) (err error) {
306
343 func (v *Validate) StructPartial(s interface{}, fields ...string) error {
344 return v.StructPartialCtx(context.Background(), s, fields...)
345 }
346
347 // StructPartialCtx validates the fields passed in only, ignoring all others and allows passing of contextual
348 // validation validation information via context.Context
349 // Fields may be provided in a namespaced fashion relative to the struct provided
350 // eg. NestedStruct.Field or NestedArrayField[0].Struct.Name
351 //
352 // It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
353 // You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
354 func (v *Validate) StructPartialCtx(ctx context.Context, s interface{}, fields ...string) (err error) {
307355 val := reflect.ValueOf(s)
308356 top := val
309357
363411 }
364412 }
365413
366 vd.validateStruct(top, val, typ, vd.ns[0:0], vd.actualNs[0:0], nil)
414 vd.validateStruct(ctx, top, val, typ, vd.ns[0:0], vd.actualNs[0:0], nil)
367415
368416 if len(vd.errs) > 0 {
369417 err = vd.errs
381429 //
382430 // It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
383431 // You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
384 func (v *Validate) StructExcept(s interface{}, fields ...string) (err error) {
385
432 func (v *Validate) StructExcept(s interface{}, fields ...string) error {
433 return v.StructExceptCtx(context.Background(), s, fields...)
434 }
435
436 // StructExceptCtx validates all fields except the ones passed in and allows passing of contextual
437 // validation validation information via context.Context
438 // Fields may be provided in a namespaced fashion relative to the struct provided
439 // i.e. NestedStruct.Field or NestedArrayField[0].Struct.Name
440 //
441 // It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
442 // You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
443 func (v *Validate) StructExceptCtx(ctx context.Context, s interface{}, fields ...string) (err error) {
386444 val := reflect.ValueOf(s)
387445 top := val
388446
418476 vd.includeExclude[string(vd.misc)] = struct{}{}
419477 }
420478
421 vd.validateStruct(top, val, typ, vd.ns[0:0], vd.actualNs[0:0], nil)
479 vd.validateStruct(ctx, top, val, typ, vd.ns[0:0], vd.actualNs[0:0], nil)
422480
423481 if len(vd.errs) > 0 {
424482 err = vd.errs
442500 // It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
443501 // You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
444502 // validate Array, Slice and maps fields which may contain more than one error
445 func (v *Validate) Var(field interface{}, tag string) (err error) {
446
503 func (v *Validate) Var(field interface{}, tag string) error {
504 return v.VarCtx(context.Background(), field, tag)
505 }
506
507 // VarCtx validates a single variable using tag style validation and allows passing of contextual
508 // validation validation information via context.Context.
509 // eg.
510 // var i int
511 // validate.Var(i, "gt=1,lt=10")
512 //
513 // WARNING: a struct can be passed for validation eg. time.Time is a struct or if you have a custom type and have registered
514 // a custom type handler, so must allow it; however unforseen validations will occur if trying to validate a struct
515 // that is meant to be passed to 'validate.Struct'
516 //
517 // It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
518 // You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
519 // validate Array, Slice and maps fields which may contain more than one error
520 func (v *Validate) VarCtx(ctx context.Context, field interface{}, tag string) (err error) {
447521 if len(tag) == 0 || tag == skipValidationTag {
448522 return nil
449523 }
469543 vd.top = val
470544 vd.isPartial = false
471545
472 vd.traverseField(val, val, vd.ns[0:0], vd.actualNs[0:0], defaultCField, ctag)
546 vd.traverseField(ctx, val, val, vd.ns[0:0], vd.actualNs[0:0], defaultCField, ctag)
473547
474548 if len(vd.errs) > 0 {
475549 err = vd.errs
494568 // It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
495569 // You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
496570 // validate Array, Slice and maps fields which may contain more than one error
497 func (v *Validate) VarWithValue(field interface{}, other interface{}, tag string) (err error) {
498
571 func (v *Validate) VarWithValue(field interface{}, other interface{}, tag string) error {
572 return v.VarWithValueCtx(context.Background(), field, other, tag)
573 }
574
575 // VarWithValueCtx validates a single variable, against another variable/field's value using tag style validation and
576 // allows passing of contextual validation validation information via context.Context.
577 // eg.
578 // s1 := "abcd"
579 // s2 := "abcd"
580 // validate.VarWithValue(s1, s2, "eqcsfield") // returns true
581 //
582 // WARNING: a struct can be passed for validation eg. time.Time is a struct or if you have a custom type and have registered
583 // a custom type handler, so must allow it; however unforseen validations will occur if trying to validate a struct
584 // that is meant to be passed to 'validate.Struct'
585 //
586 // It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
587 // You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
588 // validate Array, Slice and maps fields which may contain more than one error
589 func (v *Validate) VarWithValueCtx(ctx context.Context, field interface{}, other interface{}, tag string) (err error) {
499590 if len(tag) == 0 || tag == skipValidationTag {
500591 return nil
501592 }
521612 vd.top = otherVal
522613 vd.isPartial = false
523614
524 vd.traverseField(otherVal, reflect.ValueOf(field), vd.ns[0:0], vd.actualNs[0:0], defaultCField, ctag)
615 vd.traverseField(ctx, otherVal, reflect.ValueOf(field), vd.ns[0:0], vd.actualNs[0:0], defaultCField, ctag)
525616
526617 if len(vd.errs) > 0 {
527618 err = vd.errs
11
22 import (
33 "bytes"
4 "context"
45 "database/sql"
56 "database/sql/driver"
67 "encoding/json"
775776
776777 // the following should all return no errors as everything is valid in
777778 // the default state
778 errs := validate.StructPartial(tPartial, p1...)
779 errs := validate.StructPartialCtx(context.Background(), tPartial, p1...)
779780 Equal(t, errs, nil)
780781
781782 errs = validate.StructPartial(tPartial, p2...)
785786 errs = validate.StructPartial(tPartial.SubSlice[0], p3...)
786787 Equal(t, errs, nil)
787788
788 errs = validate.StructExcept(tPartial, p1...)
789 errs = validate.StructExceptCtx(context.Background(), tPartial, p1...)
789790 Equal(t, errs, nil)
790791
791792 errs = validate.StructExcept(tPartial, p2...)
990991 AssertError(t, errs, "Test.Float", "Test.Float", "Float", "Float", "ltecsfield")
991992 AssertError(t, errs, "Test.Array", "Test.Array", "Array", "Array", "ltecsfield")
992993
993 errs = validate.VarWithValue(1, "", "ltecsfield")
994 errs = validate.VarWithValueCtx(context.Background(), 1, "", "ltecsfield")
994995 NotEqual(t, errs, nil)
995996 AssertError(t, errs, "", "", "", "", "ltecsfield")
996997
18261827 AssertError(t, errs, "", "", "", "", "required")
18271828
18281829 val.Name = "Valid Name"
1829 errs = validate.Var(val, "required")
1830 errs = validate.VarCtx(context.Background(), val, "required")
18301831 Equal(t, errs, nil)
18311832
18321833 val.Name = "errorme"
51265127 return true
51275128 }
51285129
5130 fnCtx := func(ctx context.Context, fl FieldLevel) bool {
5131 return true
5132 }
5133
51295134 validate := New()
51305135
51315136 errs := validate.RegisterValidation("new", fn)
51385143 NotEqual(t, errs, nil)
51395144
51405145 errs = validate.RegisterValidation("new", fn)
5146 Equal(t, errs, nil)
5147
5148 errs = validate.RegisterValidationCtx("new", fnCtx)
51415149 Equal(t, errs, nil)
51425150
51435151 PanicMatches(t, func() { validate.RegisterValidation("dive", fn) }, "Tag 'dive' either contains restricted characters or is the same as a restricted tag needed for normal operation")
52375245 errs = validate.Var(tm, "gt")
52385246 Equal(t, errs, nil)
52395247
5240 t2 := time.Now().UTC()
5248 t2 := time.Now().UTC().Add(-time.Hour)
52415249
52425250 errs = validate.Var(t2, "gt")
52435251 NotEqual(t, errs, nil)
52755283 errs := validate.Var(t1, "gte")
52765284 Equal(t, errs, nil)
52775285
5278 t2 := time.Now().UTC()
5286 t2 := time.Now().UTC().Add(-time.Hour)
52795287
52805288 errs = validate.Var(t2, "gte")
52815289 NotEqual(t, errs, nil)
53225330 i := true
53235331 PanicMatches(t, func() { validate.Var(i, "lt") }, "Bad field type bool")
53245332
5325 t1 := time.Now().UTC()
5333 t1 := time.Now().UTC().Add(-time.Hour)
53265334
53275335 errs = validate.Var(t1, "lt")
53285336 Equal(t, errs, nil)
53615369 i := true
53625370 PanicMatches(t, func() { validate.Var(i, "lte") }, "Bad field type bool")
53635371
5364 t1 := time.Now().UTC()
5372 t1 := time.Now().UTC().Add(-time.Hour)
53655373
53665374 errs := validate.Var(t1, "lte")
53675375 Equal(t, errs, nil)
66946702
66956703 // the following should all return no errors as everything is valid in
66966704 // the default state
6697 errs := validate.StructFiltered(tPartial, p1)
6705 errs := validate.StructFilteredCtx(context.Background(), tPartial, p1)
66986706 Equal(t, errs, nil)
66996707
67006708 errs = validate.StructFiltered(tPartial, p2)
70787086 Equal(t, res5, "json5")
70797087 Equal(t, alt5, "Map2")
70807088 }
7089
7090 func TestValidateStructRegisterCtx(t *testing.T) {
7091
7092 var ctxVal string
7093
7094 fnCtx := func(ctx context.Context, fl FieldLevel) bool {
7095 ctxVal = ctx.Value(&ctxVal).(string)
7096 return true
7097 }
7098
7099 var ctxSlVal string
7100 slFn := func(ctx context.Context, sl StructLevel) {
7101 ctxSlVal = ctx.Value(&ctxSlVal).(string)
7102 }
7103
7104 type Test struct {
7105 Field string `validate:"val"`
7106 }
7107
7108 var tst Test
7109
7110 validate := New()
7111 validate.RegisterValidationCtx("val", fnCtx)
7112 validate.RegisterStructValidationCtx(slFn, Test{})
7113
7114 ctx := context.WithValue(context.Background(), &ctxVal, "testval")
7115 ctx = context.WithValue(ctx, &ctxSlVal, "slVal")
7116 errs := validate.StructCtx(ctx, tst)
7117 Equal(t, errs, nil)
7118 Equal(t, ctxVal, "testval")
7119 Equal(t, ctxSlVal, "slVal")
7120 }