@@ -306,7 +306,7 @@ func (v *Validate) structRecursive(top interface{}, current interface{}, s inter
306306
307307 cField .isTime = true
308308
309- if fieldError := v .fieldWithNameAndValue (top , current , valueField .Interface (), cField .tag , cField .name , cField ); fieldError != nil {
309+ if fieldError := v .fieldWithNameAndValue (top , current , valueField .Interface (), cField .tag , cField .name , false , cField ); fieldError != nil {
310310 validationErrors .Errors [fieldError .Field ] = fieldError
311311 // free up memory reference
312312 fieldError = nil
@@ -331,7 +331,7 @@ func (v *Validate) structRecursive(top interface{}, current interface{}, s inter
331331
332332 default :
333333
334- if fieldError := v .fieldWithNameAndValue (top , current , valueField .Interface (), cField .tag , cField .name , cField ); fieldError != nil {
334+ if fieldError := v .fieldWithNameAndValue (top , current , valueField .Interface (), cField .tag , cField .name , false , cField ); fieldError != nil {
335335 validationErrors .Errors [fieldError .Field ] = fieldError
336336 // free up memory reference
337337 fieldError = nil
@@ -361,14 +361,17 @@ func (v *Validate) Field(f interface{}, tag string) *FieldError {
361361// FieldWithValue allows validation of a single field, possibly even against another fields value, still using tag style validation to check multiple errors
362362func (v * Validate ) FieldWithValue (val interface {}, f interface {}, tag string ) * FieldError {
363363
364- return v .fieldWithNameAndValue (nil , val , f , tag , "" , nil )
364+ return v .fieldWithNameAndValue (nil , val , f , tag , "" , true , nil )
365365}
366366
367- func (v * Validate ) fieldWithNameAndValue (val interface {}, current interface {}, f interface {}, tag string , name string , cacheField * cachedField ) * FieldError {
367+ var cacheFields = map [string ][]* cacheTags {}
368+
369+ func (v * Validate ) fieldWithNameAndValue (val interface {}, current interface {}, f interface {}, tag string , name string , isSingleField bool , cacheField * cachedField ) * FieldError {
368370
369371 // var fieldType reflect.Type
370372 // var fieldKind reflect.Kind
371373 var cField * cachedField
374+ var ok bool
372375
373376 // This is a double check if coming from validate.Struct but need to be here in case function is called directly
374377 if tag == noValidationTag {
@@ -382,14 +385,30 @@ func (v *Validate) fieldWithNameAndValue(val interface{}, current interface{}, f
382385 if cacheField == nil {
383386 valueField := reflect .ValueOf (f )
384387
385- cField = & cachedField {name : name , kind : valueField .Kind ()}
388+ if valueField .Kind () == reflect .Ptr && ! valueField .IsNil () {
389+ // valueField = valueField.Elem()
390+ // f = valueField.Interface()
391+ return v .fieldWithNameAndValue (val , current , valueField .Elem ().Interface (), tag , name , isSingleField , cacheField )
392+ }
393+
394+ // if !ok {
395+ // cacheFields[cField.tag] = cField
396+
397+ // valueField = valueField.Elem()
398+
399+ cField = & cachedField {name : name , kind : valueField .Kind (), tag : tag , typ : valueField .Type ()}
386400 // fieldKind = valueField.Kind()
387401
388- if cField .kind == reflect .Ptr && ! valueField .IsNil () {
389- return v .fieldWithNameAndValue (val , current , valueField .Elem ().Interface (), tag , name , cacheField )
390- }
402+ // if cField.kind == reflect.Ptr && !valueField.IsNil() {
403+ // return v.fieldWithNameAndValue(val, current, valueField.Elem().Interface(), tag, name, isSingleField, cacheField)
404+ // }
405+
406+ // cField.typ = valueField.Type()
407+ // cField.tag = tag
391408
392- cField .typ = valueField .Type ()
409+ // if isSingleField {
410+ // cacheFields[cField.tag] = cField
411+ // }
393412 // cField.tags = make([][]string, 0)
394413 // fieldType = valueField.Type()
395414 // for _, t := range strings.Split(tag, tagSeparator) {
@@ -413,6 +432,7 @@ func (v *Validate) fieldWithNameAndValue(val interface{}, current interface{}, f
413432 // // vals := strings.Split(valTag, tagKeySeparator)
414433 // // key := strings.TrimSpace(vals[0])
415434 // }
435+ // }
416436 } else {
417437 cField = cacheField
418438 // fieldType = cacheField.typ
@@ -429,39 +449,52 @@ func (v *Validate) fieldWithNameAndValue(val interface{}, current interface{}, f
429449 }
430450
431451 if len (cField .tags ) == 0 {
432- for _ , t := range strings .Split (tag , tagSeparator ) {
433452
434- orVals := strings .Split (t , orSeparator )
435- // fmt.Println(len(orVals) - 1)
436- cTag := & cacheTags {isOrVal : len (orVals ) > 1 , keyVals : make ([][]string , len (orVals ))}
437- cField .tags = append (cField .tags , cTag )
453+ if isSingleField {
454+ cField .tags , ok = cacheFields [tag ]
455+ }
438456
439- for i , val := range orVals {
440- vals := strings .Split (val , tagKeySeparator )
457+ if ! ok {
441458
442- key := strings .TrimSpace ( vals [ 0 ])
459+ for _ , t := range strings .Split ( tag , tagSeparator ) {
443460
444- if len (key ) == 0 {
445- panic (fmt .Sprintf ("Invalid validation tag on field %s" , name ))
446- }
461+ orVals := strings .Split (t , orSeparator )
462+ // fmt.Println(len(orVals) - 1)
463+ cTag := & cacheTags {isOrVal : len (orVals ) > 1 , keyVals : make ([][]string , len (orVals ))}
464+ cField .tags = append (cField .tags , cTag )
447465
448- param := ""
449- if len ( vals ) > 1 {
450- param = strings . TrimSpace ( vals [ 1 ])
451- }
466+ for i , val := range orVals {
467+ vals := strings . Split ( val , tagKeySeparator )
468+
469+ key := strings . TrimSpace ( vals [ 0 ])
452470
453- // fmt.Println(cTag.keyVals)
454- cTag . keyVals [ i ] = [] string { key , param }
455- // cTag.keyVals = append(cTag.keyVals, []string{key, param})
471+ if len ( key ) == 0 {
472+ panic ( fmt . Sprintf ( "Invalid validation tag on field %s" , name ))
473+ }
456474
457- // for vals := range strings.Split(t, tagKeySeparator) {
458- // cField.tags = append(cField.tags, cacheTags{ isOrVal: len(orVals) > 1, []string{key, param})
475+ param := ""
476+ if len (vals ) > 1 {
477+ param = strings .TrimSpace (vals [1 ])
478+ }
459479
480+ // fmt.Println(cTag.keyVals)
481+ cTag .keyVals [i ] = []string {key , param }
482+ // cTag.keyVals = append(cTag.keyVals, []string{key, param})
483+
484+ // for vals := range strings.Split(t, tagKeySeparator) {
485+ // cField.tags = append(cField.tags, cacheTags{ isOrVal: len(orVals) > 1, []string{key, param})
486+
487+ }
488+
489+ // }
490+ // vals := strings.Split(valTag, tagKeySeparator)
491+ // key := strings.TrimSpace(vals[0])
460492 }
461493
462- // }
463- // vals := strings.Split(valTag, tagKeySeparator)
464- // key := strings.TrimSpace(vals[0])
494+ if isSingleField && ! ok {
495+ // fmt.Println(cField.tag)
496+ cacheFields [cField .tag ] = cField .tags
497+ }
465498 }
466499 }
467500
0 commit comments