in pkg/validate/validator.go [103:179]
func (v *Validator) Validate(s interface{}) error {
sv := reflect.ValueOf(s)
k := sv.Kind()
switch k {
case reflect.Ptr:
if !sv.IsNil() {
return v.Validate(sv.Elem().Interface())
}
return errors.New("invalid nil pointer")
case reflect.Struct:
default:
return fmt.Errorf("not support validate type '%s'", k)
}
st := util.Reflect(s)
for i, l := 0, sv.NumField(); i < l; i++ {
field := sv.Field(i)
fieldName := st.Fields[i].Name
rule, ok := v.rules[fieldName]
subV, sub := v.subs[fieldName]
fi := field.Interface()
if field.Kind() == reflect.Ptr && !field.IsNil() {
fi = field.Elem().Interface()
field = reflect.ValueOf(fi)
}
if ok {
// check current rule
// if pointer, check it's a nil pointer or not
// if array, slice and map, check the length and regex
// if sub type is not a string when do regex check, return OK
ok, invalidValue := rule.Match(fi)
if !ok {
if rule.Hide {
return fmt.Errorf("field '%s.%s' does not match rule: %s", st.Type.Name(), fieldName, rule)
}
return fmt.Errorf("field '%s.%s' invalid value '%v' does not match rule: %s", st.Type.Name(), fieldName, invalidValue, rule)
}
}
if sub {
// check sub rule
// do not support sub type is not pointer or struct
switch field.Kind() {
case reflect.Struct:
if !sub {
continue
}
if err := subV.Validate(fi); err != nil {
return err
}
case reflect.Array, reflect.Slice:
if !sub {
break
}
for i, l := 0, field.Len(); i < l; i++ {
if err := subV.Validate(field.Index(i).Interface()); err != nil {
return err
}
}
case reflect.Map:
if !sub {
break
}
keys := field.MapKeys()
for _, key := range keys {
// TODO how to validate non-base type key
if err := subV.Validate(field.MapIndex(key).Interface()); err != nil {
return err
}
}
}
}
}
return nil
}