validation.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. package valid
  2. import (
  3. "context"
  4. "fmt"
  5. "reflect"
  6. "strconv"
  7. )
  8. var (
  9. validatableType = reflect.TypeOf((*Validatable)(nil)).Elem()
  10. validatableWithContextType = reflect.TypeOf((*ValidatableWithContext)(nil)).Elem()
  11. )
  12. // Validate validates the given value and returns the validation error, if any.
  13. //
  14. // Validate performs validation using the following steps:
  15. // 1. For each rule, call its `Validate()` to validate the value. Return if any error is found.
  16. // 2. If the value being validated implements `Validatable`, call the value's `Validate()`.
  17. // Return with the validation result.
  18. // 3. If the value being validated is a map/slice/array, and the element type implements `Validatable`,
  19. // for each element call the element value's `Validate()`. Return with the validation result.
  20. func Validate(value interface{}, rules ...Rule) error {
  21. for _, rule := range rules {
  22. if s, ok := rule.(skipRule); ok && s.skip {
  23. return nil
  24. }
  25. if err := rule.Validate(value); err != nil {
  26. return err
  27. }
  28. }
  29. rv := reflect.ValueOf(value)
  30. if (rv.Kind() == reflect.Ptr || rv.Kind() == reflect.Interface) && rv.IsNil() {
  31. return nil
  32. }
  33. if v, ok := value.(Validatable); ok {
  34. return v.Validate()
  35. }
  36. switch rv.Kind() {
  37. case reflect.Map:
  38. if rv.Type().Elem().Implements(validatableType) {
  39. return validateMap(rv)
  40. }
  41. case reflect.Slice, reflect.Array:
  42. if rv.Type().Elem().Implements(validatableType) {
  43. return validateSlice(rv)
  44. }
  45. case reflect.Ptr, reflect.Interface:
  46. return Validate(rv.Elem().Interface())
  47. }
  48. return nil
  49. }
  50. // ValidateWithContext validates the given value with the given context and returns the validation error, if any.
  51. //
  52. // ValidateWithContext performs validation using the following steps:
  53. // 1. For each rule, call its `ValidateWithContext()` to validate the value if the rule implements `RuleWithContext`.
  54. // Otherwise call `Validate()` of the rule. Return if any error is found.
  55. // 2. If the value being validated implements `ValidatableWithContext`, call the value's `ValidateWithContext()`
  56. // and return with the validation result.
  57. // 3. If the value being validated implements `Validatable`, call the value's `Validate()`
  58. // and return with the validation result.
  59. // 4. If the value being validated is a map/slice/array, and the element type implements `ValidatableWithContext`,
  60. // for each element call the element value's `ValidateWithContext()`. Return with the validation result.
  61. // 5. If the value being validated is a map/slice/array, and the element type implements `Validatable`,
  62. // for each element call the element value's `Validate()`. Return with the validation result.
  63. func ValidateWithContext(ctx context.Context, value interface{}, rules ...Rule) error {
  64. for _, rule := range rules {
  65. if s, ok := rule.(skipRule); ok && s.skip {
  66. return nil
  67. }
  68. if rc, ok := rule.(RuleWithContext); ok {
  69. if err := rc.ValidateWithContext(ctx, value); err != nil {
  70. return err
  71. }
  72. } else if err := rule.Validate(value); err != nil {
  73. return err
  74. }
  75. }
  76. rv := reflect.ValueOf(value)
  77. if (rv.Kind() == reflect.Ptr || rv.Kind() == reflect.Interface) && rv.IsNil() {
  78. return nil
  79. }
  80. if v, ok := value.(ValidatableWithContext); ok {
  81. return v.ValidateWithContext(ctx)
  82. }
  83. if v, ok := value.(Validatable); ok {
  84. return v.Validate()
  85. }
  86. switch rv.Kind() {
  87. case reflect.Map:
  88. if rv.Type().Elem().Implements(validatableWithContextType) {
  89. return validateMapWithContext(ctx, rv)
  90. }
  91. if rv.Type().Elem().Implements(validatableType) {
  92. return validateMap(rv)
  93. }
  94. case reflect.Slice, reflect.Array:
  95. if rv.Type().Elem().Implements(validatableWithContextType) {
  96. return validateSliceWithContext(ctx, rv)
  97. }
  98. if rv.Type().Elem().Implements(validatableType) {
  99. return validateSlice(rv)
  100. }
  101. case reflect.Ptr, reflect.Interface:
  102. return ValidateWithContext(ctx, rv.Elem().Interface())
  103. }
  104. return nil
  105. }
  106. // By wraps a RuleFunc into a Rule.
  107. func By(f RuleFunc) Rule {
  108. return &inlineRule{f: f}
  109. }
  110. // RuleFunc represents a validator function.
  111. // You may wrap it as a Rule by calling By().
  112. type RuleFunc func(value interface{}) error
  113. // WithContext wraps a RuleWithContextFunc into a context-aware Rule.
  114. func WithContext(f RuleWithContextFunc) Rule {
  115. return &inlineRule{fc: f}
  116. }
  117. // RuleWithContextFunc represents a validator function that is context-aware.
  118. // You may wrap it as a Rule by calling WithContext().
  119. type RuleWithContextFunc func(ctx context.Context, value interface{}) error
  120. // validateMap validates a map of validatable elements
  121. func validateMap(rv reflect.Value) error {
  122. errs := Errors{}
  123. for _, key := range rv.MapKeys() {
  124. if mv := rv.MapIndex(key).Interface(); mv != nil {
  125. if err := mv.(Validatable).Validate(); err != nil {
  126. errs[fmt.Sprintf("%v", key.Interface())] = err
  127. }
  128. }
  129. }
  130. if len(errs) > 0 {
  131. return errs
  132. }
  133. return nil
  134. }
  135. // validateMapWithContext validates a map of validatable elements with the given context.
  136. func validateMapWithContext(ctx context.Context, rv reflect.Value) error {
  137. errs := Errors{}
  138. for _, key := range rv.MapKeys() {
  139. if mv := rv.MapIndex(key).Interface(); mv != nil {
  140. if err := mv.(ValidatableWithContext).ValidateWithContext(ctx); err != nil {
  141. errs[fmt.Sprintf("%v", key.Interface())] = err
  142. }
  143. }
  144. }
  145. if len(errs) > 0 {
  146. return errs
  147. }
  148. return nil
  149. }
  150. // validateSlice validates a slice/array of validatable elements
  151. func validateSlice(rv reflect.Value) error {
  152. errs := Errors{}
  153. l := rv.Len()
  154. for i := 0; i < l; i++ {
  155. if ev := rv.Index(i).Interface(); ev != nil {
  156. if err := ev.(Validatable).Validate(); err != nil {
  157. errs[strconv.Itoa(i)] = err
  158. }
  159. }
  160. }
  161. if len(errs) > 0 {
  162. return errs
  163. }
  164. return nil
  165. }
  166. // validateSliceWithContext validates a slice/array of validatable elements with the given context.
  167. func validateSliceWithContext(ctx context.Context, rv reflect.Value) error {
  168. errs := Errors{}
  169. l := rv.Len()
  170. for i := 0; i < l; i++ {
  171. if ev := rv.Index(i).Interface(); ev != nil {
  172. if err := ev.(ValidatableWithContext).ValidateWithContext(ctx); err != nil {
  173. errs[strconv.Itoa(i)] = err
  174. }
  175. }
  176. }
  177. if len(errs) > 0 {
  178. return errs
  179. }
  180. return nil
  181. }
  182. type inlineRule struct {
  183. f RuleFunc
  184. fc RuleWithContextFunc
  185. }
  186. func (r *inlineRule) Validate(value interface{}) error {
  187. if r.f == nil {
  188. return r.fc(context.Background(), value)
  189. }
  190. return r.f(value)
  191. }
  192. func (r *inlineRule) ValidateWithContext(ctx context.Context, value interface{}) error {
  193. if r.fc == nil {
  194. return r.f(value)
  195. }
  196. return r.fc(ctx, value)
  197. }