|
|
|
package validator
|
|
|
|
|
|
|
|
import (
|
|
|
|
"reflect"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
namespaceSeparator = "."
|
|
|
|
leftBracket = "["
|
|
|
|
rightBracket = "]"
|
|
|
|
)
|
|
|
|
|
|
|
|
func (v *Validate) extractType(current reflect.Value) (reflect.Value, reflect.Kind) {
|
|
|
|
|
|
|
|
switch current.Kind() {
|
|
|
|
case reflect.Ptr:
|
|
|
|
|
|
|
|
if current.IsNil() {
|
|
|
|
return current, reflect.Ptr
|
|
|
|
}
|
|
|
|
|
|
|
|
return v.extractType(current.Elem())
|
|
|
|
|
|
|
|
case reflect.Interface:
|
|
|
|
|
|
|
|
if current.IsNil() {
|
|
|
|
return current, reflect.Interface
|
|
|
|
}
|
|
|
|
|
|
|
|
return v.extractType(current.Elem())
|
|
|
|
|
|
|
|
case reflect.Invalid:
|
|
|
|
|
|
|
|
return current, reflect.Invalid
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
if v.config.hasCustomFuncs {
|
|
|
|
if fn, ok := v.config.CustomTypeFuncs[current.Type()]; ok {
|
|
|
|
return v.extractType(reflect.ValueOf(fn(current)))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return current, current.Kind()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *Validate) getStructFieldOK(current reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool) {
|
|
|
|
|
|
|
|
current, kind := v.extractType(current)
|
|
|
|
|
|
|
|
// fmt.Println("SOK:", current, kind, namespace)
|
|
|
|
|
|
|
|
// if len(namespace) == 0 {
|
|
|
|
// // if kind == reflect.Invalid {
|
|
|
|
// // return current, kind, false
|
|
|
|
// // }
|
|
|
|
// return current, kind, true
|
|
|
|
// }
|
|
|
|
|
|
|
|
if kind == reflect.Invalid {
|
|
|
|
return current, kind, false
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(namespace) == 0 {
|
|
|
|
return current, kind, true
|
|
|
|
}
|
|
|
|
|
|
|
|
switch kind {
|
|
|
|
// case reflect.Invalid:
|
|
|
|
// return current, kind, false
|
|
|
|
|
|
|
|
case reflect.Ptr, reflect.Interface:
|
|
|
|
|
|
|
|
return current, kind, false
|
|
|
|
|
|
|
|
case reflect.Struct:
|
|
|
|
|
|
|
|
typ := current.Type()
|
|
|
|
fld := namespace
|
|
|
|
ns := namespace
|
|
|
|
|
|
|
|
if typ != timeType && typ != timePtrType {
|
|
|
|
|
|
|
|
idx := strings.Index(namespace, namespaceSeparator)
|
|
|
|
|
|
|
|
if idx != -1 {
|
|
|
|
fld = namespace[:idx]
|
|
|
|
ns = namespace[idx+1:]
|
|
|
|
} else {
|
|
|
|
ns = ""
|
|
|
|
idx = len(namespace)
|
|
|
|
}
|
|
|
|
|
|
|
|
// ns := namespace[idx+1:]
|
|
|
|
|
|
|
|
bracketIdx := strings.Index(fld, leftBracket)
|
|
|
|
if bracketIdx != -1 {
|
|
|
|
fld = fld[:bracketIdx]
|
|
|
|
|
|
|
|
ns = namespace[bracketIdx:]
|
|
|
|
// if idx == -1 {
|
|
|
|
// ns = namespace[bracketIdx:]
|
|
|
|
// } else {
|
|
|
|
// ns = namespace[bracketIdx:]
|
|
|
|
// }
|
|
|
|
}
|
|
|
|
|
|
|
|
current = current.FieldByName(fld)
|
|
|
|
|
|
|
|
// if current.Kind() == reflect.Invalid {
|
|
|
|
// return current, reflect.Invalid, false
|
|
|
|
// }
|
|
|
|
|
|
|
|
// fmt.Println("NS:", ns, idx)
|
|
|
|
|
|
|
|
return v.getStructFieldOK(current, ns)
|
|
|
|
}
|
|
|
|
|
|
|
|
case reflect.Array, reflect.Slice:
|
|
|
|
idx := strings.Index(namespace, leftBracket)
|
|
|
|
idx2 := strings.Index(namespace, rightBracket)
|
|
|
|
|
|
|
|
arrIdx, _ := strconv.Atoi(namespace[idx+1 : idx2])
|
|
|
|
|
|
|
|
if arrIdx >= current.Len() {
|
|
|
|
return current, kind, false
|
|
|
|
}
|
|
|
|
|
|
|
|
startIdx := idx2 + 1
|
|
|
|
|
|
|
|
if startIdx < len(namespace) {
|
|
|
|
if namespace[startIdx:startIdx+1] == namespaceSeparator {
|
|
|
|
startIdx++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return v.getStructFieldOK(current.Index(arrIdx), namespace[startIdx:])
|
|
|
|
|
|
|
|
case reflect.Map:
|
|
|
|
idx := strings.Index(namespace, leftBracket) + 1
|
|
|
|
idx2 := strings.Index(namespace, rightBracket)
|
|
|
|
|
|
|
|
endIdx := idx2
|
|
|
|
|
|
|
|
if endIdx+1 < len(namespace) {
|
|
|
|
if namespace[endIdx+1:endIdx+2] == namespaceSeparator {
|
|
|
|
endIdx++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return v.getStructFieldOK(current.MapIndex(reflect.ValueOf(namespace[idx:idx2])), namespace[endIdx+1:])
|
|
|
|
}
|
|
|
|
|
|
|
|
// if got here there was more namespace, cannot go any deeper
|
|
|
|
panic("Invalid field namespace")
|
|
|
|
// return current, kind, false
|
|
|
|
}
|