💯Go Struct and Field validation, including Cross Field, Cross Struct, Map, Slice and Array diving
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
validator/util.go

149 lines
3.0 KiB

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[bracketIdx:]
}
// fmt.Println("NSS2:", ns)
}
// 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, "]")
// idx3 := strings.Index(namespace, namespaceSeparator)
// if idx3 == -1 {
// idx3 = 0
// } else {
// idx3 = 1
// }
//
arrIdx, _ := strconv.Atoi(namespace[idx+1 : idx2])
// fmt.Println("ArrayIndex:", arrIdx)
// fmt.Println("LEN:", current.Len())
if arrIdx >= current.Len() {
return current, kind, false
}
startIdx := idx2 + 1
if startIdx < len(namespace) {
if namespace[startIdx:startIdx+1] == "." {
startIdx++
}
}
return v.getStructFieldOK(current.Index(arrIdx), namespace[startIdx:])
case reflect.Map:
idx := strings.Index(namespace, "[") + 1
idx2 := strings.Index(namespace, "]")
endIdx := idx2
// fmt.Println("END IDX:", endIdx)
// fmt.Println("L NS:", len(namespace))
// fmt.Println("NS:", namespace)
if endIdx+1 < len(namespace) {
if namespace[endIdx+1:endIdx+2] == "." {
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:])
}
// fmt.Println("Returning field")
return current, kind, true
}