| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221 | 
							- package valid
 
- import (
 
- 	"context"
 
- 	"fmt"
 
- 	"reflect"
 
- 	"strconv"
 
- )
 
- var (
 
- 	validatableType            = reflect.TypeOf((*Validatable)(nil)).Elem()
 
- 	validatableWithContextType = reflect.TypeOf((*ValidatableWithContext)(nil)).Elem()
 
- )
 
- // Validate validates the given value and returns the validation error, if any.
 
- //
 
- // Validate performs validation using the following steps:
 
- // 1. For each rule, call its `Validate()` to validate the value. Return if any error is found.
 
- // 2. If the value being validated implements `Validatable`, call the value's `Validate()`.
 
- //    Return with the validation result.
 
- // 3. If the value being validated is a map/slice/array, and the element type implements `Validatable`,
 
- //    for each element call the element value's `Validate()`. Return with the validation result.
 
- func Validate(value interface{}, rules ...Rule) error {
 
- 	for _, rule := range rules {
 
- 		if s, ok := rule.(skipRule); ok && s.skip {
 
- 			return nil
 
- 		}
 
- 		if err := rule.Validate(value); err != nil {
 
- 			return err
 
- 		}
 
- 	}
 
- 	rv := reflect.ValueOf(value)
 
- 	if (rv.Kind() == reflect.Ptr || rv.Kind() == reflect.Interface) && rv.IsNil() {
 
- 		return nil
 
- 	}
 
- 	if v, ok := value.(Validatable); ok {
 
- 		return v.Validate()
 
- 	}
 
- 	switch rv.Kind() {
 
- 	case reflect.Map:
 
- 		if rv.Type().Elem().Implements(validatableType) {
 
- 			return validateMap(rv)
 
- 		}
 
- 	case reflect.Slice, reflect.Array:
 
- 		if rv.Type().Elem().Implements(validatableType) {
 
- 			return validateSlice(rv)
 
- 		}
 
- 	case reflect.Ptr, reflect.Interface:
 
- 		return Validate(rv.Elem().Interface())
 
- 	}
 
- 	return nil
 
- }
 
- // ValidateWithContext validates the given value with the given context and returns the validation error, if any.
 
- //
 
- // ValidateWithContext performs validation using the following steps:
 
- // 1. For each rule, call its `ValidateWithContext()` to validate the value if the rule implements `RuleWithContext`.
 
- //    Otherwise call `Validate()` of the rule. Return if any error is found.
 
- // 2. If the value being validated implements `ValidatableWithContext`, call the value's `ValidateWithContext()`
 
- //    and return with the validation result.
 
- // 3. If the value being validated implements `Validatable`, call the value's `Validate()`
 
- //    and return with the validation result.
 
- // 4. If the value being validated is a map/slice/array, and the element type implements `ValidatableWithContext`,
 
- //    for each element call the element value's `ValidateWithContext()`. Return with the validation result.
 
- // 5. If the value being validated is a map/slice/array, and the element type implements `Validatable`,
 
- //    for each element call the element value's `Validate()`. Return with the validation result.
 
- func ValidateWithContext(ctx context.Context, value interface{}, rules ...Rule) error {
 
- 	for _, rule := range rules {
 
- 		if s, ok := rule.(skipRule); ok && s.skip {
 
- 			return nil
 
- 		}
 
- 		if rc, ok := rule.(RuleWithContext); ok {
 
- 			if err := rc.ValidateWithContext(ctx, value); err != nil {
 
- 				return err
 
- 			}
 
- 		} else if err := rule.Validate(value); err != nil {
 
- 			return err
 
- 		}
 
- 	}
 
- 	rv := reflect.ValueOf(value)
 
- 	if (rv.Kind() == reflect.Ptr || rv.Kind() == reflect.Interface) && rv.IsNil() {
 
- 		return nil
 
- 	}
 
- 	if v, ok := value.(ValidatableWithContext); ok {
 
- 		return v.ValidateWithContext(ctx)
 
- 	}
 
- 	if v, ok := value.(Validatable); ok {
 
- 		return v.Validate()
 
- 	}
 
- 	switch rv.Kind() {
 
- 	case reflect.Map:
 
- 		if rv.Type().Elem().Implements(validatableWithContextType) {
 
- 			return validateMapWithContext(ctx, rv)
 
- 		}
 
- 		if rv.Type().Elem().Implements(validatableType) {
 
- 			return validateMap(rv)
 
- 		}
 
- 	case reflect.Slice, reflect.Array:
 
- 		if rv.Type().Elem().Implements(validatableWithContextType) {
 
- 			return validateSliceWithContext(ctx, rv)
 
- 		}
 
- 		if rv.Type().Elem().Implements(validatableType) {
 
- 			return validateSlice(rv)
 
- 		}
 
- 	case reflect.Ptr, reflect.Interface:
 
- 		return ValidateWithContext(ctx, rv.Elem().Interface())
 
- 	}
 
- 	return nil
 
- }
 
