func()

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
}