rule_each.go 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. package valid
  2. import (
  3. "context"
  4. "errors"
  5. "reflect"
  6. "strconv"
  7. )
  8. // Each returns a validation rule that loops through an iterable (map, slice or array)
  9. // and validates each value inside with the provided rules.
  10. // An empty iterable is considered valid. Use the Required rule to make sure the iterable is not empty.
  11. func Each(rules ...Rule) EachRule {
  12. return EachRule{
  13. rules: rules,
  14. }
  15. }
  16. // EachRule is a validation rule that validates elements in a map/slice/array using the specified list of rules.
  17. type EachRule struct {
  18. rules []Rule
  19. }
  20. // Validate loops through the given iterable and calls the Ozzo Validate() method for each value.
  21. func (r EachRule) Validate(value interface{}) error {
  22. return r.ValidateWithContext(nil, value)
  23. }
  24. // ValidateWithContext loops through the given iterable and calls the Ozzo ValidateWithContext() method for each value.
  25. func (r EachRule) ValidateWithContext(ctx context.Context, value interface{}) error {
  26. errs := Errors{}
  27. v := reflect.ValueOf(value)
  28. switch v.Kind() {
  29. case reflect.Map:
  30. for _, k := range v.MapKeys() {
  31. val := r.getInterface(v.MapIndex(k))
  32. var err error
  33. if ctx == nil {
  34. err = Validate(val, r.rules...)
  35. } else {
  36. err = ValidateWithContext(ctx, val, r.rules...)
  37. }
  38. if err != nil {
  39. errs[r.getString(k)] = err
  40. }
  41. }
  42. case reflect.Slice, reflect.Array:
  43. for i := 0; i < v.Len(); i++ {
  44. val := r.getInterface(v.Index(i))
  45. var err error
  46. if ctx == nil {
  47. err = Validate(val, r.rules...)
  48. } else {
  49. err = ValidateWithContext(ctx, val, r.rules...)
  50. }
  51. if err != nil {
  52. errs[strconv.Itoa(i)] = err
  53. }
  54. }
  55. default:
  56. return errors.New("must be an iterable (map, slice or array)")
  57. }
  58. if len(errs) > 0 {
  59. return errs
  60. }
  61. return nil
  62. }
  63. func (r EachRule) getInterface(value reflect.Value) interface{} {
  64. switch value.Kind() {
  65. case reflect.Ptr, reflect.Interface:
  66. if value.IsNil() {
  67. return nil
  68. }
  69. return value.Elem().Interface()
  70. default:
  71. return value.Interface()
  72. }
  73. }
  74. func (r EachRule) getString(value reflect.Value) string {
  75. switch value.Kind() {
  76. case reflect.Ptr, reflect.Interface:
  77. if value.IsNil() {
  78. return ""
  79. }
  80. return value.Elem().String()
  81. default:
  82. return value.String()
  83. }
  84. }