-
Notifications
You must be signed in to change notification settings - Fork 50
/
metadata.go
128 lines (111 loc) · 2.62 KB
/
metadata.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
package jd
import (
"sort"
"strings"
)
// Metadata is a closed set of values which modify Diff and Equals
// semantics.
type Metadata interface {
is_metadata()
string() string
}
type setMetadata struct{}
type multisetMetadata struct{}
type setkeysMetadata struct {
keys map[string]bool
}
type mergeMetadata struct{}
func (setMetadata) is_metadata() {}
func (multisetMetadata) is_metadata() {}
func (setkeysMetadata) is_metadata() {}
func (mergeMetadata) is_metadata() {}
func (m setMetadata) string() string {
return "set"
}
func (m multisetMetadata) string() string {
return "multiset"
}
func (m setkeysMetadata) string() string {
ks := make([]string, 0)
for k := range m.keys {
ks = append(ks, k)
}
sort.Strings(ks)
// TODO: escape commas.
return "setkeys=" + strings.Join(ks, ",")
}
func (m mergeMetadata) string() string {
// Merge apply to the whole path not just the next
// element. Therefore it is all caps.
return "MERGE"
}
var (
// MULTISET interprets all Arrays as Multisets (bags) during Diff
// and Equals operations.
MULTISET Metadata = multisetMetadata{}
// SET interprets all Arrays as Sets during Diff and Equals
// operations.
SET Metadata = setMetadata{}
// MERGE produces a Diff with merge semantics (RFC 7386).
MERGE Metadata = mergeMetadata{}
)
// SetKeys constructs Metadata to identify unique objects in an Array for
// deeper Diff and Patch operations.
func Setkeys(keys ...string) Metadata {
m := setkeysMetadata{
keys: make(map[string]bool),
}
for _, key := range keys {
m.keys[key] = true
}
return m
}
type patchStrategy string
const (
mergePatchStrategy patchStrategy = "merge"
strictPatchStrategy patchStrategy = "strict"
)
func getPatchStrategy(metadata []Metadata) patchStrategy {
if checkMetadata(MERGE, metadata) {
return mergePatchStrategy
}
return strictPatchStrategy
}
func dispatch(n JsonNode, metadata []Metadata) JsonNode {
switch n := n.(type) {
case jsonArray:
if checkMetadata(SET, metadata) {
return jsonSet(n)
}
if checkMetadata(MULTISET, metadata) {
return jsonMultiset(n)
}
return jsonList(n)
}
return n
}
func dispatchRenderOptions(n JsonNode, opts []RenderOption) JsonNode {
metadata := []Metadata{}
for _, o := range opts {
if m, ok := o.(Metadata); ok {
metadata = append(metadata, m)
}
}
return dispatch(n, metadata)
}
func checkMetadata(want Metadata, metadata []Metadata) bool {
for _, o := range metadata {
if o == want {
return true
}
}
return false
}
func getSetkeysMetadata(metadata []Metadata) *setkeysMetadata {
for _, o := range metadata {
if s, ok := o.(setkeysMetadata); ok {
return &s
}
}
return nil
}