Passed
Pull Request — main (#49)
by Igor
02:47
created

it.CountConstraint.ValidateCountable   B

Complexity

Conditions 6

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 6

Importance

Changes 0
Metric Value
cc 6
eloc 8
dl 0
loc 12
ccs 7
cts 7
cp 1
crap 6
rs 8.6666
c 0
b 0
f 0
nop 2
1
package it
2
3
import (
4
	"strconv"
5
6
	"github.com/muonsoft/validation"
7
	"github.com/muonsoft/validation/code"
8
	"github.com/muonsoft/validation/generic"
9
	"github.com/muonsoft/validation/message"
10
)
11
12
// CountConstraint checks that a given collection's (array, slice or a map) length is between some minimum and
13
// maximum value.
14
type CountConstraint struct {
15
	isIgnored              bool
16
	checkMin               bool
17
	checkMax               bool
18
	min                    int
19
	max                    int
20
	minMessageTemplate     string
21
	minMessageParameters   validation.TemplateParameterList
22
	maxMessageTemplate     string
23
	maxMessageParameters   validation.TemplateParameterList
24
	exactMessageTemplate   string
25
	exactMessageParameters validation.TemplateParameterList
26
}
27
28
func newCountConstraint(min int, max int, checkMin bool, checkMax bool) CountConstraint {
29 1
	return CountConstraint{
30
		min:                  min,
31
		max:                  max,
32
		checkMin:             checkMin,
33
		checkMax:             checkMax,
34
		minMessageTemplate:   message.CountTooFew,
35
		maxMessageTemplate:   message.CountTooMany,
36
		exactMessageTemplate: message.CountExact,
37
	}
38
}
39
40
// HasMinCount creates a CountConstraint that checks the length of the iterable (slice, array, or map)
41
// is greater than the minimum value.
42
//
43
// Example
44
//  v := []int{1, 2}
45
//  err := validator.ValidateIterable(v, it.HasMinCount(3))
46
func HasMinCount(min int) CountConstraint {
47 1
	return newCountConstraint(min, 0, true, false)
48
}
49
50
// HasMaxCount creates a CountConstraint that checks the length of the iterable (slice, array, or map)
51
// is less than the maximum value.
52
//
53
// Example
54
//  v := []int{1, 2}
55
//  err := validator.ValidateIterable(v, it.HasMaxCount(1))
56
func HasMaxCount(max int) CountConstraint {
57 1
	return newCountConstraint(0, max, false, true)
58
}
59
60
// HasCountBetween creates a CountConstraint that checks the length of the iterable (slice, array, or map)
61
// is between some minimum and maximum value.
62
//
63
// Example
64
//  v := []int{1, 2}
65
//  err := validator.ValidateIterable(v, it.HasCountBetween(3, 10))
66
func HasCountBetween(min int, max int) CountConstraint {
67 1
	return newCountConstraint(min, max, true, true)
68
}
69
70
// HasExactCount creates a CountConstraint that checks the length of the iterable (slice, array, or map)
71
// has exact value.
72
//
73
// Example
74
//  v := []int{1, 2}
75
//  err := validator.ValidateIterable(v, it.HasExactCount(3))
76
func HasExactCount(count int) CountConstraint {
77 1
	return newCountConstraint(count, count, true, true)
78
}
79
80
// Name is the constraint name.
81
func (c CountConstraint) Name() string {
82
	return "CountConstraint"
83
}
84
85
// SetUp always returns no error.
86
func (c CountConstraint) SetUp() error {
87 1
	return nil
88
}
89
90
// When enables conditional validation of this constraint. If the expression evaluates to false,
91
// then the constraint will be ignored.
92
func (c CountConstraint) When(condition bool) CountConstraint {
93 1
	c.isIgnored = !condition
94 1
	return c
95
}
96
97
// MinMessage sets the violation message that will be shown if the collection length is less than
98
// the minimum value. You can set custom template parameters for injecting its values
99
// into the final message. Also, you can use default parameters:
100
//
101
//	{{ count }} - the current collection size;
102
//	{{ limit }} - the lower limit.
103
func (c CountConstraint) MinMessage(template string, parameters ...validation.TemplateParameter) CountConstraint {
104 1
	c.minMessageTemplate = template
105 1
	c.minMessageParameters = parameters
106 1
	return c
107
}
108
109
// MaxMessage sets the violation message that will be shown if the collection length is greater than
110
// the maximum value. You can set custom template parameters for injecting its values
111
// into the final message. Also, you can use default parameters:
112
//
113
//	{{ count }} - the current collection size;
114
//	{{ limit }} - the upper limit.
115
func (c CountConstraint) MaxMessage(template string, parameters ...validation.TemplateParameter) CountConstraint {
116 1
	c.maxMessageTemplate = template
117 1
	c.maxMessageParameters = parameters
118 1
	return c
119
}
120
121
// ExactMessage sets the violation message that will be shown if minimum and maximum values are equal and
122
// the length of the collection is not exactly this value. You can set custom template parameters
123
// for injecting its values into the final message. Also, you can use default parameters:
124
//
125
//	{{ count }} - the current collection size;
126
//	{{ limit }} - the exact expected collection size.
127
func (c CountConstraint) ExactMessage(template string, parameters ...validation.TemplateParameter) CountConstraint {
128 1
	c.exactMessageTemplate = template
129 1
	c.exactMessageParameters = parameters
130 1
	return c
131
}
132
133
func (c CountConstraint) ValidateIterable(value generic.Iterable, scope validation.Scope) error {
134 1
	return c.ValidateCountable(value.Count(), scope)
135
}
136
137
func (c CountConstraint) ValidateCountable(count int, scope validation.Scope) error {
138 1
	if c.isIgnored {
139 1
		return nil
140
	}
141 1
	if c.checkMax && count > c.max {
142 1
		return c.newViolation(count, c.max, code.CountTooMany, c.maxMessageTemplate, c.maxMessageParameters, scope)
143
	}
144 1
	if c.checkMin && count < c.min {
145 1
		return c.newViolation(count, c.min, code.CountTooFew, c.minMessageTemplate, c.minMessageParameters, scope)
146
	}
147
148 1
	return nil
149
}
150
151
func (c CountConstraint) newViolation(
152
	count, limit int,
153
	violationCode, template string,
154
	parameters validation.TemplateParameterList,
155
	scope validation.Scope,
156
) validation.Violation {
157 1
	if c.checkMin && c.checkMax && c.min == c.max {
158 1
		template = c.exactMessageTemplate
159 1
		parameters = c.exactMessageParameters
160 1
		violationCode = code.CountExact
161
	}
162
163 1
	return scope.BuildViolation(violationCode, template).
164
		SetPluralCount(limit).
165
		SetParameters(
166
			parameters.Prepend(
167
				validation.TemplateParameter{Key: "{{ count }}", Value: strconv.Itoa(count)},
168
				validation.TemplateParameter{Key: "{{ limit }}", Value: strconv.Itoa(limit)},
169
			)...,
170
		).
171
		CreateViolation()
172
}
173