rule_minmax.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. package valid
  2. import (
  3. "fmt"
  4. "reflect"
  5. "time"
  6. )
  7. var (
  8. // ErrMinGreaterEqualThanRequired is the error that returns when a value is less than a specified threshold.
  9. ErrMinGreaterEqualThanRequired = NewError("validation_min_greater_equal_than_required", "must be no less than {{.threshold}}")
  10. // ErrMaxLessEqualThanRequired is the error that returns when a value is greater than a specified threshold.
  11. ErrMaxLessEqualThanRequired = NewError("validation_max_less_equal_than_required", "must be no greater than {{.threshold}}")
  12. // ErrMinGreaterThanRequired is the error that returns when a value is less than or equal to a specified threshold.
  13. ErrMinGreaterThanRequired = NewError("validation_min_greater_than_required", "must be greater than {{.threshold}}")
  14. // ErrMaxLessThanRequired is the error that returns when a value is greater than or equal to a specified threshold.
  15. ErrMaxLessThanRequired = NewError("validation_max_less_than_required", "must be less than {{.threshold}}")
  16. )
  17. // ThresholdRule is a validation rule that checks if a value satisfies the specified threshold requirement.
  18. type ThresholdRule struct {
  19. threshold interface{}
  20. operator int
  21. err Error
  22. }
  23. const (
  24. greaterThan = iota
  25. greaterEqualThan
  26. lessThan
  27. lessEqualThan
  28. )
  29. // Min returns a validation rule that checks if a value is greater or equal than the specified value.
  30. // By calling Exclusive, the rule will check if the value is strictly greater than the specified value.
  31. // Note that the value being checked and the threshold value must be of the same type.
  32. // Only int, uint, float and time.Time types are supported.
  33. // An empty value is considered valid. Please use the Required rule to make sure a value is not empty.
  34. func Min(min interface{}) ThresholdRule {
  35. return ThresholdRule{
  36. threshold: min,
  37. operator: greaterEqualThan,
  38. err: ErrMinGreaterEqualThanRequired,
  39. }
  40. }
  41. // Max returns a validation rule that checks if a value is less or equal than the specified value.
  42. // By calling Exclusive, the rule will check if the value is strictly less than the specified value.
  43. // Note that the value being checked and the threshold value must be of the same type.
  44. // Only int, uint, float and time.Time types are supported.
  45. // An empty value is considered valid. Please use the Required rule to make sure a value is not empty.
  46. func Max(max interface{}) ThresholdRule {
  47. return ThresholdRule{
  48. threshold: max,
  49. operator: lessEqualThan,
  50. err: ErrMaxLessEqualThanRequired,
  51. }
  52. }
  53. // Exclusive sets the comparison to exclude the boundary value.
  54. func (r ThresholdRule) Exclusive() ThresholdRule {
  55. if r.operator == greaterEqualThan {
  56. r.operator = greaterThan
  57. r.err = ErrMinGreaterThanRequired
  58. } else if r.operator == lessEqualThan {
  59. r.operator = lessThan
  60. r.err = ErrMaxLessThanRequired
  61. }
  62. return r
  63. }
  64. // Validate checks if the given value is valid or not.
  65. func (r ThresholdRule) Validate(value interface{}) error {
  66. value, isNil := Indirect(value)
  67. if isNil || IsEmpty(value) {
  68. return nil
  69. }
  70. rv := reflect.ValueOf(r.threshold)
  71. switch rv.Kind() {
  72. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  73. v, err := ToInt(value)
  74. if err != nil {
  75. return err
  76. }
  77. if r.compareInt(rv.Int(), v) {
  78. return nil
  79. }
  80. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
  81. v, err := ToUint(value)
  82. if err != nil {
  83. return err
  84. }
  85. if r.compareUint(rv.Uint(), v) {
  86. return nil
  87. }
  88. case reflect.Float32, reflect.Float64:
  89. v, err := ToFloat(value)
  90. if err != nil {
  91. return err
  92. }
  93. if r.compareFloat(rv.Float(), v) {
  94. return nil
  95. }
  96. case reflect.Struct:
  97. t, ok := r.threshold.(time.Time)
  98. if !ok {
  99. return fmt.Errorf("type not supported: %v", rv.Type())
  100. }
  101. v, ok := value.(time.Time)
  102. if !ok {
  103. return fmt.Errorf("cannot convert %v to time.Time", reflect.TypeOf(value))
  104. }
  105. if v.IsZero() || r.compareTime(t, v) {
  106. return nil
  107. }
  108. default:
  109. return fmt.Errorf("type not supported: %v", rv.Type())
  110. }
  111. return r.err.SetParams(map[string]interface{}{"threshold": r.threshold})
  112. }
  113. // Error sets the error message for the rule.
  114. func (r ThresholdRule) Error(message string) ThresholdRule {
  115. r.err = r.err.SetMessage(message)
  116. return r
  117. }
  118. // ErrorObject sets the error struct for the rule.
  119. func (r ThresholdRule) ErrorObject(err Error) ThresholdRule {
  120. r.err = err
  121. return r
  122. }
  123. func (r ThresholdRule) compareInt(threshold, value int64) bool {
  124. switch r.operator {
  125. case greaterThan:
  126. return value > threshold
  127. case greaterEqualThan:
  128. return value >= threshold
  129. case lessThan:
  130. return value < threshold
  131. default:
  132. return value <= threshold
  133. }
  134. }
  135. func (r ThresholdRule) compareUint(threshold, value uint64) bool {
  136. switch r.operator {
  137. case greaterThan:
  138. return value > threshold
  139. case greaterEqualThan:
  140. return value >= threshold
  141. case lessThan:
  142. return value < threshold
  143. default:
  144. return value <= threshold
  145. }
  146. }
  147. func (r ThresholdRule) compareFloat(threshold, value float64) bool {
  148. switch r.operator {
  149. case greaterThan:
  150. return value > threshold
  151. case greaterEqualThan:
  152. return value >= threshold
  153. case lessThan:
  154. return value < threshold
  155. default:
  156. return value <= threshold
  157. }
  158. }
  159. func (r ThresholdRule) compareTime(threshold, value time.Time) bool {
  160. switch r.operator {
  161. case greaterThan:
  162. return value.After(threshold)
  163. case greaterEqualThan:
  164. return value.After(threshold) || value.Equal(threshold)
  165. case lessThan:
  166. return value.Before(threshold)
  167. default:
  168. return value.Before(threshold) || value.Equal(threshold)
  169. }
  170. }