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

contraint.go   F

Size/Duplication

Total Lines 430
Duplicated Lines 0 %

Test Coverage

Coverage 94.95%

Importance

Changes 0
Metric Value
cc 63
eloc 216
dl 0
loc 430
ccs 94
cts 99
cp 0.9495
crap 63.5111
rs 3.36
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
14
}
15
16
// NilConstraint is used for a special cases to check a value for nil.
17
type NilConstraint interface {
18
	ValidateNil(isNil bool, scope Scope) error
19
}
20
21
// BoolConstraint is used to build constraints for boolean values validation.
22
type BoolConstraint interface {
23
	ValidateBool(value *bool, scope Scope) error
24
}
25
26
// NumberConstraint is used to build constraints for numeric values validation.
27
type NumberConstraint[T Numeric] interface {
28
	ValidateNumber(value *T, scope Scope) error
29
}
30
31
// StringConstraint is used to build constraints for string values validation.
32
type StringConstraint interface {
33
	ValidateString(value *string, scope Scope) error
34
}
35
36
// ComparableConstraint is used to build constraints for generic comparable value validation.
37
type ComparableConstraint[T comparable] interface {
38
	ValidateComparable(value *T, scope Scope) error
39
}
40
41
// ComparablesConstraint is used to build constraints for generic comparable values validation.
42
type ComparablesConstraint[T comparable] interface {
43
	ValidateComparables(values []T, scope Scope) error
44
}
45
46
// CountableConstraint is used to build constraints for simpler validation of iterable elements count.
47
type CountableConstraint interface {
48
	ValidateCountable(count int, scope Scope) error
49
}
50
51
// TimeConstraint is used to build constraints for date/time validation.
52
type TimeConstraint interface {
53
	ValidateTime(value *time.Time, scope Scope) error
54
}
55
56
// CustomStringConstraint can be used to create custom constraints for validating string values
57
// based on function with signature func(string) bool.
58
type CustomStringConstraint struct {
59
	isIgnored         bool
60
	isValid           func(string) bool
61
	groups            []string
62
	code              string
63
	messageTemplate   string
64
	messageParameters TemplateParameterList
65
}
66
67
// NewCustomStringConstraint creates a new string constraint from a function with signature func(string) bool.
68
// Optional parameters can be used to set up violation code (first), message template (second).
69
// All other parameters are ignored.
70
func NewCustomStringConstraint(isValid func(string) bool, parameters ...string) CustomStringConstraint {
71
	constraint := CustomStringConstraint{
72
		isValid:         isValid,
73
		code:            code.NotValid,
74
		messageTemplate: message.Templates[code.NotValid],
75
	}
76
77
	if len(parameters) > 0 {
78
		constraint.code = parameters[0]
79
	}
80
	if len(parameters) > 1 {
81
		constraint.messageTemplate = parameters[1]
82
	}
83
84
	return constraint
85
}
86
87
// Code overrides default code for produced violation.
88
func (c CustomStringConstraint) Code(code string) CustomStringConstraint {
89
	c.code = code
90
	return c
91
}
92
93 1
// Message sets the violation message template. You can set custom template parameters
94
// for injecting its values into the final message. Also, you can use default parameters:
95
//
96
//	{{ value }} - the current (invalid) value.
97
func (c CustomStringConstraint) Message(template string, parameters ...TemplateParameter) CustomStringConstraint {
98
	c.messageTemplate = template
99
	c.messageParameters = parameters
100 1
	return c
101 1
}
102
103 1
// When enables conditional validation of this constraint. If the expression evaluates to false,
104 1
// then the constraint will be ignored.
105
func (c CustomStringConstraint) When(condition bool) CustomStringConstraint {
106 1
	c.isIgnored = !condition
107 1
	return c
108
}
109
110 1
// WhenGroups enables conditional validation of the constraint by using the validation groups.
111
func (c CustomStringConstraint) WhenGroups(groups ...string) CustomStringConstraint {
112
	c.groups = groups
113
	return c
114
}
115 1
116
func (c CustomStringConstraint) ValidateString(value *string, scope Scope) error {
117
	if c.isIgnored || scope.IsIgnored(c.groups...) || value == nil || *value == "" || c.isValid(*value) {
118
		return nil
119
	}
120 1
121
	return scope.BuildViolation(c.code, c.messageTemplate).
122
		SetParameters(
123
			c.messageParameters.Prepend(
124
				TemplateParameter{Key: "{{ value }}", Value: *value},
125 1
			)...,
126 1
		).
127
		AddParameter("{{ value }}", *value).
128
		CreateViolation()
129
}
130