Test Failed
Pull Request — main (#73)
by Igor
01:52
created

validation.*PropertyPath.With   A

Complexity

Conditions 2

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 5
nop 1
dl 0
loc 7
rs 10
c 0
b 0
f 0
ccs 1
cts 1
cp 1
crap 2
1
package validation
2
3
import (
4
	"encoding/json"
5
	"fmt"
6
	"strconv"
7
)
8
9
// PropertyPathElement is a part of the PropertyPath.
10
type PropertyPathElement interface {
11
	// IsIndex can be used to determine whether an element is a string (property name) or
12
	// an index array.
13
	IsIndex() bool
14
	fmt.Stringer
15
}
16
17
// PropertyNameElement holds up property name value under PropertyPath.
18
type PropertyNameElement string
19
20
// IsIndex on PropertyNameElement always returns false.
21
func (p PropertyNameElement) IsIndex() bool {
22 1
	return false
23
}
24
25
// String returns property name as is.
26
func (p PropertyNameElement) String() string {
27 1
	return string(p)
28
}
29
30
// ArrayIndexElement holds up array index value under PropertyPath.
31
type ArrayIndexElement int
32
33
// IsIndex on ArrayIndexElement always returns true.
34
func (a ArrayIndexElement) IsIndex() bool {
35 1
	return true
36
}
37
38
// String returns array index values converted into a string.
39
func (a ArrayIndexElement) String() string {
40 1
	return strconv.Itoa(int(a))
41
}
42
43
// PropertyPath is generated by the validator and indicates how it reached the invalid value
44
// from the root element. Property path is denoted by dots, while array access
45
// is denoted by square brackets. For example, "book.keywords[0]" means that the violation
46
// occurred on the first element of array "keywords" in the "book" object.
47
//
48
// Internally PropertyPath is a linked list. You can create a new path using WithProperty
49
// or WithIndex methods. PropertyPath should always be used as a pointer value.
50
// Nil value is a valid value that means that the property path is empty.
51
type PropertyPath struct {
52
	parent *PropertyPath
53
	value  PropertyPathElement
54
}
55
56
// NewPropertyPath creates a PropertyPath from the list of elements. If the list is empty nil will be returned.
57
// Nil value is a valid value that means that the property path is empty.
58
func NewPropertyPath(elements ...PropertyPathElement) *PropertyPath {
59 1
	var path *PropertyPath
60 1
61 1
	return path.With(elements...)
62
}
63 1
64
// With returns new PropertyPath with appended elements to the end of the list.
65
func (path *PropertyPath) With(elements ...PropertyPathElement) *PropertyPath {
66
	current := path
67
	for _, element := range elements {
68 1
		current = &PropertyPath{parent: current, value: element}
69
	}
70
71
	return current
72
}
73
74
// WithProperty returns new PropertyPath with appended PropertyNameElement to the end of the list.
75
func (path *PropertyPath) WithProperty(name string) *PropertyPath {
76 1
	return &PropertyPath{
77
		parent: path,
78
		value:  PropertyNameElement(name),
79
	}
80
}
81
82
// WithIndex returns new PropertyPath with appended ArrayIndexElement to the end of the list.
83
func (path *PropertyPath) WithIndex(index int) *PropertyPath {
84 1
	return &PropertyPath{
85 1
		parent: path,
86 1
		value:  ArrayIndexElement(index),
87 1
	}
88 1
}
89
90 1
// String is used to format property path to a string.
91 1
func (path *PropertyPath) String() string {
92 1
	s := ""
93
	element := path
94
	for element != nil {
95 1
		if element.value.IsIndex() {
96
			s = "[" + element.value.String() + "]" + s
97
		} else {
98 1
			s = element.value.String() + s
99
			if element.parent != nil {
100
				s = "." + s
101
			}
102
		}
103 1
		element = element.parent
104
	}
105
106
	return s
107
}
108
109
// MarshalJSON will marshal property path value to a JSON string.
110
func (path *PropertyPath) MarshalJSON() ([]byte, error) {
111
	return json.Marshal(path.String())
112
}
113