diff --git a/baked_in.go b/baked_in.go index 92b4611..392de19 100644 --- a/baked_in.go +++ b/baked_in.go @@ -2,8 +2,10 @@ package validator import ( "fmt" + "net/url" "reflect" "strconv" + "strings" "time" "unicode/utf8" ) @@ -12,574 +14,525 @@ import ( // you can add, remove or even replace items to suite your needs, // or even disregard and use your own map if so desired. var BakedInValidators = map[string]Func{ - "required": hasValue, - "len": hasLengthOf, - "min": hasMinOf, - "max": hasMaxOf, - // "eq": isEq, - // "ne": isNe, - // "lt": isLt, - "lte": isLte, - // "gt": isGt, - "gte": isGte, - // "eqfield": isEqField, - // "nefield": isNeField, - // "gtefield": isGteField, - // "gtfield": isGtField, - // "ltefield": isLteField, - // "ltfield": isLtField, - // "alpha": isAlpha, - // "alphanum": isAlphanum, - // "numeric": isNumeric, - // "number": isNumber, - // "hexadecimal": isHexadecimal, - // "hexcolor": isHexcolor, - // "rgb": isRgb, - // "rgba": isRgba, - // "hsl": isHsl, - // "hsla": isHsla, - // "email": isEmail, - // "url": isURL, - // "uri": isURI, - // "base64": isBase64, - // "contains": contains, - // "containsany": containsAny, - // "containsrune": containsRune, - // "excludes": excludes, - // "excludesall": excludesAll, - // "excludesrune": excludesRune, - // "isbn": isISBN, - // "isbn10": isISBN10, - // "isbn13": isISBN13, - // "uuid": isUUID, - // "uuid3": isUUID3, - // "uuid4": isUUID4, - // "uuid5": isUUID5, - // "ascii": isASCII, - // "printascii": isPrintableASCII, - // "multibyte": hasMultiByteCharacter, - // "datauri": isDataURI, - // "latitude": isLatitude, - // "longitude": isLongitude, - // "ssn": isSSN, -} - -// func isSSN(top interface{}, current interface{}, field interface{}, param string) bool { - -// if len(field.(string)) != 11 { -// return false -// } - -// return matchesRegex(sSNRegex, field) -// } - -// func isLongitude(top interface{}, current interface{}, field interface{}, param string) bool { -// return matchesRegex(longitudeRegex, field) -// } - -// func isLatitude(top interface{}, current interface{}, field interface{}, param string) bool { -// return matchesRegex(latitudeRegex, field) -// } - -// func isDataURI(top interface{}, current interface{}, field interface{}, param string) bool { - -// uri := strings.SplitN(field.(string), ",", 2) - -// if len(uri) != 2 { -// return false -// } - -// if !matchesRegex(dataURIRegex, uri[0]) { -// return false -// } - -// return isBase64(top, current, uri[1], param) -// } - -// func hasMultiByteCharacter(top interface{}, current interface{}, field interface{}, param string) bool { - -// if len(field.(string)) == 0 { -// return true -// } - -// return matchesRegex(multibyteRegex, field) -// } - -// func isPrintableASCII(top interface{}, current interface{}, field interface{}, param string) bool { -// return matchesRegex(printableASCIIRegex, field) -// } - -// func isASCII(top interface{}, current interface{}, field interface{}, param string) bool { -// return matchesRegex(aSCIIRegex, field) -// } - -// func isUUID5(top interface{}, current interface{}, field interface{}, param string) bool { -// return matchesRegex(uUID5Regex, field) -// } - -// func isUUID4(top interface{}, current interface{}, field interface{}, param string) bool { -// return matchesRegex(uUID4Regex, field) -// } - -// func isUUID3(top interface{}, current interface{}, field interface{}, param string) bool { -// return matchesRegex(uUID3Regex, field) -// } - -// func isUUID(top interface{}, current interface{}, field interface{}, param string) bool { -// return matchesRegex(uUIDRegex, field) -// } - -// func isISBN(top interface{}, current interface{}, field interface{}, param string) bool { -// return isISBN10(top, current, field, param) || isISBN13(top, current, field, param) -// } - -// func isISBN13(top interface{}, current interface{}, field interface{}, param string) bool { - -// s := strings.Replace(strings.Replace(field.(string), "-", "", 4), " ", "", 4) - -// if !matchesRegex(iSBN13Regex, s) { -// return false -// } - -// var checksum int32 -// var i int32 - -// factor := []int32{1, 3} - -// for i = 0; i < 12; i++ { -// checksum += factor[i%2] * int32(s[i]-'0') -// } + "required": hasValue, + "len": hasLengthOf, + "min": hasMinOf, + "max": hasMaxOf, + "eq": isEq, + "ne": isNe, + "lt": isLt, + "lte": isLte, + "gt": isGt, + "gte": isGte, + "eqfield": isEqField, + "nefield": isNeField, + "gtefield": isGteField, + "gtfield": isGtField, + "ltefield": isLteField, + "ltfield": isLtField, + "alpha": isAlpha, + "alphanum": isAlphanum, + "numeric": isNumeric, + "number": isNumber, + "hexadecimal": isHexadecimal, + "hexcolor": isHexcolor, + "rgb": isRgb, + "rgba": isRgba, + "hsl": isHsl, + "hsla": isHsla, + "email": isEmail, + "url": isURL, + "uri": isURI, + "base64": isBase64, + "contains": contains, + "containsany": containsAny, + "containsrune": containsRune, + "excludes": excludes, + "excludesall": excludesAll, + "excludesrune": excludesRune, + "isbn": isISBN, + "isbn10": isISBN10, + "isbn13": isISBN13, + "uuid": isUUID, + "uuid3": isUUID3, + "uuid4": isUUID4, + "uuid5": isUUID5, + "ascii": isASCII, + "printascii": isPrintableASCII, + "multibyte": hasMultiByteCharacter, + "datauri": isDataURI, + "latitude": isLatitude, + "longitude": isLongitude, + "ssn": isSSN, +} -// if (int32(s[12]-'0'))-((10-(checksum%10))%10) == 0 { -// return true -// } +func isSSN(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { -// return false -// } + if field.Len() != 11 { + return false + } -// func isISBN10(top interface{}, current interface{}, field interface{}, param string) bool { + return matchesRegex(sSNRegex, field.String()) +} -// s := strings.Replace(strings.Replace(field.(string), "-", "", 3), " ", "", 3) +func isLongitude(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + return matchesRegex(longitudeRegex, field.String()) +} -// if !matchesRegex(iSBN10Regex, s) { -// return false -// } +func isLatitude(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + return matchesRegex(latitudeRegex, field.String()) +} -// var checksum int32 -// var i int32 +func isDataURI(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { -// for i = 0; i < 9; i++ { -// checksum += (i + 1) * int32(s[i]-'0') -// } + uri := strings.SplitN(field.String(), ",", 2) -// if s[9] == 'X' { -// checksum += 10 * 10 -// } else { -// checksum += 10 * int32(s[9]-'0') -// } + if len(uri) != 2 { + return false + } -// if checksum%11 == 0 { -// return true -// } + if !matchesRegex(dataURIRegex, uri[0]) { + return false + } -// return false -// } + fld := reflect.ValueOf(uri[1]) -// func excludesRune(top interface{}, current interface{}, field interface{}, param string) bool { -// return !containsRune(top, current, field, param) -// } + return isBase64(topStruct, currentStruct, fld, fld.Type(), fld.Kind(), param) +} -// func excludesAll(top interface{}, current interface{}, field interface{}, param string) bool { -// return !containsAny(top, current, field, param) -// } +func hasMultiByteCharacter(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { -// func excludes(top interface{}, current interface{}, field interface{}, param string) bool { -// return !contains(top, current, field, param) -// } + if field.Len() == 0 { + return true + } -// func containsRune(top interface{}, current interface{}, field interface{}, param string) bool { -// r, _ := utf8.DecodeRuneInString(param) + return matchesRegex(multibyteRegex, field.String()) +} -// return strings.ContainsRune(field.(string), r) -// } +func isPrintableASCII(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + return matchesRegex(printableASCIIRegex, field.String()) +} -// func containsAny(top interface{}, current interface{}, field interface{}, param string) bool { -// return strings.ContainsAny(field.(string), param) -// } +func isASCII(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + return matchesRegex(aSCIIRegex, field.String()) +} -// func contains(top interface{}, current interface{}, field interface{}, param string) bool { -// return strings.Contains(field.(string), param) -// } +func isUUID5(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + return matchesRegex(uUID5Regex, field.String()) +} -// func isNeField(top interface{}, current interface{}, field interface{}, param string) bool { -// return !isEqField(top, current, field, param) -// } +func isUUID4(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + return matchesRegex(uUID4Regex, field.String()) +} -// func isNe(top interface{}, current interface{}, field interface{}, param string) bool { -// return !isEq(top, current, field, param) -// } +func isUUID3(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + return matchesRegex(uUID3Regex, field.String()) +} -// func isEqField(top interface{}, current interface{}, field interface{}, param string) bool { +func isUUID(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + return matchesRegex(uUIDRegex, field.String()) +} -// if current == nil { -// panic("struct not passed for cross validation") -// } +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) +} -// currentVal := reflect.ValueOf(current) +func isISBN13(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { -// if currentVal.Kind() == reflect.Ptr && !currentVal.IsNil() { -// currentVal = reflect.ValueOf(currentVal.Elem().Interface()) -// } + s := strings.Replace(strings.Replace(field.String(), "-", "", 4), " ", "", 4) -// var currentFielVal reflect.Value + if !matchesRegex(iSBN13Regex, s) { + return false + } -// switch currentVal.Kind() { + var checksum int32 + var i int32 -// case reflect.Struct: + factor := []int32{1, 3} -// if currentVal.Type() == reflect.TypeOf(time.Time{}) { -// currentFielVal = currentVal -// break -// } + for i = 0; i < 12; i++ { + checksum += factor[i%2] * int32(s[i]-'0') + } -// f := currentVal.FieldByName(param) + if (int32(s[12]-'0'))-((10-(checksum%10))%10) == 0 { + return true + } -// if f.Kind() == reflect.Invalid { -// panic(fmt.Sprintf("Field \"%s\" not found in struct", param)) -// } + return false +} -// currentFielVal = f +func isISBN10(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { -// default: + s := strings.Replace(strings.Replace(field.String(), "-", "", 3), " ", "", 3) -// currentFielVal = currentVal -// } + if !matchesRegex(iSBN10Regex, s) { + return false + } -// if currentFielVal.Kind() == reflect.Ptr && !currentFielVal.IsNil() { + var checksum int32 + var i int32 -// currentFielVal = reflect.ValueOf(currentFielVal.Elem().Interface()) -// } + for i = 0; i < 9; i++ { + checksum += (i + 1) * int32(s[i]-'0') + } -// fv := reflect.ValueOf(field) + if s[9] == 'X' { + checksum += 10 * 10 + } else { + checksum += 10 * int32(s[9]-'0') + } -// switch fv.Kind() { + if checksum%11 == 0 { + return true + } -// case reflect.String: -// return fv.String() == currentFielVal.String() -// case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return false +} -// return fv.Int() == currentFielVal.Int() +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) +} -// case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: +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) +} -// return fv.Uint() == currentFielVal.Uint() +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) +} -// case reflect.Float32, reflect.Float64: +func containsRune(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + r, _ := utf8.DecodeRuneInString(param) -// return fv.Float() == currentFielVal.Float() -// case reflect.Slice, reflect.Map, reflect.Array: + return strings.ContainsRune(field.String(), r) +} -// return int64(fv.Len()) == int64(currentFielVal.Len()) -// case reflect.Struct: +func containsAny(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + return strings.ContainsAny(field.String(), param) +} -// if fv.Type() == reflect.TypeOf(time.Time{}) { +func contains(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + return strings.Contains(field.String(), param) +} -// if currentFielVal.Type() != reflect.TypeOf(time.Time{}) { -// panic("Bad Top Level field type") -// } +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) +} -// t := currentFielVal.Interface().(time.Time) -// fieldTime := field.(time.Time) +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) +} -// return fieldTime.Equal(t) -// } -// } +func isEqField(topStruct reflect.Value, current reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { -// panic(fmt.Sprintf("Bad field type %T", field)) -// } + // if current == nil { + if !current.IsValid() { + panic("struct or field value not passed for cross validation") + } -// func isEq(top interface{}, current interface{}, field interface{}, param string) bool { + if current.Kind() == reflect.Ptr && !current.IsNil() { + current = current.Elem() + } -// st := reflect.ValueOf(field) + switch current.Kind() { -// switch st.Kind() { + case reflect.Struct: -// case reflect.String: + if current.Type() == timeType || current.Type() == timePtrType { + break + } -// return st.String() == param + current = current.FieldByName(param) -// case reflect.Slice, reflect.Map, reflect.Array: -// p := asInt(param) + if current.Kind() == reflect.Invalid { + panic(fmt.Sprintf("Field \"%s\" not found in struct", param)) + } + } -// return int64(st.Len()) == p + if current.Kind() == reflect.Ptr && !current.IsNil() { + current = current.Elem() + } -// case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: -// p := asInt(param) + switch fieldKind { -// return st.Int() == p + case reflect.String: + return field.String() == current.String() -// case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: -// p := asUint(param) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return field.Int() == current.Int() -// return st.Uint() == p + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return field.Uint() == current.Uint() -// case reflect.Float32, reflect.Float64: -// p := asFloat(param) + case reflect.Float32, reflect.Float64: + return field.Float() == current.Float() -// return st.Float() == p -// } + case reflect.Slice, reflect.Map, reflect.Array: + return int64(field.Len()) == int64(current.Len()) -// panic(fmt.Sprintf("Bad field type %T", field)) -// } + case reflect.Struct: + if fieldType == timeType || fieldType == timePtrType { -// func isBase64(top interface{}, current interface{}, field interface{}, param string) bool { -// return matchesRegex(base64Regex, field) -// } + if current.Type() != timeType && current.Type() != timePtrType { + panic("Bad Top Level field type") + } -// func isURI(top interface{}, current interface{}, field interface{}, param string) bool { + t := current.Interface().(time.Time) + fieldTime := field.Interface().(time.Time) -// st := reflect.ValueOf(field) + return fieldTime.Equal(t) + } + } -// switch st.Kind() { + panic(fmt.Sprintf("Bad field type %T", field.Interface())) +} -// case reflect.String: -// _, err := url.ParseRequestURI(field.(string)) +func isEq(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { -// return err == nil -// } + switch fieldKind { -// panic(fmt.Sprintf("Bad field type %T", field)) -// } + case reflect.String: + return field.String() == param -// func isURL(top interface{}, current interface{}, field interface{}, param string) bool { -// st := reflect.ValueOf(field) + case reflect.Slice, reflect.Map, reflect.Array: + p := asInt(param) -// switch st.Kind() { + return int64(field.Len()) == p -// case reflect.String: -// url, err := url.ParseRequestURI(field.(string)) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + p := asInt(param) -// if err != nil { -// return false -// } + return field.Int() == p -// if len(url.Scheme) == 0 { -// return false -// } + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + p := asUint(param) -// return err == nil -// } + return field.Uint() == p -// panic(fmt.Sprintf("Bad field type %T", field)) -// } + case reflect.Float32, reflect.Float64: + p := asFloat(param) -// func isEmail(top interface{}, current interface{}, field interface{}, param string) bool { -// return matchesRegex(emailRegex, field) -// } + return field.Float() == p + } -// func isHsla(top interface{}, current interface{}, field interface{}, param string) bool { -// return matchesRegex(hslaRegex, field) -// } + panic(fmt.Sprintf("Bad field type %T", field.Interface())) +} -// func isHsl(top interface{}, current interface{}, field interface{}, param string) bool { -// return matchesRegex(hslRegex, field) -// } +func isBase64(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + return matchesRegex(base64Regex, field.String()) +} -// func isRgba(top interface{}, current interface{}, field interface{}, param string) bool { -// return matchesRegex(rgbaRegex, field) -// } +func isURI(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { -// func isRgb(top interface{}, current interface{}, field interface{}, param string) bool { -// return matchesRegex(rgbRegex, field) -// } + switch fieldKind { -// func isHexcolor(top interface{}, current interface{}, field interface{}, param string) bool { -// return matchesRegex(hexcolorRegex, field) -// } + case reflect.String: + _, err := url.ParseRequestURI(field.String()) -// func isHexadecimal(top interface{}, current interface{}, field interface{}, param string) bool { -// return matchesRegex(hexadecimalRegex, field) -// } + return err == nil + } -// func isNumber(top interface{}, current interface{}, field interface{}, param string) bool { -// return matchesRegex(numberRegex, field) -// } + panic(fmt.Sprintf("Bad field type %T", field.Interface())) +} -// func isNumeric(top interface{}, current interface{}, field interface{}, param string) bool { -// return matchesRegex(numericRegex, field) -// } +func isURL(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { -// func isAlphanum(top interface{}, current interface{}, field interface{}, param string) bool { -// return matchesRegex(alphaNumericRegex, field) -// } + switch fieldKind { -// func isAlpha(top interface{}, current interface{}, field interface{}, param string) bool { -// return matchesRegex(alphaRegex, field) -// } + case reflect.String: + url, err := url.ParseRequestURI(field.String()) -func hasValue(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + if err != nil { + return false + } - // st := reflect.ValueOf(field) + if len(url.Scheme) == 0 { + return false + } - switch fieldKind { + return err == nil + } - case reflect.Slice, reflect.Map, reflect.Array: - return !field.IsNil() && int64(field.Len()) > 0 + panic(fmt.Sprintf("Bad field type %T", field.Interface())) +} - default: - return field.IsValid() && field != reflect.Zero(fieldType).Interface() - } +func isEmail(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + return matchesRegex(emailRegex, field.String()) } -// func isGteField(top interface{}, current interface{}, field interface{}, param string) bool { +func isHsla(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + return matchesRegex(hslaRegex, field.String()) +} -// if current == nil { -// panic("struct not passed for cross validation") -// } +func isHsl(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + return matchesRegex(hslRegex, field.String()) +} -// currentVal := reflect.ValueOf(current) +func isRgba(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + return matchesRegex(rgbaRegex, field.String()) +} -// if currentVal.Kind() == reflect.Ptr && !currentVal.IsNil() { -// currentVal = reflect.ValueOf(currentVal.Elem().Interface()) -// } +func isRgb(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + return matchesRegex(rgbRegex, field.String()) +} -// var currentFielVal reflect.Value +func isHexcolor(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + return matchesRegex(hexcolorRegex, field.String()) +} -// switch currentVal.Kind() { +func isHexadecimal(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + return matchesRegex(hexadecimalRegex, field.String()) +} -// case reflect.Struct: +func isNumber(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + return matchesRegex(numberRegex, field.String()) +} -// if currentVal.Type() == reflect.TypeOf(time.Time{}) { -// currentFielVal = currentVal -// break -// } +func isNumeric(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + return matchesRegex(numericRegex, field.String()) +} -// f := currentVal.FieldByName(param) +func isAlphanum(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + return matchesRegex(alphaNumericRegex, field.String()) +} -// if f.Kind() == reflect.Invalid { -// panic(fmt.Sprintf("Field \"%s\" not found in struct", param)) -// } +func isAlpha(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + return matchesRegex(alphaRegex, field.String()) +} -// currentFielVal = f +func hasValue(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { -// default: + switch fieldKind { -// currentFielVal = currentVal -// } + case reflect.Slice, reflect.Map, reflect.Array: + return !field.IsNil() && int64(field.Len()) > 0 -// if currentFielVal.Kind() == reflect.Ptr && !currentFielVal.IsNil() { + default: + return field.IsValid() && field != reflect.Zero(fieldType).Interface() + } +} -// currentFielVal = reflect.ValueOf(currentFielVal.Elem().Interface()) -// } +func isGteField(topStruct reflect.Value, current reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { -// fv := reflect.ValueOf(field) + if !current.IsValid() { + panic("struct not passed for cross validation") + } -// switch fv.Kind() { + if current.Kind() == reflect.Ptr && !current.IsNil() { + current = current.Elem() + } -// case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + switch current.Kind() { -// return fv.Int() >= currentFielVal.Int() + case reflect.Struct: -// case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + if current.Type() == timeType || current.Type() == timePtrType { + break + } -// return fv.Uint() >= currentFielVal.Uint() + current = current.FieldByName(param) -// case reflect.Float32, reflect.Float64: + if current.Kind() == reflect.Invalid { + panic(fmt.Sprintf("Field \"%s\" not found in struct", param)) + } + } -// return fv.Float() >= currentFielVal.Float() + if current.Kind() == reflect.Ptr && !current.IsNil() { + current = current.Elem() + } -// case reflect.Struct: + switch fieldKind { -// if fv.Type() == reflect.TypeOf(time.Time{}) { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: -// if currentFielVal.Type() != reflect.TypeOf(time.Time{}) { -// panic("Bad Top Level field type") -// } + return field.Int() >= current.Int() -// t := currentFielVal.Interface().(time.Time) -// fieldTime := field.(time.Time) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: -// return fieldTime.After(t) || fieldTime.Equal(t) -// } -// } + return field.Uint() >= current.Uint() -// panic(fmt.Sprintf("Bad field type %T", field)) -// } + case reflect.Float32, reflect.Float64: -// func isGtField(top interface{}, current interface{}, field interface{}, param string) bool { + return field.Float() >= current.Float() -// if current == nil { -// panic("struct not passed for cross validation") -// } + case reflect.Struct: -// currentVal := reflect.ValueOf(current) + if field.Type() == timeType || field.Type() == timePtrType { -// if currentVal.Kind() == reflect.Ptr && !currentVal.IsNil() { -// currentVal = reflect.ValueOf(currentVal.Elem().Interface()) -// } + if current.Type() != timeType && current.Type() != timePtrType { + panic("Bad Top Level field type") + } -// var currentFielVal reflect.Value + t := current.Interface().(time.Time) + fieldTime := field.Interface().(time.Time) -// switch currentVal.Kind() { + return fieldTime.After(t) || fieldTime.Equal(t) + } + } -// case reflect.Struct: + panic(fmt.Sprintf("Bad field type %T", field.Interface())) +} -// if currentVal.Type() == reflect.TypeOf(time.Time{}) { -// currentFielVal = currentVal -// break -// } +func isGtField(topStruct reflect.Value, current reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { -// f := currentVal.FieldByName(param) + if !current.IsValid() { + panic("struct not passed for cross validation") + } -// if f.Kind() == reflect.Invalid { -// panic(fmt.Sprintf("Field \"%s\" not found in struct", param)) -// } + if current.Kind() == reflect.Ptr && !current.IsNil() { + current = current.Elem() + } -// currentFielVal = f + switch current.Kind() { -// default: + case reflect.Struct: -// currentFielVal = currentVal -// } + if current.Type() == timeType || current.Type() == timePtrType { + break + } -// if currentFielVal.Kind() == reflect.Ptr && !currentFielVal.IsNil() { + current = current.FieldByName(param) -// currentFielVal = reflect.ValueOf(currentFielVal.Elem().Interface()) -// } + if current.Kind() == reflect.Invalid { + panic(fmt.Sprintf("Field \"%s\" not found in struct", param)) + } + } -// fv := reflect.ValueOf(field) + if current.Kind() == reflect.Ptr && !current.IsNil() { + current = current.Elem() + } -// switch fv.Kind() { + switch fieldKind { -// case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: -// return fv.Int() > currentFielVal.Int() + return field.Int() > current.Int() -// case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: -// return fv.Uint() > currentFielVal.Uint() + return field.Uint() > current.Uint() -// case reflect.Float32, reflect.Float64: + case reflect.Float32, reflect.Float64: -// return fv.Float() > currentFielVal.Float() + return field.Float() > current.Float() -// case reflect.Struct: + case reflect.Struct: -// if fv.Type() == reflect.TypeOf(time.Time{}) { + if field.Type() == timeType || field.Type() == timePtrType { -// if currentFielVal.Type() != reflect.TypeOf(time.Time{}) { -// panic("Bad Top Level field type") -// } + if current.Type() != timeType && current.Type() != timePtrType { + panic("Bad Top Level field type") + } -// t := currentFielVal.Interface().(time.Time) -// fieldTime := field.(time.Time) + t := current.Interface().(time.Time) + fieldTime := field.Interface().(time.Time) -// return fieldTime.After(t) -// } -// } + return fieldTime.After(t) + } + } -// panic(fmt.Sprintf("Bad field type %T", field)) -// } + 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 { @@ -624,46 +577,44 @@ func isGte(topStruct reflect.Value, currentStruct reflect.Value, field reflect.V panic(fmt.Sprintf("Bad field type %T", field.Interface())) } -// func isGt(top interface{}, current interface{}, field interface{}, param string) bool { +func isGt(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { -// st := reflect.ValueOf(field) - -// switch st.Kind() { + switch fieldKind { -// case reflect.String: -// p := asInt(param) + case reflect.String: + p := asInt(param) -// return int64(utf8.RuneCountInString(st.String())) > p + return int64(utf8.RuneCountInString(field.String())) > p -// case reflect.Slice, reflect.Map, reflect.Array: -// p := asInt(param) + case reflect.Slice, reflect.Map, reflect.Array: + p := asInt(param) -// return int64(st.Len()) > p + return int64(field.Len()) > p -// case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: -// p := asInt(param) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + p := asInt(param) -// return st.Int() > p + return field.Int() > p -// case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: -// p := asUint(param) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + p := asUint(param) -// return st.Uint() > p + return field.Uint() > p -// case reflect.Float32, reflect.Float64: -// p := asFloat(param) + case reflect.Float32, reflect.Float64: + p := asFloat(param) -// return st.Float() > p -// case reflect.Struct: + return field.Float() > p + case reflect.Struct: -// if st.Type() == reflect.TypeOf(time.Time{}) { + if field.Type() == timeType || field.Type() == timePtrType { -// return field.(time.Time).After(time.Now().UTC()) -// } -// } + return field.Interface().(time.Time).After(time.Now().UTC()) + } + } -// panic(fmt.Sprintf("Bad field type %T", field)) -// } + panic(fmt.Sprintf("Bad field type %T", field.Interface())) +} // length tests whether a variable's length is equal to a given // value. For strings it tests the number of characters whereas @@ -710,155 +661,127 @@ func hasMinOf(topStruct reflect.Value, currentStruct reflect.Value, field reflec return isGte(topStruct, currentStruct, field, fieldType, fieldKind, param) } -// func isLteField(top interface{}, current interface{}, field interface{}, param string) bool { - -// if current == nil { -// panic("struct not passed for cross validation") -// } - -// currentVal := reflect.ValueOf(current) - -// if currentVal.Kind() == reflect.Ptr && !currentVal.IsNil() { -// currentVal = reflect.ValueOf(currentVal.Elem().Interface()) -// } - -// var currentFielVal reflect.Value - -// switch currentVal.Kind() { - -// case reflect.Struct: - -// if currentVal.Type() == reflect.TypeOf(time.Time{}) { -// currentFielVal = currentVal -// break -// } +func isLteField(topStruct reflect.Value, current reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { -// f := currentVal.FieldByName(param) - -// if f.Kind() == reflect.Invalid { -// panic(fmt.Sprintf("Field \"%s\" not found in struct", param)) -// } - -// currentFielVal = f - -// default: - -// currentFielVal = currentVal -// } - -// if currentFielVal.Kind() == reflect.Ptr && !currentFielVal.IsNil() { - -// currentFielVal = reflect.ValueOf(currentFielVal.Elem().Interface()) -// } - -// fv := reflect.ValueOf(field) + if !current.IsValid() { + panic("struct not passed for cross validation") + } -// switch fv.Kind() { + if current.Kind() == reflect.Ptr && !current.IsNil() { + current = current.Elem() + } -// case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + switch current.Kind() { -// return fv.Int() <= currentFielVal.Int() + case reflect.Struct: -// case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + if current.Type() == timeType || current.Type() == timePtrType { + break + } -// return fv.Uint() <= currentFielVal.Uint() + current = current.FieldByName(param) -// case reflect.Float32, reflect.Float64: + if current.Kind() == reflect.Invalid { + panic(fmt.Sprintf("Field \"%s\" not found in struct", param)) + } + } -// return fv.Float() <= currentFielVal.Float() + if current.Kind() == reflect.Ptr && !current.IsNil() { + current = current.Elem() + } -// case reflect.Struct: + switch fieldKind { -// if fv.Type() == reflect.TypeOf(time.Time{}) { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: -// if currentFielVal.Type() != reflect.TypeOf(time.Time{}) { -// panic("Bad Top Level field type") -// } + return field.Int() <= current.Int() -// t := currentFielVal.Interface().(time.Time) -// fieldTime := field.(time.Time) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: -// return fieldTime.Before(t) || fieldTime.Equal(t) -// } -// } + return field.Uint() <= current.Uint() -// panic(fmt.Sprintf("Bad field type %T", field)) -// } + case reflect.Float32, reflect.Float64: -// func isLtField(top interface{}, current interface{}, field interface{}, param string) bool { + return field.Float() <= current.Float() -// if current == nil { -// panic("struct not passed for cross validation") -// } + case reflect.Struct: -// currentVal := reflect.ValueOf(current) + if field.Type() == timeType || field.Type() == timePtrType { -// if currentVal.Kind() == reflect.Ptr && !currentVal.IsNil() { -// currentVal = reflect.ValueOf(currentVal.Elem().Interface()) -// } + if current.Type() != timeType && current.Type() != timePtrType { + panic("Bad Top Level field type") + } -// var currentFielVal reflect.Value + t := current.Interface().(time.Time) + fieldTime := field.Interface().(time.Time) -// switch currentVal.Kind() { + return fieldTime.Before(t) || fieldTime.Equal(t) + } + } -// case reflect.Struct: + panic(fmt.Sprintf("Bad field type %T", field.Interface())) +} -// if currentVal.Type() == reflect.TypeOf(time.Time{}) { -// currentFielVal = currentVal -// break -// } +func isLtField(topStruct reflect.Value, current reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { -// f := currentVal.FieldByName(param) + if !current.IsValid() { + panic("struct not passed for cross validation") + } -// if f.Kind() == reflect.Invalid { -// panic(fmt.Sprintf("Field \"%s\" not found in struct", param)) -// } + if current.Kind() == reflect.Ptr && !current.IsNil() { + current = current.Elem() + } -// currentFielVal = f + switch current.Kind() { -// default: + case reflect.Struct: -// currentFielVal = currentVal -// } + if current.Type() == timeType || current.Type() == timePtrType { + break + } -// if currentFielVal.Kind() == reflect.Ptr && !currentFielVal.IsNil() { + current = current.FieldByName(param) -// currentFielVal = reflect.ValueOf(currentFielVal.Elem().Interface()) -// } + if current.Kind() == reflect.Invalid { + panic(fmt.Sprintf("Field \"%s\" not found in struct", param)) + } + } -// fv := reflect.ValueOf(field) + if current.Kind() == reflect.Ptr && !current.IsNil() { + current = current.Elem() + } -// switch fv.Kind() { + switch fieldKind { -// case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: -// return fv.Int() < currentFielVal.Int() + return field.Int() < current.Int() -// case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: -// return fv.Uint() < currentFielVal.Uint() + return field.Uint() < current.Uint() -// case reflect.Float32, reflect.Float64: + case reflect.Float32, reflect.Float64: -// return fv.Float() < currentFielVal.Float() + return field.Float() < current.Float() -// case reflect.Struct: + case reflect.Struct: -// if fv.Type() == reflect.TypeOf(time.Time{}) { + if field.Type() == timeType || field.Type() == timePtrType { -// if currentFielVal.Type() != reflect.TypeOf(time.Time{}) { -// panic("Bad Top Level field type") -// } + if current.Type() != timeType && current.Type() != timePtrType { + panic("Bad Top Level field type") + } -// t := currentFielVal.Interface().(time.Time) -// fieldTime := field.(time.Time) + t := current.Interface().(time.Time) + fieldTime := field.Interface().(time.Time) -// return fieldTime.Before(t) -// } -// } + return fieldTime.Before(t) + } + } -// panic(fmt.Sprintf("Bad field type %T", field)) -// } + 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 { @@ -903,47 +826,45 @@ func isLte(topStruct reflect.Value, currentStruct reflect.Value, field reflect.V panic(fmt.Sprintf("Bad field type %T", field.Interface())) } -// func isLt(top interface{}, current interface{}, field interface{}, param string) bool { +func isLt(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { -// st := reflect.ValueOf(field) - -// switch st.Kind() { + switch fieldKind { -// case reflect.String: -// p := asInt(param) + case reflect.String: + p := asInt(param) -// return int64(utf8.RuneCountInString(st.String())) < p + return int64(utf8.RuneCountInString(field.String())) < p -// case reflect.Slice, reflect.Map, reflect.Array: -// p := asInt(param) + case reflect.Slice, reflect.Map, reflect.Array: + p := asInt(param) -// return int64(st.Len()) < p + return int64(field.Len()) < p -// case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: -// p := asInt(param) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + p := asInt(param) -// return st.Int() < p + return field.Int() < p -// case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: -// p := asUint(param) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + p := asUint(param) -// return st.Uint() < p + return field.Uint() < p -// case reflect.Float32, reflect.Float64: -// p := asFloat(param) + case reflect.Float32, reflect.Float64: + p := asFloat(param) -// return st.Float() < p + return field.Float() < p -// case reflect.Struct: + case reflect.Struct: -// if st.Type() == reflect.TypeOf(time.Time{}) { + if field.Type() == timeType || field.Type() == timePtrType { -// return field.(time.Time).Before(time.Now().UTC()) -// } -// } + return field.Interface().(time.Time).Before(time.Now().UTC()) + } + } -// panic(fmt.Sprintf("Bad field type %T", field)) -// } + panic(fmt.Sprintf("Bad field type %T", field.Interface())) +} // max tests whether a variable value is lesser than a given // value. For numbers, it's a simple lesser-than test; for diff --git a/benchmarks_test.go b/benchmarks_test.go index b7f22d7..ee836c2 100644 --- a/benchmarks_test.go +++ b/benchmarks_test.go @@ -42,122 +42,122 @@ func BenchmarkTemplateParallelSimple(b *testing.B) { }) } -// func BenchmarkValidateStructLarge(b *testing.B) { - -// tFail := &TestString{ -// Required: "", -// Len: "", -// Min: "", -// Max: "12345678901", -// MinMax: "", -// Lt: "0123456789", -// Lte: "01234567890", -// Gt: "1", -// Gte: "1", -// OmitEmpty: "12345678901", -// Sub: &SubTest{ -// Test: "", -// }, -// Anonymous: struct { -// A string `validate:"required"` -// }{ -// A: "", -// }, -// Iface: &Impl{ -// F: "12", -// }, -// } - -// tSuccess := &TestString{ -// Required: "Required", -// Len: "length==10", -// Min: "min=1", -// Max: "1234567890", -// MinMax: "12345", -// Lt: "012345678", -// Lte: "0123456789", -// Gt: "01234567890", -// Gte: "0123456789", -// OmitEmpty: "", -// Sub: &SubTest{ -// Test: "1", -// }, -// SubIgnore: &SubTest{ -// Test: "", -// }, -// Anonymous: struct { -// A string `validate:"required"` -// }{ -// A: "1", -// }, -// Iface: &Impl{ -// F: "123", -// }, -// } - -// for n := 0; n < b.N; n++ { -// validate.Struct(tSuccess) -// validate.Struct(tFail) -// } -// } - -// func BenchmarkTemplateParallelLarge(b *testing.B) { - -// tFail := &TestString{ -// Required: "", -// Len: "", -// Min: "", -// Max: "12345678901", -// MinMax: "", -// Lt: "0123456789", -// Lte: "01234567890", -// Gt: "1", -// Gte: "1", -// OmitEmpty: "12345678901", -// Sub: &SubTest{ -// Test: "", -// }, -// Anonymous: struct { -// A string `validate:"required"` -// }{ -// A: "", -// }, -// Iface: &Impl{ -// F: "12", -// }, -// } - -// tSuccess := &TestString{ -// Required: "Required", -// Len: "length==10", -// Min: "min=1", -// Max: "1234567890", -// MinMax: "12345", -// Lt: "012345678", -// Lte: "0123456789", -// Gt: "01234567890", -// Gte: "0123456789", -// OmitEmpty: "", -// Sub: &SubTest{ -// Test: "1", -// }, -// SubIgnore: &SubTest{ -// Test: "", -// }, -// Anonymous: struct { -// A string `validate:"required"` -// }{ -// A: "1", -// }, -// Iface: &Impl{ -// F: "123", -// }, -// } - -// b.RunParallel(func(pb *testing.PB) { -// for pb.Next() { -// validate.Struct(tSuccess) -// validate.Struct(tFail) -// } -// }) -// } +func BenchmarkValidateStructLarge(b *testing.B) { + + tFail := &TestString{ + Required: "", + Len: "", + Min: "", + Max: "12345678901", + MinMax: "", + Lt: "0123456789", + Lte: "01234567890", + Gt: "1", + Gte: "1", + OmitEmpty: "12345678901", + Sub: &SubTest{ + Test: "", + }, + Anonymous: struct { + A string `validate:"required"` + }{ + A: "", + }, + Iface: &Impl{ + F: "12", + }, + } + + tSuccess := &TestString{ + Required: "Required", + Len: "length==10", + Min: "min=1", + Max: "1234567890", + MinMax: "12345", + Lt: "012345678", + Lte: "0123456789", + Gt: "01234567890", + Gte: "0123456789", + OmitEmpty: "", + Sub: &SubTest{ + Test: "1", + }, + SubIgnore: &SubTest{ + Test: "", + }, + Anonymous: struct { + A string `validate:"required"` + }{ + A: "1", + }, + Iface: &Impl{ + F: "123", + }, + } + + for n := 0; n < b.N; n++ { + validate.Struct(tSuccess) + validate.Struct(tFail) + } +} + +func BenchmarkTemplateParallelLarge(b *testing.B) { + + tFail := &TestString{ + Required: "", + Len: "", + Min: "", + Max: "12345678901", + MinMax: "", + Lt: "0123456789", + Lte: "01234567890", + Gt: "1", + Gte: "1", + OmitEmpty: "12345678901", + Sub: &SubTest{ + Test: "", + }, + Anonymous: struct { + A string `validate:"required"` + }{ + A: "", + }, + Iface: &Impl{ + F: "12", + }, + } + + tSuccess := &TestString{ + Required: "Required", + Len: "length==10", + Min: "min=1", + Max: "1234567890", + MinMax: "12345", + Lt: "012345678", + Lte: "0123456789", + Gt: "01234567890", + Gte: "0123456789", + OmitEmpty: "", + Sub: &SubTest{ + Test: "1", + }, + SubIgnore: &SubTest{ + Test: "", + }, + Anonymous: struct { + A string `validate:"required"` + }{ + A: "1", + }, + Iface: &Impl{ + F: "123", + }, + } + + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + validate.Struct(tSuccess) + validate.Struct(tFail) + } + }) +} diff --git a/regexes.go b/regexes.go index d3e8d80..e3f420e 100644 --- a/regexes.go +++ b/regexes.go @@ -58,7 +58,7 @@ var ( sSNRegex = regexp.MustCompile(sSNRegexString) ) -func matchesRegex(regex *regexp.Regexp, field interface{}) bool { - fieldAsString := field.(string) //this will panic inherently - return regex.MatchString(fieldAsString) +func matchesRegex(regex *regexp.Regexp, value string) bool { + // fieldAsString := field.(string) //this will panic inherently + return regex.MatchString(value) } diff --git a/validator.go b/validator.go index a71e652..28249c1 100644 --- a/validator.go +++ b/validator.go @@ -101,6 +101,28 @@ func New(config Config) *Validate { return &Validate{config: config} } +// Field allows validation of a single field, still using tag style validation to check multiple errors +func (v *Validate) Field(field interface{}, tag string) ValidationErrors { + + errs := map[string]*FieldError{} + fieldVal := reflect.ValueOf(field) + + v.traverseField(fieldVal, fieldVal, fieldVal, "", errs, false, tag, "") + + return errs +} + +// FieldWithValue allows validation of a single field, possibly even against another fields value, still using tag style validation to check multiple errors +func (v *Validate) FieldWithValue(val interface{}, field interface{}, tag string) ValidationErrors { + + errs := map[string]*FieldError{} + topVal := reflect.ValueOf(val) + + v.traverseField(topVal, topVal, reflect.ValueOf(field), "", errs, false, tag, "") + + return errs +} + // Struct validates a struct, even it's nested structs, and returns a struct containing the errors // NOTE: Nested Arrays, or Maps of structs do not get validated only the Array or Map itself; the reason is that there is no good // way to represent or report which struct within the array has the error, besides can validate the struct prior to adding it to @@ -141,30 +163,6 @@ func (v *Validate) tranverseStruct(topStruct reflect.Value, currentStruct reflec } } -// Field allows validation of a single field, still using tag style validation to check multiple errors -func (v *Validate) Field(field interface{}, tag string) ValidationErrors { - - errs := map[string]*FieldError{} - fieldVal := reflect.ValueOf(field) - - v.traverseField(fieldVal, fieldVal, fieldVal, "", errs, false, tag, "") - - return errs - - // return v.FieldWithValue(nil, field, tag) -} - -// FieldWithValue allows validation of a single field, possibly even against another fields value, still using tag style validation to check multiple errors -func (v *Validate) FieldWithValue(val interface{}, field interface{}, tag string) ValidationErrors { - - errs := map[string]*FieldError{} - topVal := reflect.ValueOf(val) - - v.traverseField(topVal, topVal, reflect.ValueOf(field), "", errs, false, tag, "") - - return errs -} - func (v *Validate) traverseField(topStruct reflect.Value, currentStruct reflect.Value, current reflect.Value, errPrefix string, errs ValidationErrors, isStructField bool, tag string, name string) { if tag == skipValidationTag { @@ -275,13 +273,13 @@ func (v *Validate) traverseField(topStruct reflect.Value, currentStruct reflect. // no use in checking tags if it's empty and is ok to be // omitempty needs to be the first tag if you wish to use it - if t == omitempty && !hasValue(topStruct, currentStruct, current, typ, kind, "") { - return - } + if t == omitempty { - // if strings.Contains(tag, omitempty) && !hasValue(topStruct, currentStruct, current, "") { - // return - // } + if !hasValue(topStruct, currentStruct, current, typ, kind, "") { + return + } + continue + } var key string var param string