diff --git a/baked_in.go b/baked_in.go index b9d2286..92b4611 100644 --- a/baked_in.go +++ b/baked_in.go @@ -13,9 +13,9 @@ import ( // or even disregard and use your own map if so desired. var BakedInValidators = map[string]Func{ "required": hasValue, - // "len": hasLengthOf, - "min": hasMinOf, - "max": hasMaxOf, + "len": hasLengthOf, + "min": hasMinOf, + "max": hasMaxOf, // "eq": isEq, // "ne": isNe, // "lt": isLt, @@ -621,7 +621,7 @@ func isGte(topStruct reflect.Value, currentStruct reflect.Value, field reflect.V } } - panic(fmt.Sprintf("Bad field type %T", field)) + panic(fmt.Sprintf("Bad field type %T", field.Interface())) } // func isGt(top interface{}, current interface{}, field interface{}, param string) bool { @@ -665,43 +665,41 @@ func isGte(topStruct reflect.Value, currentStruct reflect.Value, field reflect.V // panic(fmt.Sprintf("Bad field type %T", field)) // } -// // 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(top interface{}, current interface{}, field interface{}, param string) bool { +// 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 { -// st := reflect.ValueOf(field) + switch fieldKind { -// switch st.Kind() { + case reflect.String: + p := asInt(param) -// case reflect.String: -// p := asInt(param) + return int64(utf8.RuneCountInString(field.String())) == p -// return int64(utf8.RuneCountInString(st.String())) == p + case reflect.Slice, reflect.Map, reflect.Array: + p := asInt(param) -// case reflect.Slice, reflect.Map, reflect.Array: -// p := asInt(param) + return int64(field.Len()) == p -// return int64(st.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 field.Int() == p -// return st.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 + } -// panic(fmt.Sprintf("Bad field type %T", field)) -// } + panic(fmt.Sprintf("Bad field type %T", field.Interface())) +} // min tests whether a variable value is larger or equal to a given // number. For number types, it's a simple lesser-than test; for @@ -902,7 +900,7 @@ func isLte(topStruct reflect.Value, currentStruct reflect.Value, field reflect.V } } - panic(fmt.Sprintf("Bad field type %T", field)) + panic(fmt.Sprintf("Bad field type %T", field.Interface())) } // func isLt(top interface{}, current interface{}, field interface{}, param string) bool { diff --git a/benchmarks_test.go b/benchmarks_test.go index 8f09908..b7f22d7 100644 --- a/benchmarks_test.go +++ b/benchmarks_test.go @@ -2,11 +2,11 @@ package validator import "testing" -// func BenchmarkValidateField(b *testing.B) { -// for n := 0; n < b.N; n++ { -// validate.Field("1", "len=1") -// } -// } +func BenchmarkValidateField(b *testing.B) { + for n := 0; n < b.N; n++ { + validate.Field("1", "len=1") + } +} func BenchmarkValidateStructSimple(b *testing.B) { diff --git a/validator.go b/validator.go index cd05aa2..a71e652 100644 --- a/validator.go +++ b/validator.go @@ -141,6 +141,30 @@ 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 {