-
-
Notifications
You must be signed in to change notification settings - Fork 104
/
json_pointer.go
144 lines (120 loc) · 2.71 KB
/
json_pointer.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package vulcain
import (
"strings"
"github.com/dunglas/httpsfv"
)
// node represents a node of a JSON document
type node struct {
preload bool
preloadParams []*httpsfv.Params
fields bool
fieldsParams []*httpsfv.Params
path string
parent *node
children []*node
}
// _type is the type of operation to apply, can be Preload or Fields
type _type int
const (
preload _type = iota
fields
)
// importPointers imports JSON pointers in the tree
func (n *node) importPointers(t _type, pointers httpsfv.List) {
for _, member := range pointers {
// Ignore invalid value
member, ok := member.(httpsfv.Item)
if !ok {
continue
}
pointer, ok := member.Value.(string)
if !ok {
continue
}
pointer = strings.Trim(pointer, "/")
if pointer != "" {
partsToTree(t, strings.Split(pointer, "/"), n, member.Params)
}
}
}
// String returns a JSON pointer
func (n *node) String() string {
if n.parent == nil {
return "/"
}
s := n.path
c := n.parent
for c != nil {
s = c.path + "/" + s
c = c.parent
}
return s
}
// partsToTree transforms a splitted JSON pointer to a tree
func partsToTree(t _type, parts []string, root *node, params *httpsfv.Params) {
if len(parts) == 0 {
return
}
var child *node
for _, c := range root.children {
if c.path == parts[0] {
child = c
break
}
}
if child == nil {
child = &node{}
child.path = parts[0]
child.parent = root
root.children = append(root.children, child)
}
switch t {
case preload:
child.preload = true
child.preloadParams = append(child.preloadParams, params)
case fields:
child.fields = true
child.fieldsParams = append(child.fieldsParams, params)
}
partsToTree(t, parts[1:], child, params)
}
// hasChildren checks if the node has at least a child of the given type
func (n *node) hasChildren(t _type) bool {
for _, c := range n.children {
if t == preload && c.preload {
return true
}
if t == fields && c.fields {
return true
}
}
return false
}
// httpList transforms the node in an HTTP Structured Field List
func (n *node) httpList(t _type, prefix string) httpsfv.List {
if len(n.children) == 0 {
if prefix == "" {
return httpsfv.List{}
}
var list httpsfv.List
switch t {
case preload:
for _, params := range n.preloadParams {
list = append(list, httpsfv.Item{Value: prefix, Params: params})
}
case fields:
for _, params := range n.fieldsParams {
list = append(list, httpsfv.Item{Value: prefix, Params: params})
}
}
return list
}
var list httpsfv.List
for _, c := range n.children {
if (t == preload && !c.preload) || (t == fields && !c.fields) {
continue
}
list = append(list, c.httpList(t, prefix+"/"+c.path)...)
}
return list
}