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

validation.Scope.NewConstraintError   A

Complexity

Conditions 1

Size

Total Lines 5
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 5
nop 2
dl 0
loc 5
rs 10
c 0
b 0
f 0
ccs 3
cts 3
cp 1
crap 1
1
package validation
2
3
import (
4
	"context"
5
	"fmt"
6
7
	"github.com/muonsoft/language"
8
)
9
10
const DefaultGroup = "default"
11
12
// Scope holds the current state of validation. On the client-side of the package,
13
// it can be used to build violations.
14
type Scope struct {
15
	context          context.Context
16
	propertyPath     *PropertyPath
17
	language         language.Tag
18
	translator       Translator
19
	violationFactory ViolationFactory
20
	groups           []string
21
	constraints      map[string]interface{}
22
}
23
24
// Context returns context value that was passed to the validator by Context argument or
25
// by creating scoped validator with the validator.WithContext method.
26
func (s Scope) Context() context.Context {
27 1
	return s.context
28
}
29
30
// NewConstraintError creates a new ConstraintError, which can be used to stop validation process
31
// if constraint is not properly configured.
32
func (s Scope) NewConstraintError(constraintName, description string) ConstraintError {
33 1
	return ConstraintError{
34 1
		ConstraintName: constraintName,
35
		Path:           s.propertyPath,
36 1
		Description:    description,
37 1
	}
38 1
}
39 1
40
// BuildViolation is used to create violations in validation methods of constraints.
41
// This method automatically injects the property path and language of the current validation scope.
42 1
func (s Scope) BuildViolation(code, message string) *ViolationBuilder {
43
	b := NewViolationBuilder(s.violationFactory).BuildViolation(code, message)
44
	b.SetPropertyPath(s.propertyPath)
45
46
	if s.language != language.Und {
47 1
		b.SetLanguage(s.language)
48
	} else if s.context != nil {
49 1
		b.SetLanguage(language.FromContext(s.context))
50
	}
51
52
	return b
53
}
54 1
55
// AtProperty returns a copy of the scope with property path appended by the given property name.
56 1
func (s Scope) AtProperty(name string) Scope {
57
	s.propertyPath = s.propertyPath.WithProperty(name)
58
59
	return s
60
}
61
62 1
// AtIndex returns a copy of the scope with property path appended by the given array index.
63
func (s Scope) AtIndex(index int) Scope {
64
	s.propertyPath = s.propertyPath.WithIndex(index)
65
66
	return s
67
}
68 1
69
// Validator creates a new validator for the given scope. This validator can be used to perform
70
// complex validation on a custom constraint using existing constraints.
71
func (s Scope) Validator() *Validator {
72
	return newScopedValidator(s)
73
}
74
75 1
// IsIgnored is the reverse condition for applying validation groups to the IsApplied method.
76 1
// It is recommended to use this method in every validation method of the constraint.
77 1
func (s Scope) IsIgnored(groups ...string) bool {
78
	return !s.IsApplied(groups...)
79 1
}
80 1
81 1
// IsApplied compares scope validation groups and constraint groups. If one of the scope groups intersects with
82
// the constraint groups, the validation scope should be applied (returns true).
83
// Empty groups are treated as DefaultGroup. To set validation groups use the validator.WithGroups() method.
84
func (s Scope) IsApplied(groups ...string) bool {
85
	if len(s.groups) == 0 {
86 1
		if len(groups) == 0 {
87 1
			return true
88 1
		}
89 1
		for _, g := range groups {
90
			if g == DefaultGroup {
91
				return true
92 1
			}
93 1
		}
94 1
	}
95
96
	for _, g1 := range s.groups {
97
		if len(groups) == 0 {
98
			if g1 == DefaultGroup {
99 1
				return true
100
			}
101
		}
102
		for _, g2 := range groups {
103 1
			if g1 == g2 {
104 1
				return true
105 1
			}
106 1
		}
107
	}
108 1
109
	return false
110 1
}
111 1
112
func (s Scope) validate(arguments ...Argument) error {
113
	return s.Validator().Validate(s.context, arguments...)
114
}
115 1
116
func (s *Scope) applyOptions(options ...Option) error {
117
	for _, option := range options {
118
		err := option.SetUp(s)
119 1
		if err != nil {
120 1
			return fmt.Errorf(`failed to set up option: %w`, err)
121
		}
122
	}
123
124 1
	return nil
125 1
}
126
127 1
func (s Scope) withContext(ctx context.Context) Scope {
128
	s.context = ctx
129
130 1
	return s
131
}
132
133
func (s Scope) withLanguage(tag language.Tag) Scope {
134 1
	s.language = tag
135
136 1
	return s
137
}
138
139
func (s Scope) withGroups(groups ...string) Scope {
140 1
	s.groups = groups
141
	return s
142 1
}
143
144
func newScope(
145
	translator Translator,
146 1
	violationFactory ViolationFactory,
147 1
	constraints map[string]interface{},
148
) Scope {
149
	return Scope{
150
		context:          context.Background(),
151
		translator:       translator,
152
		violationFactory: violationFactory,
153
		constraints:      constraints,
154
	}
155
}
156