-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathvalidation.go
319 lines (278 loc) · 11.7 KB
/
validation.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
// Copyright 2015 Alex Browne and Soroush Pour.
// Allrights reserved. Use of this source code is
// governed by the MIT license, which can be found
// in the LICENSE file.
package form
import "fmt"
// InputValidation is an object which has methods for validating an input. Such
// methods always return an InputValidation and are chainable. Whenever an input
// is invalid, a validation error is added to the corresponding Form and can
// be accessed via the form.HasErrors method and the form.Errors property.
type InputValidation struct {
Errors []error
Input *Input
Form *Form
InputName string
}
// ValidationError is returned whenever an error arises from a validation
// method.
type ValidationError struct {
Input *Input
InputName string
msg string
}
// Error satisfies the Error method of the builtin error interface.
func (valErr ValidationError) Error() string {
return valErr.msg
}
// Validate returns an InputValidation object which can be used to validate a
// single input.
func (form *Form) Validate(inputName string) *InputValidation {
return &InputValidation{
Input: form.Inputs[inputName],
Form: form,
InputName: inputName,
}
}
// AddError adds a validation error to the form with the given format and args.
// The arguments format and args work exactly like they do in fmt.Sprintf.
func (val *InputValidation) AddError(format string, args ...interface{}) {
err := fmt.Errorf(format, args...)
val.Errors = append(val.Errors, err)
valErr := &ValidationError{
Input: val.Input,
InputName: val.InputName,
msg: err.Error(),
}
val.Form.Errors = append(val.Form.Errors, valErr)
}
// Required adds a validation error to the form if the input is not included in
// the form or if it is an empty string.
func (val *InputValidation) Required() *InputValidation {
return val.Requiredf("%s is required.", val.InputName)
}
// Requiredf is like Required but allows you to specify a custom error message.
// The arguments format and args work exactly like they do in fmt.Sprintf.
func (val *InputValidation) Requiredf(format string, args ...interface{}) *InputValidation {
if val.Input == nil || val.Input.RawValue == "" {
val.AddError(format, args...)
}
return val
}
func lessFunc(limit int) func(int) bool {
return func(value int) bool {
return value < limit
}
}
func lessOrEqualFunc(limit int) func(int) bool {
return func(value int) bool {
return value <= limit
}
}
func greaterFunc(limit int) func(int) bool {
return func(value int) bool {
return value > limit
}
}
func greaterOrEqualFunc(limit int) func(int) bool {
return func(value int) bool {
return value >= limit
}
}
// Less adds a validation error to the form if the input is not less than limit.
// Less only works for int values.
func (val *InputValidation) Less(limit int) *InputValidation {
return val.Lessf(limit, "%s must be less than %d.", val.InputName, limit)
}
// Lessf is like Less but allows you to specify a custom error message.
// The arguments format and args work exactly like they do in fmt.Sprintf.
func (val *InputValidation) Lessf(limit int, format string, args ...interface{}) *InputValidation {
return val.validateInt(lessFunc(limit), format, args...)
}
// LessOrEqual adds a validation error to the form if the input is not less than
// or equal to limit. LessOrEqual only works for int values.
func (val *InputValidation) LessOrEqual(limit int) *InputValidation {
return val.LessOrEqualf(limit, "%s must be less than or equal to %d.", val.InputName, limit)
}
// LessOrEqualf is like LessOrEqual but allows you to specify a custom error
// message. The arguments format and args work exactly like they do in
// fmt.Sprintf.
func (val *InputValidation) LessOrEqualf(limit int, format string, args ...interface{}) *InputValidation {
return val.validateInt(lessOrEqualFunc(limit), format, args...)
}
// Greater adds a validation error to the form if the input is not greater than
// limit. Greater only works for int values.
func (val *InputValidation) Greater(limit int) *InputValidation {
return val.Greaterf(limit, "%s must be greater than %d.", val.InputName, limit)
}
// Greaterf is like Greater but allows you to specify a custom error message.
// The arguments format and args work exactly like they do in fmt.Sprintf.
func (val *InputValidation) Greaterf(limit int, format string, args ...interface{}) *InputValidation {
return val.validateInt(greaterFunc(limit), format, args...)
}
// GreaterOrEqual adds a validation error to the form if the input is not
// greater than or equal to limit. GreaterOrEqual only works for int values.
func (val *InputValidation) GreaterOrEqual(limit int) *InputValidation {
return val.GreaterOrEqualf(limit, "%s must be greater than or equal to %d.", val.InputName, limit)
}
// GreaterOrEqualf is like GreaterOrEqual but allows you to specify a custom error message.
// The arguments format and args work exactly like they do in fmt.Sprintf.
func (val *InputValidation) GreaterOrEqualf(limit int, format string, args ...interface{}) *InputValidation {
return val.validateInt(greaterOrEqualFunc(limit), format, args...)
}
// IsInt adds a validation error to the form if the input is not convertible
// to an int.
func (val *InputValidation) IsInt() *InputValidation {
return val.IsIntf("%s must be an integer.", val.InputName)
}
// IsIntf is like IsInt but allows you to specify a custom error message.
// The arguments format and args work exactly like they do in fmt.Sprintf.
func (val *InputValidation) IsIntf(format string, args ...interface{}) *InputValidation {
// If the input does not exist or is empty, skip this validation.
if val.Input == nil || val.Input.RawValue == "" {
return val
}
// Attempt to convert the input value to a int and if the conversion fails,
// add a validation error.
if _, err := val.Input.Int(); err != nil {
val.AddError(format, args...)
}
return val
}
func (val *InputValidation) validateInt(validateFunc func(value int) bool, format string, args ...interface{}) *InputValidation {
// If the input does not exist or is empty, skip this validation.
if val.Input == nil || val.Input.RawValue == "" {
return val
}
// Attempt to convert the input value to an integer.
intVal, err := val.Input.Int()
if err != nil {
val.AddError("%s must be an integer.", val.InputName)
return val
}
// Call validateFunc and if it returns false, add the appropriate error.
if !validateFunc(intVal) {
val.AddError(format, args...)
}
return val
}
func lessFloatFunc(limit float64) func(float64) bool {
return func(value float64) bool {
return value < limit
}
}
func lessOrEqualFloatFunc(limit float64) func(float64) bool {
return func(value float64) bool {
return value <= limit
}
}
func greaterFloatFunc(limit float64) func(float64) bool {
return func(value float64) bool {
return value > limit
}
}
func greaterOrEqualFloatFunc(limit float64) func(float64) bool {
return func(value float64) bool {
return value >= limit
}
}
// LessFloat adds a validation error to the form if the input is not less than
// limit. LessFloat only works for float values.
func (val *InputValidation) LessFloat(limit float64) *InputValidation {
return val.LessFloatf(limit, "%s must be less than %f.", val.InputName, limit)
}
// LessFloatf is like LessFloat but allows you to specify a custom error
// message. The arguments format and args work exactly like they do in
// fmt.Sprintf.
func (val *InputValidation) LessFloatf(limit float64, format string, args ...interface{}) *InputValidation {
return val.validateFloat(lessFloatFunc(limit), format, args...)
}
// LessOrEqualFloat adds a validation error to the form if the input is not less
// than or equal to limit. LessOrEqualFloat only works for float values.
func (val *InputValidation) LessOrEqualFloat(limit float64) *InputValidation {
return val.LessOrEqualFloatf(limit, "%s must be less than or equal to %f.", val.InputName, limit)
}
// LessOrEqualFloatf is like LessOrEqualFloat but allows you to specify a custom
// error message. The arguments format and args work exactly like they do in
// fmt.Sprintf.
func (val *InputValidation) LessOrEqualFloatf(limit float64, format string, args ...interface{}) *InputValidation {
return val.validateFloat(lessOrEqualFloatFunc(limit), format, args...)
}
// GreaterFloat adds a validation error to the form if the input is not greater
// than limit. GreaterFloat only works for float values.
func (val *InputValidation) GreaterFloat(limit float64) *InputValidation {
return val.GreaterFloatf(limit, "%s must be greater than %f.", val.InputName, limit)
}
// GreaterFloatf is like GreaterFloat but allows you to specify a custom error
// message. The arguments format and args work exactly like they do in
// fmt.Sprintf.
func (val *InputValidation) GreaterFloatf(limit float64, format string, args ...interface{}) *InputValidation {
return val.validateFloat(greaterFloatFunc(limit), format, args...)
}
// GreaterOrEqualFloat adds a validation error to the form if the input is not
// greater than or equal to limit. GreaterOrEqualFloat only works for float
// values.
func (val *InputValidation) GreaterOrEqualFloat(limit float64) *InputValidation {
return val.GreaterOrEqualFloatf(limit, "%s must be greater than or equal to %f.", val.InputName, limit)
}
// GreaterOrEqualFloatf is like GreaterOrEqualFloat but allows you to specify a
// custom error message. The arguments format and args work exactly like they do
// in fmt.Sprintf.
func (val *InputValidation) GreaterOrEqualFloatf(limit float64, format string, args ...interface{}) *InputValidation {
return val.validateFloat(greaterOrEqualFloatFunc(limit), format, args...)
}
// IsFloat adds a validation error to the form if the input is not convertible
// to a float64.
func (val *InputValidation) IsFloat() *InputValidation {
return val.IsFloatf("%s must be a number.", val.InputName)
}
// IsFloatf is like IsFloat but allows you to specify a custom error message.
// The arguments format and args work exactly like they do in fmt.Sprintf.
func (val *InputValidation) IsFloatf(format string, args ...interface{}) *InputValidation {
// If the input does not exist or is empty, skip this validation.
if val.Input == nil || val.Input.RawValue == "" {
return val
}
// Attempt to convert the input value to a float and if the conversion fails,
// add a validation error.
if _, err := val.Input.Float(); err != nil {
val.AddError(format, args...)
}
return val
}
func (val *InputValidation) validateFloat(validateFunc func(value float64) bool, format string, args ...interface{}) *InputValidation {
// If the input does not exist or is empty, skip this validation.
if val.Input == nil || val.Input.RawValue == "" {
return val
}
// Attempt to convert the input value to a float.
floatVal, err := val.Input.Float()
if err != nil {
val.AddError("%s must be a number.", val.InputName)
return val
}
// Call validateFunc and if it returns false, add the appropriate error.
if !validateFunc(floatVal) {
val.AddError(format, args...)
}
return val
}
// IsBool adds a validation error to the form if the input is not convertible
// to a bool.
func (val *InputValidation) IsBool() *InputValidation {
return val.IsBoolf("%s must be either true or false.", val.InputName)
}
// IsBoolf is like IsBool but allows you to specify a custom error message.
// The arguments format and args work exactly like they do in fmt.Sprintf.
func (val *InputValidation) IsBoolf(format string, args ...interface{}) *InputValidation {
// If the input does not exist or is empty, skip this validation.
if val.Input == nil || val.Input.RawValue == "" {
return val
}
// Attempt to convert the input to a boolean and if the conversion fails,
// add a validation error.
if _, err := val.Input.Bool(); err != nil {
val.AddError(format, args...)
}
return val
}