@@ -20,21 +20,22 @@ import (
2020)
2121
2222const (
23- utf8HexComma = "0x2C"
24- tagSeparator = ","
25- orSeparator = "|"
26- noValidationTag = "-"
27- tagKeySeparator = "="
28- structOnlyTag = "structonly"
29- omitempty = "omitempty"
30- required = "required"
31- fieldErrMsg = "Field validation for \" %s\" failed on the \" %s\" tag"
32- sliceErrMsg = "Field validation for \" %s\" failed at index \" %d\" failed with error(s): %s"
33- mapErrMsg = "Field validation for \" %s\" failed with key \" %v\" failed with error(s): %s"
34- structErrMsg = "Struct:%s\n "
35- diveTag = "dive"
36- diveSplit = "," + diveTag
37- indexFieldName = "%s[%d]"
23+ utf8HexComma = "0x2C"
24+ tagSeparator = ","
25+ orSeparator = "|"
26+ noValidationTag = "-"
27+ tagKeySeparator = "="
28+ structOnlyTag = "structonly"
29+ omitempty = "omitempty"
30+ required = "required"
31+ fieldErrMsg = "Field validation for \" %s\" failed on the \" %s\" tag"
32+ sliceErrMsg = "Field validation for \" %s\" failed at index \" %d\" with error(s): %s"
33+ mapErrMsg = "Field validation for \" %s\" failed on key \" %v\" with error(s): %s"
34+ structErrMsg = "Struct:%s\n "
35+ diveTag = "dive"
36+ diveSplit = "," + diveTag
37+ arrayIndexFieldName = "%s[%d]"
38+ mapIndexFieldName = "%s[%v]"
3839)
3940
4041var structPool * pool
@@ -670,7 +671,18 @@ func (v *Validate) fieldWithNameAndValue(val interface{}, current interface{}, f
670671 }
671672
672673 } else if cField .isMap {
673- // return if error here
674+ if errs := v .traverseMap (val , current , valueField , cField ); errs != nil && len (errs ) > 0 {
675+
676+ return & FieldError {
677+ Field : cField .name ,
678+ Kind : cField .kind ,
679+ Type : cField .typ ,
680+ Value : f ,
681+ IsPlaceholderErr : true ,
682+ IsMap : true ,
683+ MapErrs : errs ,
684+ }
685+ }
674686 } else {
675687 // throw error, if not a slice or map then should not have gotten here
676688 panic ("dive error! can't dive on a non slice or map" )
@@ -680,6 +692,65 @@ func (v *Validate) fieldWithNameAndValue(val interface{}, current interface{}, f
680692 return nil
681693}
682694
695+ func (v * Validate ) traverseMap (val interface {}, current interface {}, valueField reflect.Value , cField * cachedField ) map [interface {}]error {
696+
697+ errs := map [interface {}]error {}
698+
699+ for _ , key := range valueField .MapKeys () {
700+
701+ idxField := valueField .MapIndex (key )
702+
703+ if cField .sliceSubKind == reflect .Ptr && ! idxField .IsNil () {
704+ idxField = idxField .Elem ()
705+ cField .sliceSubKind = idxField .Kind ()
706+ }
707+
708+ switch cField .sliceSubKind {
709+ case reflect .Struct , reflect .Interface :
710+
711+ if cField .isTimeSubtype {
712+
713+ if fieldError := v .fieldWithNameAndValue (val , current , idxField .Interface (), cField .diveTag , fmt .Sprintf (mapIndexFieldName , cField .name , key .Interface ()), false , nil ); fieldError != nil {
714+ errs [key .Interface ()] = fieldError
715+ }
716+
717+ continue
718+ }
719+
720+ if idxField .Kind () == reflect .Ptr && idxField .IsNil () {
721+
722+ if strings .Contains (cField .tag , omitempty ) {
723+ continue
724+ }
725+
726+ if strings .Contains (cField .tag , required ) {
727+
728+ errs [key .Interface ()] = & FieldError {
729+ Field : cField .name ,
730+ Tag : required ,
731+ Value : idxField .Interface (),
732+ Kind : reflect .Ptr ,
733+ Type : cField .sliceSubtype ,
734+ }
735+ }
736+
737+ continue
738+ }
739+
740+ if structErrors := v .structRecursive (val , current , idxField .Interface ()); structErrors != nil {
741+ errs [key .Interface ()] = structErrors
742+ }
743+
744+ default :
745+ if fieldError := v .fieldWithNameAndValue (val , current , idxField .Interface (), cField .diveTag , fmt .Sprintf (mapIndexFieldName , cField .name , key .Interface ()), false , nil ); fieldError != nil {
746+ errs [key .Interface ()] = fieldError
747+ }
748+ }
749+ }
750+
751+ return errs
752+ }
753+
683754func (v * Validate ) traverseSliceOrArray (val interface {}, current interface {}, valueField reflect.Value , cField * cachedField ) map [int ]error {
684755
685756 errs := map [int ]error {}
@@ -698,7 +769,7 @@ func (v *Validate) traverseSliceOrArray(val interface{}, current interface{}, va
698769
699770 if cField .isTimeSubtype {
700771
701- if fieldError := v .fieldWithNameAndValue (val , current , idxField .Interface (), cField .diveTag , cField .name , false , nil ); fieldError != nil {
772+ if fieldError := v .fieldWithNameAndValue (val , current , idxField .Interface (), cField .diveTag , fmt . Sprintf ( arrayIndexFieldName , cField .name , i ) , false , nil ); fieldError != nil {
702773 errs [i ] = fieldError
703774 }
704775
@@ -730,7 +801,7 @@ func (v *Validate) traverseSliceOrArray(val interface{}, current interface{}, va
730801 }
731802
732803 default :
733- if fieldError := v .fieldWithNameAndValue (val , current , idxField .Interface (), cField .diveTag , fmt .Sprintf (indexFieldName , cField .name , i ), false , nil ); fieldError != nil {
804+ if fieldError := v .fieldWithNameAndValue (val , current , idxField .Interface (), cField .diveTag , fmt .Sprintf (arrayIndexFieldName , cField .name , i ), false , nil ); fieldError != nil {
734805 errs [i ] = fieldError
735806 }
736807 }
0 commit comments