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