Test Setup Failed
Pull Request — main (#71)
by Igor
02:10
created

validation.SequentialConstraint.validate   B

Complexity

Conditions 6

Size

Total Lines 20
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 6.288

Importance

Changes 0
Metric Value
cc 6
eloc 14
nop 2
dl 0
loc 20
ccs 8
cts 10
cp 0.8
crap 6.288
rs 8.6666
c 0
b 0
f 0
1
package validation
2
3
import (
4
	"time"
5
6
	"github.com/muonsoft/validation/code"
7
	"github.com/muonsoft/validation/message"
8
)
9
10
type Numeric interface {
11
	~float32 | ~float64 |
12
		~int | ~int8 | ~int16 | ~int32 | ~int64 |
13
		~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
14
}
15
16
// Constraint is the base interface to build validation constraints.
17
// Deprecated
18
type Constraint interface {
19
	// Name is a constraint name that can be used in internal errors.
20
	Name() string
21
}
22
23
// NilConstraint is used for a special cases to check a value for nil.
24
type NilConstraint interface {
25
	ValidateNil(isNil bool, scope Scope) error
26
}
27
28
// BoolConstraint is used to build constraints for boolean values validation.
29
type BoolConstraint interface {
30
	ValidateBool(value *bool, scope Scope) error
31
}
32
33
// NumberConstraint is used to build constraints for numeric values validation.
34
type NumberConstraint[T Numeric] interface {
35
	ValidateNumber(value *T, scope Scope) error
36
}
37
38
// StringConstraint is used to build constraints for string values validation.
39
type StringConstraint interface {
40
	ValidateString(value *string, scope Scope) error
41
}
42
43
// ComparableConstraint is used to build constraints for generic comparable value validation.
44
type ComparableConstraint[T comparable] interface {
45
	ValidateComparable(value *T, scope Scope) error
46
}
47
48
// ComparablesConstraint is used to build constraints for generic comparable values validation.
49
type ComparablesConstraint[T comparable] interface {
50
	ValidateComparables(values []T, scope Scope) error
51
}
52
53
// CountableConstraint is used to build constraints for simpler validation of iterable elements count.
54
type CountableConstraint interface {
55
	ValidateCountable(count int, scope Scope) error
56
}
57
58
// TimeConstraint is used to build constraints for date/time validation.
59
type TimeConstraint interface {
60
	ValidateTime(value *time.Time, scope Scope) error
61
}
62
63
// CustomStringConstraint can be used to create custom constraints for validating string values
64
// based on function with signature func(string) bool.
65
type CustomStringConstraint struct {
66
	isIgnored         bool
67
	isValid           func(string) bool
68
	groups            []string
69
	code              string
70
	messageTemplate   string
71
	messageParameters TemplateParameterList
72
}
73
74
// NewCustomStringConstraint creates a new string constraint from a function with signature func(string) bool.
75
// Optional parameters can be used to set up violation code (first), message template (second).
76
// All other parameters are ignored.
77
func NewCustomStringConstraint(isValid func(string) bool, parameters ...string) CustomStringConstraint {
78
	constraint := CustomStringConstraint{
79
		isValid:         isValid,
80
		code:            code.NotValid,
81
		messageTemplate: message.Templates[code.NotValid],
82
	}
83
84
	if len(parameters) > 0 {
85
		constraint.code = parameters[0]
86
	}
87
	if len(parameters) > 1 {
88
		constraint.messageTemplate = parameters[1]
89
	}
90
91
	return constraint
92
}
93 1
94
// Code overrides default code for produced violation.
95
func (c CustomStringConstraint) Code(code string) CustomStringConstraint {
96
	c.code = code
97
	return c
98
}
99
100 1
// Message sets the violation message template. You can set custom template parameters
101 1
// for injecting its values into the final message. Also, you can use default parameters:
102
//
103 1
//	{{ value }} - the current (invalid) value.
104 1
func (c CustomStringConstraint) Message(template string, parameters ...TemplateParameter) CustomStringConstraint {
105
	c.messageTemplate = template
106 1
	c.messageParameters = parameters
107 1
	return c
108
}
109
110 1
// When enables conditional validation of this constraint. If the expression evaluates to false,
111
// then the constraint will be ignored.
112
func (c CustomStringConstraint) When(condition bool) CustomStringConstraint {
113
	c.isIgnored = !condition
114
	return c
115 1
}
116
117
// WhenGroups enables conditional validation of the constraint by using the validation groups.
118
func (c CustomStringConstraint) WhenGroups(groups ...string) CustomStringConstraint {
119
	c.groups = groups
120 1
	return c
121
}
122
123
func (c CustomStringConstraint) ValidateString(value *string, scope Scope) error {
124
	if c.isIgnored || scope.IsIgnored(c.groups...) || value == nil || *value == "" || c.isValid(*value) {
125 1
		return nil
126 1
	}
127
128
	return scope.BuildViolation(c.code, c.messageTemplate).
129
		SetParameters(
130
			c.messageParameters.Prepend(
131
				TemplateParameter{Key: "{{ value }}", Value: *value},
132
			)...,
133
		).
134 1
		AddParameter("{{ value }}", *value).
135 1
		CreateViolation()
136 1
}
137
138
type notFoundConstraint struct {
139
	key string
140
}
141
142 1
func (c notFoundConstraint) SetUp() error {
143 1
	return ConstraintNotFoundError{Key: c.key}
144
}
145
146
func (c notFoundConstraint) Name() string {
147
	return "notFoundConstraint"
148
}
149