- // By wraps a RuleFunc into a Rule.
 
- func By(f RuleFunc) Rule {
 
- 	return &inlineRule{f: f}
 
- }
 
- // RuleFunc represents a validator function.
 
- // You may wrap it as a Rule by calling By().
 
- type RuleFunc func(value interface{}) error
 
- // WithContext wraps a RuleWithContextFunc into a context-aware Rule.
 
- func WithContext(f RuleWithContextFunc) Rule {
 
- 	return &inlineRule{fc: f}
 
- }
 
- // RuleWithContextFunc represents a validator function that is context-aware.
 
- // You may wrap it as a Rule by calling WithContext().
 
- type RuleWithContextFunc func(ctx context.Context, value interface{}) error
 
- // validateMap validates a map of validatable elements
 
- func validateMap(rv reflect.Value) error {
 
- 	errs := Errors{}
 
- 	for _, key := range rv.MapKeys() {
 
- 		if mv := rv.MapIndex(key).Interface(); mv != nil {
 
- 			if err := mv.(Validatable).Validate(); err != nil {
 
- 				errs[fmt.Sprintf("%v", key.Interface())] = err
 
- 			}
 
- 		}
 
- 	}
 
- 	if len(errs) > 0 {
 
- 		return errs
 
- 	}
 
- 	return nil
 
- }
 
- // validateMapWithContext validates a map of validatable elements with the given context.
 
- func validateMapWithContext(ctx context.Context, rv reflect.Value) error {
 
- 	errs := Errors{}
 
- 	for _, key := range rv.MapKeys() {
 
- 		if mv := rv.MapIndex(key).Interface(); mv != nil {
 
- 			if err := mv.(ValidatableWithContext).ValidateWithContext(ctx); err != nil {
 
- 				errs[fmt.Sprintf("%v", key.Interface())] = err
 
- 			}
 
- 		}
 
- 	}
 
- 	if len(errs) > 0 {
 
- 		return errs
 
- 	}
 
- 	return nil
 
- }
 
- // validateSlice validates a slice/array of validatable elements
 
- func validateSlice(rv reflect.Value) error {
 
- 	errs := Errors{}
 
- 	l := rv.Len()
 
- 	for i := 0; i < l; i++ {
 
- 		if ev := rv.Index(i).Interface(); ev != nil {
 
- 			if err := ev.(Validatable).Validate(); err != nil {
 
- 				errs[strconv.Itoa(i)] = err
 
- 			}
 
- 		}
 
- 	}
 
- 	if len(errs) > 0 {
 
- 		return errs
 
- 	}
 
- 	return nil
 
- }
 
- // validateSliceWithContext validates a slice/array of validatable elements with the given context.
 
- func validateSliceWithContext(ctx context.Context, rv reflect.Value) error {
 
- 	errs := Errors{}
 
- 	l := rv.Len()
 
- 	for i := 0; i < l; i++ {
 
- 		if ev := rv.Index(i).Interface(); ev != nil {
 
- 			if err := ev.(ValidatableWithContext).ValidateWithContext(ctx); err != nil {
 
- 				errs[strconv.Itoa(i)] = err
 
- 			}
 
- 		}
 
- 	}
 
- 	if len(errs) > 0 {
 
- 		return errs
 
- 	}
 
- 	return nil
 
- }
 
- type inlineRule struct {
 
- 	f  RuleFunc
 
- 	fc RuleWithContextFunc
 
- }
 
- func (r *inlineRule) Validate(value interface{}) error {
 
- 	if r.f == nil {
 
- 		return r.fc(context.Background(), value)
 
- 	}
 
- 	return r.f(value)
 
- }
 
- func (r *inlineRule) ValidateWithContext(ctx context.Context, value interface{}) error {
 
- 	if r.fc == nil {
 
- 		return r.f(value)
 
- 	}
 
- 	return r.fc(ctx, value)
 
- }
 
 
  |