-
Notifications
You must be signed in to change notification settings - Fork 1
/
validation.go
141 lines (129 loc) · 3.86 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
package validation
import "context"
// Validate executes given validators to make result.
func Validate(validators ...Validator) Errors {
return execValidators(context.Background(), validators, false)
}
// ValidateWithCtx executes given validators with given context.
func ValidateWithCtx(ctx context.Context, validators ...Validator) Errors {
return execValidators(ctx, validators, false)
}
// Group groups the given validators into one.
// In case there are errors, only one error will be returned.
func Group(validators ...Validator) SingleValidator {
return NewSingleValidator(func(ctx context.Context) Error {
if len(validators) == 0 {
return nil
}
errs := execValidators(ctx, validators, false)
if len(errs) == 0 {
return nil
}
return errorBuild("group", "", nil, errs)
})
}
// OneOf checks if the target value satisfies one of the given validators.
// When a validator passes, the remaining ones will be skipped.
func OneOf(validators ...Validator) SingleValidator {
return NewSingleValidator(func(ctx context.Context) Error {
if len(validators) == 0 {
return nil
}
wrapErrs := Errors{}
for _, v := range validators {
errs := v.Validate(ctx)
if len(errs) == 0 {
return nil // return nil when one passes
}
wrapErrs = append(wrapErrs, errs...)
}
return errorBuild("one_of", "", nil, wrapErrs)
})
}
// ExactOneOf checks if the target value satisfies only one of the given validators.
// This returns error when there is not one or more than one validator pass.
func ExactOneOf(validators ...Validator) SingleValidator {
return NewSingleValidator(func(ctx context.Context) Error {
numValidatorPass := 0
wrapErrs := Errors{}
for _, v := range validators {
errs := v.Validate(ctx)
if len(errs) == 0 {
numValidatorPass++
} else {
wrapErrs = append(wrapErrs, errs...)
}
if numValidatorPass > 1 {
break
}
}
if numValidatorPass == 1 {
return nil
}
return errorBuild("exact_one_of", "", nil, wrapErrs)
})
}
// NotOf checks the target value not satisfy any of the given validators.
// When a validator passes, an error will be returned and the remaining checks will be skipped.
func NotOf(validators ...Validator) SingleValidator {
return NewSingleValidator(func(ctx context.Context) Error {
for _, v := range validators {
errs := v.Validate(ctx)
if len(errs) == 0 {
return errorBuild("not_of", "", nil, nil)
}
}
return nil
})
}
// If a bare check validation convenient for validating custom data such as
// `If(myTime.Before(dueDate)).OnError(vld.SetCustomKey("MY_ERR_KEY"))`.
// Deprecated: use `Must` instead
func If(cond bool) SingleValidator {
return NewSingleValidator(func(context.Context) Error {
if cond {
return nil
}
return errorBuild("if", "", cond, nil)
})
}
// Must a bare check validation convenient for validating custom data such as
// `Must(myTime.Before(dueDate)).OnError(vld.SetCustomKey("MY_ERR_KEY"))`.
func Must(cond bool) SingleValidator {
return NewSingleValidator(func(context.Context) Error {
if cond {
return nil
}
return errorBuild("must", "", cond, nil)
})
}
// When works like a `if...then...else` statement
func When(conditions ...any) SingleCondValidator {
return NewSingleCondValidator(conditions...)
}
// Case works like a `switch...case` statement
func Case(conditions ...SingleCondValidator) MultiCondValidator {
return NewMultiCondValidator(conditions...)
}
// execValidators executes a list of validators and collect errors as result
// nolint: unparam
func execValidators(ctx context.Context, validators []Validator, stopOnError bool) Errors {
errs := make(Errors, 0, len(validators))
for _, v := range validators {
hasErr := false
for _, e := range v.Validate(ctx) {
if e == nil {
continue
}
hasErr = true
errs = append(errs, e)
}
if stopOnError && hasErr {
break
}
}
if len(errs) == 0 {
return nil
}
return errs
}