diff --git a/baked_in.go b/baked_in.go index b323863..8e5f648 100644 --- a/baked_in.go +++ b/baked_in.go @@ -71,32 +71,32 @@ var BakedInValidators = map[string]Func{ "mac": isMac, } -func isMac(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isMac(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { _, err := net.ParseMAC(field.String()) return err == nil } -func isIPv4(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isIPv4(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { ip := net.ParseIP(field.String()) return ip != nil && ip.To4() != nil } -func isIPv6(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isIPv6(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { ip := net.ParseIP(field.String()) return ip != nil && ip.To4() == nil } -func isIP(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isIP(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { ip := net.ParseIP(field.String()) return ip != nil } -func isSSN(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isSSN(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { if field.Len() != 11 { return false @@ -105,15 +105,15 @@ func isSSN(topStruct reflect.Value, currentStruct reflect.Value, field reflect.V return matchesRegex(sSNRegex, field.String()) } -func isLongitude(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isLongitude(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return matchesRegex(longitudeRegex, field.String()) } -func isLatitude(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isLatitude(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return matchesRegex(latitudeRegex, field.String()) } -func isDataURI(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isDataURI(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { uri := strings.SplitN(field.String(), ",", 2) @@ -127,10 +127,10 @@ func isDataURI(topStruct reflect.Value, currentStruct reflect.Value, field refle fld := reflect.ValueOf(uri[1]) - return isBase64(topStruct, currentStruct, fld, fld.Type(), fld.Kind(), param) + return isBase64(v, topStruct, currentStruct, fld, fld.Type(), fld.Kind(), param) } -func hasMultiByteCharacter(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func hasMultiByteCharacter(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { if field.Len() == 0 { return true @@ -139,35 +139,35 @@ func hasMultiByteCharacter(topStruct reflect.Value, currentStruct reflect.Value, return matchesRegex(multibyteRegex, field.String()) } -func isPrintableASCII(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isPrintableASCII(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return matchesRegex(printableASCIIRegex, field.String()) } -func isASCII(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isASCII(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return matchesRegex(aSCIIRegex, field.String()) } -func isUUID5(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isUUID5(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return matchesRegex(uUID5Regex, field.String()) } -func isUUID4(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isUUID4(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return matchesRegex(uUID4Regex, field.String()) } -func isUUID3(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isUUID3(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return matchesRegex(uUID3Regex, field.String()) } -func isUUID(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isUUID(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return matchesRegex(uUIDRegex, field.String()) } -func isISBN(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - return isISBN10(topStruct, currentStruct, field, fieldType, fieldKind, param) || isISBN13(topStruct, currentStruct, field, fieldType, fieldKind, param) +func isISBN(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + return isISBN10(v, topStruct, currentStruct, field, fieldType, fieldKind, param) || isISBN13(v, topStruct, currentStruct, field, fieldType, fieldKind, param) } -func isISBN13(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isISBN13(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { s := strings.Replace(strings.Replace(field.String(), "-", "", 4), " ", "", 4) @@ -191,7 +191,7 @@ func isISBN13(topStruct reflect.Value, currentStruct reflect.Value, field reflec return false } -func isISBN10(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isISBN10(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { s := strings.Replace(strings.Replace(field.String(), "-", "", 3), " ", "", 3) @@ -219,41 +219,41 @@ func isISBN10(topStruct reflect.Value, currentStruct reflect.Value, field reflec return false } -func excludesRune(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - return !containsRune(topStruct, currentStruct, field, fieldType, fieldKind, param) +func excludesRune(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + return !containsRune(v, topStruct, currentStruct, field, fieldType, fieldKind, param) } -func excludesAll(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - return !containsAny(topStruct, currentStruct, field, fieldType, fieldKind, param) +func excludesAll(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + return !containsAny(v, topStruct, currentStruct, field, fieldType, fieldKind, param) } -func excludes(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - return !contains(topStruct, currentStruct, field, fieldType, fieldKind, param) +func excludes(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + return !contains(v, topStruct, currentStruct, field, fieldType, fieldKind, param) } -func containsRune(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func containsRune(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { r, _ := utf8.DecodeRuneInString(param) return strings.ContainsRune(field.String(), r) } -func containsAny(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func containsAny(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return strings.ContainsAny(field.String(), param) } -func contains(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func contains(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return strings.Contains(field.String(), param) } -func isNeField(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - return !isEqField(topStruct, currentStruct, field, fieldType, fieldKind, param) +func isNeField(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + return !isEqField(v, topStruct, currentStruct, field, fieldType, fieldKind, param) } -func isNe(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - return !isEq(topStruct, currentStruct, field, fieldType, fieldKind, param) +func isNe(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + return !isEq(v, topStruct, currentStruct, field, fieldType, fieldKind, param) } -func isEqField(topStruct reflect.Value, current reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isEqField(v *Validate, topStruct reflect.Value, current reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { // if current == nil { if !current.IsValid() { @@ -317,7 +317,7 @@ func isEqField(topStruct reflect.Value, current reflect.Value, field reflect.Val panic(fmt.Sprintf("Bad field type %T", field.Interface())) } -func isEq(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isEq(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { switch fieldKind { @@ -348,11 +348,11 @@ func isEq(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Va panic(fmt.Sprintf("Bad field type %T", field.Interface())) } -func isBase64(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isBase64(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return matchesRegex(base64Regex, field.String()) } -func isURI(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isURI(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { switch fieldKind { @@ -365,7 +365,7 @@ func isURI(topStruct reflect.Value, currentStruct reflect.Value, field reflect.V panic(fmt.Sprintf("Bad field type %T", field.Interface())) } -func isURL(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isURL(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { switch fieldKind { @@ -386,51 +386,51 @@ func isURL(topStruct reflect.Value, currentStruct reflect.Value, field reflect.V panic(fmt.Sprintf("Bad field type %T", field.Interface())) } -func isEmail(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isEmail(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return matchesRegex(emailRegex, field.String()) } -func isHsla(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isHsla(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return matchesRegex(hslaRegex, field.String()) } -func isHsl(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isHsl(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return matchesRegex(hslRegex, field.String()) } -func isRgba(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isRgba(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return matchesRegex(rgbaRegex, field.String()) } -func isRgb(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isRgb(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return matchesRegex(rgbRegex, field.String()) } -func isHexcolor(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isHexcolor(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return matchesRegex(hexcolorRegex, field.String()) } -func isHexadecimal(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isHexadecimal(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return matchesRegex(hexadecimalRegex, field.String()) } -func isNumber(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isNumber(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return matchesRegex(numberRegex, field.String()) } -func isNumeric(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isNumeric(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return matchesRegex(numericRegex, field.String()) } -func isAlphanum(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isAlphanum(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return matchesRegex(alphaNumericRegex, field.String()) } -func isAlpha(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isAlpha(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return matchesRegex(alphaRegex, field.String()) } -func hasValue(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func hasValue(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { switch fieldKind { case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func: @@ -440,7 +440,7 @@ func hasValue(topStruct reflect.Value, currentStruct reflect.Value, field reflec } } -func isGteField(topStruct reflect.Value, current reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isGteField(v *Validate, topStruct reflect.Value, current reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { if !current.IsValid() { panic("struct not passed for cross validation") @@ -501,7 +501,7 @@ func isGteField(topStruct reflect.Value, current reflect.Value, field reflect.Va panic(fmt.Sprintf("Bad field type %T", field.Interface())) } -func isGtField(topStruct reflect.Value, current reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isGtField(v *Validate, topStruct reflect.Value, current reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { if !current.IsValid() { panic("struct not passed for cross validation") @@ -562,7 +562,7 @@ func isGtField(topStruct reflect.Value, current reflect.Value, field reflect.Val panic(fmt.Sprintf("Bad field type %T", field.Interface())) } -func isGte(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isGte(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { switch fieldKind { @@ -605,7 +605,7 @@ func isGte(topStruct reflect.Value, currentStruct reflect.Value, field reflect.V panic(fmt.Sprintf("Bad field type %T", field.Interface())) } -func isGt(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isGt(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { switch fieldKind { @@ -647,7 +647,7 @@ func isGt(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Va // length tests whether a variable's length is equal to a given // value. For strings it tests the number of characters whereas // for maps and slices it tests the number of items. -func hasLengthOf(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func hasLengthOf(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { switch fieldKind { @@ -684,12 +684,12 @@ func hasLengthOf(topStruct reflect.Value, currentStruct reflect.Value, field ref // number. For number types, it's a simple lesser-than test; for // strings it tests the number of characters whereas for maps // and slices it tests the number of items. -func hasMinOf(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func hasMinOf(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - return isGte(topStruct, currentStruct, field, fieldType, fieldKind, param) + return isGte(v, topStruct, currentStruct, field, fieldType, fieldKind, param) } -func isLteField(topStruct reflect.Value, current reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isLteField(v *Validate, topStruct reflect.Value, current reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { if !current.IsValid() { panic("struct not passed for cross validation") @@ -750,7 +750,7 @@ func isLteField(topStruct reflect.Value, current reflect.Value, field reflect.Va panic(fmt.Sprintf("Bad field type %T", field.Interface())) } -func isLtField(topStruct reflect.Value, current reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isLtField(v *Validate, topStruct reflect.Value, current reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { if !current.IsValid() { panic("struct not passed for cross validation") @@ -811,7 +811,7 @@ func isLtField(topStruct reflect.Value, current reflect.Value, field reflect.Val panic(fmt.Sprintf("Bad field type %T", field.Interface())) } -func isLte(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isLte(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { switch fieldKind { @@ -854,7 +854,7 @@ func isLte(topStruct reflect.Value, currentStruct reflect.Value, field reflect.V panic(fmt.Sprintf("Bad field type %T", field.Interface())) } -func isLt(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isLt(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { switch fieldKind { @@ -898,9 +898,9 @@ func isLt(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Va // value. For numbers, it's a simple lesser-than test; for // strings it tests the number of characters whereas for maps // and slices it tests the number of items. -func hasMaxOf(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func hasMaxOf(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - return isLte(topStruct, currentStruct, field, fieldType, fieldKind, param) + return isLte(v, topStruct, currentStruct, field, fieldType, fieldKind, param) } // asInt retuns the parameter as a int64 diff --git a/util.go b/util.go new file mode 100644 index 0000000..7d55550 --- /dev/null +++ b/util.go @@ -0,0 +1,124 @@ +package validator + +import ( + "reflect" + "strconv" + "strings" +) + +func (v *Validate) determineType(current reflect.Value) (reflect.Value, reflect.Kind) { + + switch current.Kind() { + case reflect.Ptr: + + if current.IsNil() { + return current, reflect.Ptr + } + + return v.determineType(current.Elem()) + + case reflect.Interface: + + if current.IsNil() { + return current, reflect.Interface + } + + return v.determineType(current.Elem()) + + case reflect.Invalid: + + return current, reflect.Invalid + + default: + + // fmt.Println(current.Kind()) + if v.config.hasCustomFuncs { + if fn, ok := v.config.CustomTypeFuncs[current.Type()]; ok { + return v.determineType(reflect.ValueOf(fn(current))) + } + } + + return current, current.Kind() + } +} + +func (v *Validate) getStructFieldOK(current reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool) { + + // fmt.Println("NS:", namespace) + + current, kind := v.determineType(current) + + // fmt.Println("getStructFieldOK - ", current, kind) + + switch kind { + case reflect.Ptr, reflect.Interface, reflect.Invalid: + return current, kind, false + + case reflect.Struct: + + typ := current.Type() + fld := namespace + + if typ != timeType && typ != timePtrType { + + idx := strings.Index(namespace, namespaceSeparator) + + // fmt.Println("IDX:", namespace, idx) + if idx != -1 { + fld = namespace[:idx] + } + + ns := namespace[idx+1:] + + bracketIdx := strings.Index(fld, "[") + if bracketIdx != -1 { + fld = fld[:bracketIdx] + // fmt.Println("NSS:", ns) + + if idx == -1 { + ns = namespace[bracketIdx:] + } else { + ns = namespace[idx+bracketIdx:] + } + } + + // fmt.Println("Looking for field:", fld) + current = current.FieldByName(fld) + + // fmt.Println("Current:", current) + + return v.getStructFieldOK(current, ns) + } + + case reflect.Array, reflect.Slice: + idx := strings.Index(namespace, "[") + idx2 := strings.Index(namespace, "]") + + arrIdx, _ := strconv.Atoi(namespace[idx+1 : idx2]) + + // fmt.Println("ArrayIndex:", arrIdx) + // fmt.Println("LEN:", current.Len()) + if arrIdx >= current.Len() { + return current, kind, false + } + + return v.getStructFieldOK(current.Index(arrIdx), namespace[idx2+1:]) + + case reflect.Map: + idx := strings.Index(namespace, "[") + idx2 := strings.Index(namespace, "]") + + // key, _ := strconv.Atoi(namespace[idx+1 : idx2]) + + // fmt.Println("ArrayIndex:", arrIdx) + // fmt.Println("LEN:", current.Len()) + // if arrIdx >= current.Len() { + // return current, kind, false + // } + + return v.getStructFieldOK(current.MapIndex(reflect.ValueOf(namespace[idx+1:idx2])), namespace[idx2+1:]) + } + + // fmt.Println("Returning field") + return current, kind, true +} diff --git a/validator.go b/validator.go index 709a1fc..cd5e783 100644 --- a/validator.go +++ b/validator.go @@ -22,6 +22,7 @@ import ( const ( utf8HexComma = "0x2C" utf8Pipe = "0x7C" + namespaceSeparator = "." tagSeparator = "," orSeparator = "|" tagKeySeparator = "=" @@ -96,7 +97,7 @@ type CustomTypeFunc func(field reflect.Value) interface{} // currentStruct = current level struct when validating by struct otherwise optional comparison value // field = field value for validation // param = parameter used in validation i.e. gt=0 param would be 0 -type Func func(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldtype reflect.Type, fieldKind reflect.Kind, param string) bool +type Func func(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldtype reflect.Type, fieldKind reflect.Kind, param string) bool // ValidationErrors is a type of map[string]*FieldError // it exists to allow for multiple errors to be passed from this library @@ -263,18 +264,11 @@ func (v *Validate) traverseField(topStruct reflect.Value, currentStruct reflect. return } - kind := current.Kind() - - if kind == reflect.Ptr && !current.IsNil() { - current = current.Elem() - kind = current.Kind() - } - - // this also allows for tags 'required' and 'omitempty' to be used on - // nested struct fields because when len(tags) > 0 below and the value is nil - // then required failes and we check for omitempty just before that - if ((kind == reflect.Ptr || kind == reflect.Interface) && current.IsNil()) || kind == reflect.Invalid { + current, kind := v.determineType(current) + var typ reflect.Type + switch kind { + case reflect.Ptr, reflect.Interface, reflect.Invalid: if strings.Contains(tag, omitempty) { return } @@ -299,6 +293,7 @@ func (v *Validate) traverseField(topStruct reflect.Value, currentStruct reflect. return } + // fmt.Println(kind) errs[errPrefix+name] = &FieldError{ Field: name, Tag: vals[0], @@ -314,67 +309,150 @@ func (v *Validate) traverseField(topStruct reflect.Value, currentStruct reflect. if kind == reflect.Invalid { return } - } - typ := current.Type() - - switch kind { - case reflect.Struct, reflect.Interface: - - if kind == reflect.Interface { - - current = current.Elem() - kind = current.Kind() - - if kind == reflect.Ptr && !current.IsNil() { - current = current.Elem() - kind = current.Kind() - } - - // changed current, so have to get inner type again - typ = current.Type() - - if kind != reflect.Struct { - goto FALLTHROUGH - } - } + case reflect.Struct: + typ = current.Type() if typ != timeType && typ != timePtrType { + // goto FALLTHROUGH - if kind == reflect.Struct { - - if v.config.hasCustomFuncs { - if fn, ok := v.config.CustomTypeFuncs[typ]; ok { - v.traverseField(topStruct, currentStruct, reflect.ValueOf(fn(current)), errPrefix, errs, isStructField, tag, name) - return - } - } - - // required passed validation above so stop here - // if only validating the structs existance. - if strings.Contains(tag, structOnlyTag) { - return - } - - v.tranverseStruct(topStruct, current, current, errPrefix+name+".", errs, false) + // required passed validation above so stop here + // if only validating the structs existance. + if strings.Contains(tag, structOnlyTag) { return } - } - FALLTHROUGH: - fallthrough - default: - if len(tag) == 0 { + + v.tranverseStruct(topStruct, current, current, errPrefix+name+".", errs, false) return } + // FALLTHROUGH: + // fallthrough + // default: + // fmt.Println(tag) + // if len(tag) == 0 { + // return + // } } - if v.config.hasCustomFuncs { - if fn, ok := v.config.CustomTypeFuncs[typ]; ok { - v.traverseField(topStruct, currentStruct, reflect.ValueOf(fn(current)), errPrefix, errs, isStructField, tag, name) - return - } + if len(tag) == 0 { + return } + typ = current.Type() + // fmt.Println("Kind:", k) + + // kind := current.Kind() + + // if kind == reflect.Ptr && !current.IsNil() { + // current = current.Elem() + // kind = current.Kind() + // } + + // this also allows for tags 'required' and 'omitempty' to be used on + // nested struct fields because when len(tags) > 0 below and the value is nil + // then required failes and we check for omitempty just before that + // if ((kind == reflect.Ptr || kind == reflect.Interface) && current.IsNil()) || kind == reflect.Invalid { + + // if strings.Contains(tag, omitempty) { + // return + // } + + // if len(tag) > 0 { + + // tags := strings.Split(tag, tagSeparator) + // var param string + // vals := strings.SplitN(tags[0], tagKeySeparator, 2) + + // if len(vals) > 1 { + // param = vals[1] + // } + + // if kind == reflect.Invalid { + // errs[errPrefix+name] = &FieldError{ + // Field: name, + // Tag: vals[0], + // Param: param, + // Kind: kind, + // } + // return + // } + + // errs[errPrefix+name] = &FieldError{ + // Field: name, + // Tag: vals[0], + // Param: param, + // Value: current.Interface(), + // Kind: kind, + // Type: current.Type(), + // } + + // return + // } + // // if we get here tag length is zero and we can leave + // if kind == reflect.Invalid { + // return + // } + // } + + // typ := current.Type() + + // switch kind { + // case reflect.Struct, reflect.Interface: + + // if kind == reflect.Interface { + + // current = current.Elem() + // kind = current.Kind() + + // if kind == reflect.Ptr && !current.IsNil() { + // current = current.Elem() + // kind = current.Kind() + // } + + // // changed current, so have to get inner type again + // typ = current.Type() + + // if kind != reflect.Struct { + // goto FALLTHROUGH + // } + // } + + // if typ != timeType && typ != timePtrType { + + // if kind == reflect.Struct { + + // if v.config.hasCustomFuncs { + // if fn, ok := v.config.CustomTypeFuncs[typ]; ok { + // v.traverseField(topStruct, currentStruct, reflect.ValueOf(fn(current)), errPrefix, errs, isStructField, tag, name) + // return + // } + // } + + // // required passed validation above so stop here + // // if only validating the structs existance. + // if strings.Contains(tag, structOnlyTag) { + // return + // } + + // v.tranverseStruct(topStruct, current, current, errPrefix+name+".", errs, false) + // return + // } + // } + // FALLTHROUGH: + // fallthrough + // default: + // if len(tag) == 0 { + // return + // } + // } + + // if v.config.hasCustomFuncs { + // if fn, ok := v.config.CustomTypeFuncs[typ]; ok { + // v.traverseField(topStruct, currentStruct, reflect.ValueOf(fn(current)), errPrefix, errs, isStructField, tag, name) + // return + // } + // } + tags, isCached := tagsCache.Get(tag) if !isCached { @@ -431,7 +509,7 @@ func (v *Validate) traverseField(topStruct reflect.Value, currentStruct reflect. if cTag.tagVals[0][0] == omitempty { - if !hasValue(topStruct, currentStruct, current, typ, kind, "") { + if !hasValue(v, topStruct, currentStruct, current, typ, kind, "") { return } continue @@ -491,7 +569,7 @@ func (v *Validate) validateField(topStruct reflect.Value, currentStruct reflect. panic(strings.TrimSpace(fmt.Sprintf(undefinedValidation, name))) } - if valFunc(topStruct, currentStruct, current, currentType, currentKind, val[1]) { + if valFunc(v, topStruct, currentStruct, current, currentType, currentKind, val[1]) { return false } @@ -514,7 +592,7 @@ func (v *Validate) validateField(topStruct reflect.Value, currentStruct reflect. panic(strings.TrimSpace(fmt.Sprintf(undefinedValidation, name))) } - if valFunc(topStruct, currentStruct, current, currentType, currentKind, cTag.tagVals[0][1]) { + if valFunc(v, topStruct, currentStruct, current, currentType, currentKind, cTag.tagVals[0][1]) { return false } diff --git a/validator_test.go b/validator_test.go index 5ca43f9..ccd9a9b 100644 --- a/validator_test.go +++ b/validator_test.go @@ -192,6 +192,59 @@ func ValidateValuerType(field reflect.Value) interface{} { return nil } +func TestCrossNamespaceFieldValidation(t *testing.T) { + + type Inner struct { + CreatedAt *time.Time + Slice []string + Map map[string]string + } + + type Test struct { + Inner *Inner + CreatedAt *time.Time + } + + now := time.Now() + + inner := &Inner{ + CreatedAt: &now, + Slice: []string{"val1", "val2", "val3"}, + Map: map[string]string{"key1": "val1", "key2": "val2", "key3": "val3"}, + } + + test := &Test{ + Inner: inner, + CreatedAt: &now, + } + + val := reflect.ValueOf(test) + + current, kind, ok := validate.getStructFieldOK(val, "Inner.CreatedAt") + Equal(t, ok, true) + Equal(t, kind, reflect.Struct) + tm, ok := current.Interface().(time.Time) + Equal(t, ok, true) + Equal(t, tm, now) + + current, kind, ok = validate.getStructFieldOK(val, "Inner.Slice[1]") + Equal(t, ok, true) + Equal(t, kind, reflect.String) + Equal(t, current.String(), "val2") + + current, kind, ok = validate.getStructFieldOK(val, "Inner.Slice[101]") + Equal(t, ok, false) + + current, kind, ok = validate.getStructFieldOK(val, "Inner.Map[key3]") + Equal(t, ok, true) + Equal(t, kind, reflect.String) + Equal(t, current.String(), "val3") + + // fmt.Println(ok) + // fmt.Println(current) + // fmt.Println(kind) +} + func TestExistsValidation(t *testing.T) { jsonText := "{ \"truthiness2\": true }" @@ -2710,7 +2763,7 @@ func TestValidateByTagAndValue(t *testing.T) { errs := validate.FieldWithValue(val, field, "required") Equal(t, errs, nil) - fn := func(topStruct reflect.Value, current reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + fn := func(v *Validate, topStruct reflect.Value, current reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return current.String() == field.String() } @@ -2729,7 +2782,7 @@ func TestValidateByTagAndValue(t *testing.T) { func TestAddFunctions(t *testing.T) { - fn := func(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + fn := func(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return true }