Passed
Push — main ( f2c4e5...99f745 )
by Igor
57s queued 11s
created

validation.*Scope.describeOptionError   A

Complexity

Conditions 3

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3.0261

Importance

Changes 0
Metric Value
cc 3
eloc 9
dl 0
loc 13
ccs 6
cts 7
cp 0.8571
crap 3.0261
rs 9.95
c 0
b 0
f 0
nop 2
1
package validation
2
3
import (
4
	"context"
5
	"fmt"
6
7
	"github.com/muonsoft/language"
8
)
9
10
// Scope holds the current state of validation. On the client-side of the package,
11
// it can be used to build violations.
12
type Scope struct {
13
	context          context.Context
14
	propertyPath     *PropertyPath
15
	language         language.Tag
16
	translator       Translator
17
	violationFactory ViolationFactory
18
	constraints      map[string]Constraint
19
}
20
21
// Context returns context value that was passed to the validator by Context argument or
22
// by creating scoped validator with the validator.WithContext method.
23
func (s Scope) Context() context.Context {
24 1
	return s.context
25
}
26
27
// BuildViolation is used to create violations in validation methods of constraints.
28
// This method automatically injects the property path and language of the current validation scope.
29
func (s Scope) BuildViolation(code, message string) *ViolationBuilder {
30 1
	b := NewViolationBuilder(s.violationFactory).BuildViolation(code, message)
31 1
	b.SetPropertyPath(s.propertyPath)
32
33 1
	if s.language != language.Und {
34 1
		b.SetLanguage(s.language)
35 1
	} else if s.context != nil {
36 1
		b.SetLanguage(language.FromContext(s.context))
37
	}
38
39 1
	return b
40
}
41
42
// AtProperty returns a copy of the scope with property path appended by the given property name.
43
func (s Scope) AtProperty(name string) Scope {
44 1
	s.propertyPath = s.propertyPath.WithProperty(name)
45
46 1
	return s
47
}
48
49
// AtIndex returns a copy of the scope with property path appended by the given array index.
50
func (s Scope) AtIndex(index int) Scope {
51 1
	s.propertyPath = s.propertyPath.WithIndex(index)
52
53 1
	return s
54
}
55
56
// Validator creates a new validator for the given scope. This validator can be used to perform
57
// complex validation on a custom constraint using existing constraints.
58
func (s Scope) Validator() *Validator {
59 1
	return newScopedValidator(s)
60
}
61
62
func (s *Scope) applyOptions(options ...Option) error {
63 1
	for _, option := range options {
64 1
		var err error
65 1
		if o, ok := option.(internalOption); ok {
66 1
			err = o.setUpOnScope(s)
67
		} else {
68 1
			err = option.SetUp()
69
		}
70 1
		if err != nil {
71 1
			return s.describeOptionError(option, err)
72
		}
73
	}
74
75 1
	return nil
76
}
77
78
func (s *Scope) describeOptionError(option Option, err error) error {
79 1
	c, ok := option.(Constraint)
80 1
	if !ok {
81
		return fmt.Errorf(`failed to set up option: %w`, err)
82
	}
83
84 1
	if s.propertyPath == nil {
85 1
		err = fmt.Errorf(`failed to set up constraint "%s": %w`, c.Name(), err)
86
	} else {
87 1
		err = fmt.Errorf(`failed to set up constraint "%s" at path "%s": %w`, c.Name(), s.propertyPath.String(), err)
88
	}
89
90 1
	return err
91
}
92
93
func (s Scope) withContext(ctx context.Context) Scope {
94 1
	s.context = ctx
95
96 1
	return s
97
}
98
99
func (s Scope) withLanguage(tag language.Tag) Scope {
100 1
	s.language = tag
101
102 1
	return s
103
}
104
105
func newScope(
106
	translator Translator,
107
	violationFactory ViolationFactory,
108
	constraints map[string]Constraint,
109
) Scope {
110 1
	return Scope{
111
		context:          context.Background(),
112
		translator:       translator,
113
		violationFactory: violationFactory,
114
		constraints:      constraints,
115
	}
116
}
117