Code Cleanup + some renaming

pull/161/head
joeybloggs 9 years ago
parent 81e29d3724
commit d19088f865
  1. 64
      util.go
  2. 129
      validator.go
  3. 27
      validator_test.go

@ -6,7 +6,13 @@ import (
"strings" "strings"
) )
func (v *Validate) determineType(current reflect.Value) (reflect.Value, reflect.Kind) { const (
namespaceSeparator = "."
leftBracket = "["
rightBracket = "]"
)
func (v *Validate) extractType(current reflect.Value) (reflect.Value, reflect.Kind) {
switch current.Kind() { switch current.Kind() {
case reflect.Ptr: case reflect.Ptr:
@ -15,7 +21,7 @@ func (v *Validate) determineType(current reflect.Value) (reflect.Value, reflect.
return current, reflect.Ptr return current, reflect.Ptr
} }
return v.determineType(current.Elem()) return v.extractType(current.Elem())
case reflect.Interface: case reflect.Interface:
@ -23,7 +29,7 @@ func (v *Validate) determineType(current reflect.Value) (reflect.Value, reflect.
return current, reflect.Interface return current, reflect.Interface
} }
return v.determineType(current.Elem()) return v.extractType(current.Elem())
case reflect.Invalid: case reflect.Invalid:
@ -31,10 +37,9 @@ func (v *Validate) determineType(current reflect.Value) (reflect.Value, reflect.
default: default:
// fmt.Println(current.Kind())
if v.config.hasCustomFuncs { if v.config.hasCustomFuncs {
if fn, ok := v.config.CustomTypeFuncs[current.Type()]; ok { if fn, ok := v.config.CustomTypeFuncs[current.Type()]; ok {
return v.determineType(reflect.ValueOf(fn(current))) return v.extractType(reflect.ValueOf(fn(current)))
} }
} }
@ -44,14 +49,15 @@ func (v *Validate) determineType(current reflect.Value) (reflect.Value, reflect.
func (v *Validate) getStructFieldOK(current reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool) { func (v *Validate) getStructFieldOK(current reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool) {
// fmt.Println("NS:", namespace) current, kind := v.extractType(current)
current, kind := v.determineType(current)
// fmt.Println("getStructFieldOK - ", current, kind)
switch kind { switch kind {
case reflect.Ptr, reflect.Interface, reflect.Invalid: case reflect.Ptr, reflect.Interface, reflect.Invalid:
if len(namespace) == 0 {
return current, kind, true
}
return current, kind, false return current, kind, false
case reflect.Struct: case reflect.Struct:
@ -63,50 +69,34 @@ func (v *Validate) getStructFieldOK(current reflect.Value, namespace string) (re
idx := strings.Index(namespace, namespaceSeparator) idx := strings.Index(namespace, namespaceSeparator)
// fmt.Println("IDX:", namespace, idx)
if idx != -1 { if idx != -1 {
fld = namespace[:idx] fld = namespace[:idx]
} }
ns := namespace[idx+1:] ns := namespace[idx+1:]
bracketIdx := strings.Index(fld, "[") bracketIdx := strings.Index(fld, leftBracket)
if bracketIdx != -1 { if bracketIdx != -1 {
fld = fld[:bracketIdx] fld = fld[:bracketIdx]
// fmt.Println("NSS:", ns)
if idx == -1 { if idx == -1 {
ns = namespace[bracketIdx:] ns = namespace[bracketIdx:]
} else { } else {
ns = namespace[bracketIdx:] ns = namespace[bracketIdx:]
} }
// fmt.Println("NSS2:", ns)
} }
// fmt.Println("Looking for field:", fld)
current = current.FieldByName(fld) current = current.FieldByName(fld)
// fmt.Println("Current:", current)
return v.getStructFieldOK(current, ns) return v.getStructFieldOK(current, ns)
} }
case reflect.Array, reflect.Slice: case reflect.Array, reflect.Slice:
idx := strings.Index(namespace, "[") idx := strings.Index(namespace, leftBracket)
idx2 := strings.Index(namespace, "]") idx2 := strings.Index(namespace, rightBracket)
// idx3 := strings.Index(namespace, namespaceSeparator)
// if idx3 == -1 {
// idx3 = 0
// } else {
// idx3 = 1
// }
//
arrIdx, _ := strconv.Atoi(namespace[idx+1 : idx2]) arrIdx, _ := strconv.Atoi(namespace[idx+1 : idx2])
// fmt.Println("ArrayIndex:", arrIdx)
// fmt.Println("LEN:", current.Len())
if arrIdx >= current.Len() { if arrIdx >= current.Len() {
return current, kind, false return current, kind, false
} }
@ -114,7 +104,7 @@ func (v *Validate) getStructFieldOK(current reflect.Value, namespace string) (re
startIdx := idx2 + 1 startIdx := idx2 + 1
if startIdx < len(namespace) { if startIdx < len(namespace) {
if namespace[startIdx:startIdx+1] == "." { if namespace[startIdx:startIdx+1] == namespaceSeparator {
startIdx++ startIdx++
} }
} }
@ -122,27 +112,19 @@ func (v *Validate) getStructFieldOK(current reflect.Value, namespace string) (re
return v.getStructFieldOK(current.Index(arrIdx), namespace[startIdx:]) return v.getStructFieldOK(current.Index(arrIdx), namespace[startIdx:])
case reflect.Map: case reflect.Map:
idx := strings.Index(namespace, "[") + 1 idx := strings.Index(namespace, leftBracket) + 1
idx2 := strings.Index(namespace, "]") idx2 := strings.Index(namespace, rightBracket)
endIdx := idx2 endIdx := idx2
// fmt.Println("END IDX:", endIdx)
// fmt.Println("L NS:", len(namespace))
// fmt.Println("NS:", namespace)
if endIdx+1 < len(namespace) { if endIdx+1 < len(namespace) {
if namespace[endIdx+1:endIdx+2] == "." { if namespace[endIdx+1:endIdx+2] == namespaceSeparator {
endIdx++ endIdx++
} }
} }
// fmt.Println("KEY:", namespace[idx:idx2])
// fmt.Println("KEY NS:", namespace[endIdx+1:])
return v.getStructFieldOK(current.MapIndex(reflect.ValueOf(namespace[idx:idx2])), namespace[endIdx+1:]) return v.getStructFieldOK(current.MapIndex(reflect.ValueOf(namespace[idx:idx2])), namespace[endIdx+1:])
} }
// fmt.Println("Returning field")
return current, kind, true return current, kind, true
} }

@ -22,7 +22,6 @@ import (
const ( const (
utf8HexComma = "0x2C" utf8HexComma = "0x2C"
utf8Pipe = "0x7C" utf8Pipe = "0x7C"
namespaceSeparator = "."
tagSeparator = "," tagSeparator = ","
orSeparator = "|" orSeparator = "|"
tagKeySeparator = "=" tagKeySeparator = "="
@ -32,8 +31,8 @@ const (
diveTag = "dive" diveTag = "dive"
existsTag = "exists" existsTag = "exists"
fieldErrMsg = "Key: \"%s\" Error:Field validation for \"%s\" failed on the \"%s\" tag" fieldErrMsg = "Key: \"%s\" Error:Field validation for \"%s\" failed on the \"%s\" tag"
arrayIndexFieldName = "%s[%d]" arrayIndexFieldName = "%s" + leftBracket + "%d" + rightBracket
mapIndexFieldName = "%s[%v]" mapIndexFieldName = "%s" + leftBracket + "%v" + rightBracket
invalidValidation = "Invalid validation tag on field %s" invalidValidation = "Invalid validation tag on field %s"
undefinedValidation = "Undefined validation function on field %s" undefinedValidation = "Undefined validation function on field %s"
) )
@ -264,7 +263,7 @@ func (v *Validate) traverseField(topStruct reflect.Value, currentStruct reflect.
return return
} }
current, kind := v.determineType(current) current, kind := v.extractType(current)
var typ reflect.Type var typ reflect.Type
switch kind { switch kind {
@ -293,7 +292,6 @@ func (v *Validate) traverseField(topStruct reflect.Value, currentStruct reflect.
return return
} }
// fmt.Println(kind)
errs[errPrefix+name] = &FieldError{ errs[errPrefix+name] = &FieldError{
Field: name, Field: name,
Tag: vals[0], Tag: vals[0],
@ -314,7 +312,6 @@ func (v *Validate) traverseField(topStruct reflect.Value, currentStruct reflect.
typ = current.Type() typ = current.Type()
if typ != timeType && typ != timePtrType { if typ != timeType && typ != timePtrType {
// goto FALLTHROUGH
// required passed validation above so stop here // required passed validation above so stop here
// if only validating the structs existance. // if only validating the structs existance.
@ -325,13 +322,6 @@ func (v *Validate) traverseField(topStruct reflect.Value, currentStruct reflect.
v.tranverseStruct(topStruct, current, current, errPrefix+name+".", errs, false) v.tranverseStruct(topStruct, current, current, errPrefix+name+".", errs, false)
return return
} }
// FALLTHROUGH:
// fallthrough
// default:
// fmt.Println(tag)
// if len(tag) == 0 {
// return
// }
} }
if len(tag) == 0 { if len(tag) == 0 {
@ -339,119 +329,6 @@ func (v *Validate) traverseField(topStruct reflect.Value, currentStruct reflect.
} }
typ = current.Type() 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) tags, isCached := tagsCache.Get(tag)

@ -301,6 +301,33 @@ func TestCrossNamespaceFieldValidation(t *testing.T) {
Equal(t, ok, true) Equal(t, ok, true)
Equal(t, kind, reflect.String) Equal(t, kind, reflect.String)
Equal(t, current.String(), "9") Equal(t, current.String(), "9")
inner = &Inner{
CreatedAt: &now,
Slice: []string{"val1", "val2", "val3"},
SliceStructs: []*SliceStruct{{Name: "name1"}, {Name: "name2"}, nil},
SliceSlice: [][]string{{"1", "2", "3"}, {"4", "5", "6"}, {"7", "8", "9"}},
SliceSliceStruct: [][]*SliceStruct{{{Name: "name1"}, {Name: "name2"}, {Name: "name3"}}, {{Name: "name4"}, {Name: "name5"}, {Name: "name6"}}, {{Name: "name7"}, {Name: "name8"}, {Name: "name9"}}},
SliceMap: []map[string]string{{"key1": "val1", "key2": "val2", "key3": "val3"}, {"key4": "val4", "key5": "val5", "key6": "val6"}},
Map: map[string]string{"key1": "val1", "key2": "val2", "key3": "val3"},
MapStructs: map[string]*SliceStruct{"key1": {Name: "name1"}, "key2": {Name: "name2"}, "key3": {Name: "name3"}},
MapMap: map[string]map[string]string{"key1": {"key1-1": "val1"}, "key2": {"key2-1": "val2"}, "key3": {"key3-1": "val3"}},
MapMapStruct: map[string]map[string]*SliceStruct{"key1": {"key1-1": {Name: "name1"}}, "key2": {"key2-1": {Name: "name2"}}, "key3": {"key3-1": {Name: "name3"}}},
MapSlice: map[string][]string{"key1": {"1", "2", "3"}, "key2": {"4", "5", "6"}, "key3": {"7", "8", "9"}},
}
test = &Test{
Inner: inner,
CreatedAt: nil,
}
val = reflect.ValueOf(test)
current, kind, ok = validate.getStructFieldOK(val, "Inner.SliceStructs[2]")
Equal(t, ok, true)
Equal(t, kind, reflect.Ptr)
Equal(t, current.String(), "<*validator.SliceStruct Value>")
Equal(t, current.IsNil(), true)
} }
func TestExistsValidation(t *testing.T) { func TestExistsValidation(t *testing.T) {

Loading…
Cancel
Save