|
|
|
@ -7,6 +7,12 @@ import (
|
|
|
|
|
"sync"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type ValidateValuer interface {
|
|
|
|
|
ValidateValue() interface{}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var vvType = reflect.TypeOf((*ValidateValuer)(nil)).Elem()
|
|
|
|
|
|
|
|
|
|
// Validate validates a variable
|
|
|
|
|
func Validate(v interface{}) []ValidationError {
|
|
|
|
|
rv := reflect.ValueOf(v)
|
|
|
|
@ -160,7 +166,14 @@ func getRules(rt reflect.Type) []rule {
|
|
|
|
|
for i := 0; i < rt.NumField(); i++ {
|
|
|
|
|
ft := rt.Field(i)
|
|
|
|
|
|
|
|
|
|
kind := ft.Type.Kind()
|
|
|
|
|
var valuer bool
|
|
|
|
|
if ft.Type.Implements(vvType) {
|
|
|
|
|
ft.Type = reflect.TypeOf(reflect.New(ft.Type).Interface().(ValidateValuer).ValidateValue())
|
|
|
|
|
valuer = true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
kind := simplifyKind(ft.Type.Kind())
|
|
|
|
|
|
|
|
|
|
var ptr bool
|
|
|
|
|
if kind == reflect.Ptr {
|
|
|
|
|
kind = ft.Type.Elem().Kind()
|
|
|
|
@ -169,9 +182,7 @@ func getRules(rt reflect.Type) []rule {
|
|
|
|
|
kind = simplifyKind(kind)
|
|
|
|
|
|
|
|
|
|
tags := strings.Split(ft.Tag.Get(`validate`), `,`)
|
|
|
|
|
rules = append(rules, getTagFuncs(i, ft, kind, tags, ptr)...)
|
|
|
|
|
|
|
|
|
|
// TODO: Add validator interface
|
|
|
|
|
rules = append(rules, getTagFuncs(i, ft, kind, tags, ptr, valuer)...)
|
|
|
|
|
|
|
|
|
|
switch kind {
|
|
|
|
|
case reflect.Slice, reflect.Struct, reflect.Interface:
|
|
|
|
@ -192,7 +203,7 @@ func nest(ft reflect.StructField) func(reflect.Value) ([]ValidationError, bool)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func getTagFuncs(i int, ft reflect.StructField, kind reflect.Kind, tags []string, ptr bool) []rule {
|
|
|
|
|
func getTagFuncs(i int, ft reflect.StructField, kind reflect.Kind, tags []string, ptr, valuer bool) []rule {
|
|
|
|
|
var rules []rule
|
|
|
|
|
for _, v := range tags {
|
|
|
|
|
if v == `` {
|
|
|
|
@ -212,46 +223,62 @@ func getTagFuncs(i int, ft reflect.StructField, kind reflect.Kind, tags []string
|
|
|
|
|
ptr = false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var f validateCheck
|
|
|
|
|
|
|
|
|
|
if tag == `optional` {
|
|
|
|
|
rules = append(rules, rule{i, func(rv reflect.Value) ([]ValidationError, bool) {
|
|
|
|
|
f = func(rv reflect.Value) ([]ValidationError, bool) {
|
|
|
|
|
check, _ := getTagFunc(`required`, ``, kind)
|
|
|
|
|
return nil, check(rv, nil)
|
|
|
|
|
}})
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var not bool
|
|
|
|
|
if strings.HasPrefix(tag, `!`) {
|
|
|
|
|
not = true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
check, val := getTagFunc(strings.TrimPrefix(tag, `!`), value, kind)
|
|
|
|
|
|
|
|
|
|
f := func(rv reflect.Value) ([]ValidationError, bool) {
|
|
|
|
|
if check(rv, val) == !not {
|
|
|
|
|
return nil, true
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
var not bool
|
|
|
|
|
if strings.HasPrefix(tag, `!`) {
|
|
|
|
|
not = true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return []ValidationError{{Field: []Field{{nil, &ft}}, Check: tag, Value: value}}, false
|
|
|
|
|
}
|
|
|
|
|
check, val := getTagFunc(strings.TrimPrefix(tag, `!`), value, kind)
|
|
|
|
|
|
|
|
|
|
if ptr {
|
|
|
|
|
oldF := f
|
|
|
|
|
f = func(rv reflect.Value) ([]ValidationError, bool) {
|
|
|
|
|
if rv.IsNil() {
|
|
|
|
|
return []ValidationError{{Field: []Field{{nil, &ft}}, Check: tag, Value: value}}, false
|
|
|
|
|
if check(rv, val) == !not {
|
|
|
|
|
return nil, true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return oldF(rv.Elem())
|
|
|
|
|
return []ValidationError{{Field: []Field{{nil, &ft}}, Check: tag, Value: value}}, false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ptr {
|
|
|
|
|
f = depointerFunc(f, ft, tag, value)
|
|
|
|
|
}
|
|
|
|
|
if valuer {
|
|
|
|
|
f = valuerFunc(f)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rules = append(rules, rule{i, f})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return rules
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type validateCheck = func(rv reflect.Value) ([]ValidationError, bool)
|
|
|
|
|
|
|
|
|
|
func depointerFunc(f validateCheck, ft reflect.StructField, tag, value string) validateCheck {
|
|
|
|
|
return func(rv reflect.Value) ([]ValidationError, bool) {
|
|
|
|
|
if rv.IsNil() {
|
|
|
|
|
return []ValidationError{{Field: []Field{{nil, &ft}}, Check: tag, Value: value}}, false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return f(rv.Elem())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func valuerFunc(f validateCheck) validateCheck {
|
|
|
|
|
return func(rv reflect.Value) ([]ValidationError, bool) {
|
|
|
|
|
rv = reflect.ValueOf(rv.Interface().(ValidateValuer).ValidateValue())
|
|
|
|
|
return f(rv)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func getTagFunc(tag, value string, kind reflect.Kind) (ValidationFunc, interface{}) {
|
|
|
|
|
tagInfo, ok := funcs[tag]
|
|
|
|
|
if !ok {
|
|
|
|
|