Passed
Pull Request — main (#23)
by Igor
01:32
created

validation.newNilValidator   A

Complexity

Conditions 3

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 3.1406

Importance

Changes 0
Metric Value
cc 3
eloc 5
dl 0
loc 7
ccs 3
cts 4
cp 0.75
crap 3.1406
rs 10
c 0
b 0
f 0
nop 1
1
package validation
2
3
import (
4
	"reflect"
5
	"time"
6
7
	"github.com/muonsoft/validation/generic"
8
)
9
10
type validateFunc func(scope Scope) (ViolationList, error)
11
12
type validateByConstraintFunc func(constraint Constraint, scope Scope) error
13
14
func newValueValidator(value interface{}, options []Option) (validateFunc, error) {
15 1
	switch v := value.(type) {
16
	case Validatable:
17 1
		return newValidValidator(v, options), nil
18
	case time.Time:
19 1
		return newTimeValidator(&v, options), nil
20
	case *time.Time:
21 1
		return newTimeValidator(v, options), nil
22
	}
23
24 1
	v := reflect.ValueOf(value)
25
26 1
	switch v.Kind() {
27
	case reflect.Ptr:
28 1
		return newValuePointerValidator(v, options)
29
	case reflect.Bool:
30 1
		b := v.Bool()
31 1
		return newBoolValidator(&b, options), nil
32
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
33
		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
34
		reflect.Float32, reflect.Float64:
35 1
		n, err := generic.NewNumber(value)
36 1
		if err != nil {
37
			return nil, err
38
		}
39
40 1
		return newNumberValidator(*n, options), nil
41
	case reflect.String:
42 1
		s := v.String()
43 1
		return newStringValidator(&s, options), nil
44
	case reflect.Array, reflect.Slice, reflect.Map:
45 1
		i, err := generic.NewIterable(value)
46 1
		if err != nil {
47
			return nil, err
48
		}
49
50 1
		return newIterableValidator(i, options), nil
51
	}
52
53 1
	return nil, &NotValidatableError{Value: v}
54
}
55
56
func newValuePointerValidator(value reflect.Value, options []Option) (validateFunc, error) {
57 1
	p := value.Elem()
58 1
	if value.IsNil() {
59 1
		return newNilValidator(options), nil
60
	}
61
62 1
	switch p.Kind() {
63
	case reflect.Bool:
64 1
		b := p.Bool()
65 1
		return newBoolValidator(&b, options), nil
66
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
67
		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
68
		reflect.Float32, reflect.Float64:
69 1
		n, err := generic.NewNumber(p.Interface())
70 1
		if err != nil {
71
			return nil, err
72
		}
73
74 1
		return newNumberValidator(*n, options), nil
75
	case reflect.String:
76 1
		s := p.String()
77 1
		return newStringValidator(&s, options), nil
78
	case reflect.Array, reflect.Slice, reflect.Map:
79 1
		i, err := generic.NewIterable(p.Interface())
80 1
		if err != nil {
81
			return nil, err
82
		}
83
84 1
		return newIterableValidator(i, options), nil
85
	}
86
87
	return nil, &NotValidatableError{Value: value}
88
}
89
90
func newNilValidator(options []Option) validateFunc {
91 1
	return newValidator(options, func(constraint Constraint, scope Scope) error {
92 1
		if constraintValidator, ok := constraint.(NilConstraint); ok {
93 1
			return constraintValidator.ValidateNil(scope)
94
		}
95
96
		return nil
97
	})
98
}
99
100
func newBoolValidator(value *bool, options []Option) validateFunc {
101 1
	return newValidator(options, func(constraint Constraint, scope Scope) error {
102 1
		if c, ok := constraint.(BoolConstraint); ok {
103 1
			return c.ValidateBool(value, scope)
104
		}
105
106 1
		return newInapplicableConstraintError(constraint, "bool")
107
	})
108
}
109
110
func newNumberValidator(value generic.Number, options []Option) validateFunc {
111 1
	return newValidator(options, func(constraint Constraint, scope Scope) error {
112 1
		if c, ok := constraint.(NumberConstraint); ok {
113 1
			return c.ValidateNumber(value, scope)
114
		}
115
116 1
		return newInapplicableConstraintError(constraint, "number")
117
	})
118
}
119
120
func newStringValidator(value *string, options []Option) validateFunc {
121 1
	return newValidator(options, func(constraint Constraint, scope Scope) error {
122 1
		if c, ok := constraint.(StringConstraint); ok {
123 1
			return c.ValidateString(value, scope)
124
		}
125
126 1
		return newInapplicableConstraintError(constraint, "string")
127
	})
128
}
129
130
func newIterableValidator(iterable generic.Iterable, options []Option) validateFunc {
131 1
	return func(scope Scope) (ViolationList, error) {
132 1
		err := scope.applyOptions(options...)
133 1
		if err != nil {
134
			return nil, err
135
		}
136
137 1
		violations, err := validateOnScope(scope, options, func(constraint Constraint, scope Scope) error {
138 1
			if c, ok := constraint.(IterableConstraint); ok {
139 1
				return c.ValidateIterable(iterable, scope)
140
			}
141
142 1
			return newInapplicableConstraintError(constraint, "iterable")
143
		})
144 1
		if err != nil {
145 1
			return nil, err
146
		}
147
148 1
		if iterable.IsElementImplements(validatableType) {
149 1
			vs, err := validateIterableOfValidatables(scope, iterable)
150 1
			if err != nil {
151
				return nil, err
152
			}
153 1
			violations = append(violations, vs...)
154
		}
155
156 1
		return violations, nil
157
	}
158
}
159
160
func newCountableValidator(count int, options []Option) validateFunc {
161 1
	return newValidator(options, func(constraint Constraint, scope Scope) error {
162 1
		if c, ok := constraint.(CountableConstraint); ok {
163 1
			return c.ValidateCountable(count, scope)
164
		}
165
166 1
		return newInapplicableConstraintError(constraint, "countable")
167
	})
168
}
169
170
func newTimeValidator(value *time.Time, options []Option) validateFunc {
171 1
	return newValidator(options, func(constraint Constraint, scope Scope) error {
172 1
		if c, ok := constraint.(TimeConstraint); ok {
173 1
			return c.ValidateTime(value, scope)
174
		}
175
176 1
		return newInapplicableConstraintError(constraint, "time")
177
	})
178
}
179
180
func newEachValidator(iterable generic.Iterable, options []Option) validateFunc {
181 1
	return func(scope Scope) (ViolationList, error) {
182 1
		violations := make(ViolationList, 0)
183
184 1
		err := iterable.Iterate(func(key generic.Key, value interface{}) error {
185 1
			opts := options
186 1
			if key.IsIndex() {
187 1
				opts = append(opts, ArrayIndex(key.Index()))
188
			} else {
189 1
				opts = append(opts, PropertyName(key.String()))
190
			}
191
192 1
			validate, err := newValueValidator(value, opts)
193 1
			if err != nil {
194
				return err
195
			}
196
197 1
			vs, err := validate(scope)
198 1
			if err != nil {
199
				return err
200
			}
201 1
			violations = append(violations, vs...)
202
203 1
			return nil
204
		})
205
206 1
		return violations, err
207
	}
208
}
209
210
func newEachStringValidator(values []string, options []Option) validateFunc {
211 1
	return func(scope Scope) (ViolationList, error) {
212 1
		violations := make(ViolationList, 0)
213
214 1
		for i := range values {
215 1
			opts := append(options, ArrayIndex(i))
216 1
			validate := newStringValidator(&values[i], opts)
217 1
			vs, err := validate(scope)
218 1
			if err != nil {
219
				return nil, err
220
			}
221 1
			violations = append(violations, vs...)
222
		}
223
224 1
		return violations, nil
225
	}
226
}
227
228
func newValidValidator(value Validatable, options []Option) validateFunc {
229 1
	return func(scope Scope) (ViolationList, error) {
230 1
		err := scope.applyOptions(options...)
231 1
		if err != nil {
232
			return nil, err
233
		}
234
235 1
		err = value.Validate(newScopedValidator(scope))
236 1
		violations, ok := UnwrapViolationList(err)
237 1
		if ok {
238 1
			return violations, nil
239
		}
240
241
		return nil, err
242
	}
243
}
244
245
func newValidator(options []Option, validate validateByConstraintFunc) validateFunc {
246 1
	return func(scope Scope) (ViolationList, error) {
247 1
		err := scope.applyOptions(options...)
248 1
		if err != nil {
249 1
			return nil, err
250
		}
251
252 1
		return validateOnScope(scope, options, validate)
253
	}
254
}
255
256
func validateOnScope(scope Scope, options []Option, validate validateByConstraintFunc) (ViolationList, error) {
257 1
	violations := make(ViolationList, 0)
258
259 1
	for _, option := range options {
260 1
		if constraint, ok := option.(Constraint); ok {
261 1
			err := violations.AppendFromError(validate(constraint, scope))
262 1
			if err != nil {
263 1
				return nil, err
264
			}
265
		}
266
	}
267
268 1
	return violations, nil
269
}
270
271
func validateIterableOfValidatables(scope Scope, iterable generic.Iterable) (ViolationList, error) {
272 1
	violations := make(ViolationList, 0)
273
274 1
	err := iterable.Iterate(func(key generic.Key, value interface{}) error {
275 1
		s := scope
276 1
		if key.IsIndex() {
277 1
			s = s.atIndex(key.Index())
278
		} else {
279 1
			s = s.atProperty(key.String())
280
		}
281
282 1
		validate := newValidValidator(value.(Validatable), nil)
283 1
		vs, err := validate(s)
284 1
		if err != nil {
285
			return err
286
		}
287
288 1
		violations = append(violations, vs...)
289
290 1
		return nil
291
	})
292
293 1
	return violations, err
294
}
295