diff --git a/validator.go b/validator.go index 0fe2eac..18ce53a 100644 --- a/validator.go +++ b/validator.go @@ -12,23 +12,24 @@ import ( "bytes" "fmt" "reflect" - "strconv" "strings" "time" ) const ( - utf8HexComma = "0x2C" - utf8Pipe = "0x7C" - tagSeparator = "," - orSeparator = "|" - tagKeySeparator = "=" - structOnlyTag = "structonly" - omitempty = "omitempty" - skipValidationTag = "-" - diveTag = "dive" - fieldErrMsg = "Key: \"%s\" Error:Field validation for \"%s\" failed on the \"%s\" tag" - invaldField = "Invalid field passed to traverseField" + utf8HexComma = "0x2C" + utf8Pipe = "0x7C" + tagSeparator = "," + orSeparator = "|" + tagKeySeparator = "=" + structOnlyTag = "structonly" + omitempty = "omitempty" + skipValidationTag = "-" + diveTag = "dive" + fieldErrMsg = "Key: \"%s\" Error:Field validation for \"%s\" failed on the \"%s\" tag" + invaldField = "Invalid field passed to traverseField" + arrayIndexFieldName = "%s[%d]" + mapIndexFieldName = "%s[%v]" ) var ( @@ -133,7 +134,7 @@ func (v *Validate) Struct(current interface{}) ValidationErrors { errs := map[string]*FieldError{} sv := reflect.ValueOf(current) - v.tranverseStruct(sv, sv, sv, "", errs) + v.tranverseStruct(sv, sv, sv, "", errs, true) if len(errs) == 0 { return nil @@ -142,7 +143,7 @@ func (v *Validate) Struct(current interface{}) ValidationErrors { return errs } -func (v *Validate) tranverseStruct(topStruct reflect.Value, currentStruct reflect.Value, current reflect.Value, errPrefix string, errs ValidationErrors) { +func (v *Validate) tranverseStruct(topStruct reflect.Value, currentStruct reflect.Value, current reflect.Value, errPrefix string, errs ValidationErrors, useStructName bool) { if current.Kind() == reflect.Ptr && !current.IsNil() { current = current.Elem() @@ -153,7 +154,11 @@ func (v *Validate) tranverseStruct(topStruct reflect.Value, currentStruct reflec } typ := current.Type() - errPrefix += typ.Name() + "." + + if useStructName { + errPrefix += typ.Name() + "." + } + numFields := current.NumField() var fld reflect.StructField @@ -246,7 +251,7 @@ func (v *Validate) traverseField(topStruct reflect.Value, currentStruct reflect. return } - v.tranverseStruct(topStruct, current, current, errPrefix, errs) + v.tranverseStruct(topStruct, current, current, errPrefix+name+".", errs, false) return } @@ -311,14 +316,17 @@ func (v *Validate) traverseField(topStruct reflect.Value, currentStruct reflect. // or panic ;) switch kind { case reflect.Slice, reflect.Array: - - case reflect.Map: v.traverseSlice(topStruct, currentStruct, current, errPrefix, errs, diveSubTag, name) + case reflect.Map: + v.traverseMap(topStruct, currentStruct, current, errPrefix, errs, diveSubTag, name) + default: + // throw error, if not a slice or map then should not have gotten here + // bad dive tag usage + panic("dive error! can't dive on a non slice or map") } } } -// func (v *Validate) traverseSlice(val interface{}, current interface{}, valueField reflect.Value, cField *cachedField) map[int]error { func (v *Validate) traverseSlice(topStruct reflect.Value, currentStruct reflect.Value, current reflect.Value, errPrefix string, errs ValidationErrors, tag string, name string) { for i := 0; i < current.Len(); i++ { @@ -329,7 +337,21 @@ func (v *Validate) traverseSlice(topStruct reflect.Value, currentStruct reflect. idxField = idxField.Elem() } - v.traverseField(topStruct, currentStruct, current, errPrefix, errs, false, tag, name+"["+strconv.Itoa(i)+"]") + v.traverseField(topStruct, currentStruct, current, errPrefix, errs, false, tag, fmt.Sprintf(arrayIndexFieldName, name, i)) + } +} + +func (v *Validate) traverseMap(topStruct reflect.Value, currentStruct reflect.Value, current reflect.Value, errPrefix string, errs ValidationErrors, tag string, name string) { + + for _, key := range current.MapKeys() { + + idxField := current.MapIndex(key) + + if idxField.Kind() == reflect.Ptr && !idxField.IsNil() { + idxField = idxField.Elem() + } + + v.traverseField(topStruct, currentStruct, current, errPrefix, errs, false, tag, fmt.Sprintf(mapIndexFieldName, name, key.Interface())) } }