1 package jsonpatch
2
3 import (
4 "bytes"
5 "encoding/json"
6 "fmt"
7 "reflect"
8 "strings"
9 )
10
11 var errBadJSONDoc = fmt.Errorf("invalid JSON Document")
12
13 type JsonPatchOperation = Operation
14
15 type Operation struct {
16 Operation string `json:"op"`
17 Path string `json:"path"`
18 Value interface{} `json:"value,omitempty"`
19 }
20
21 func (j *Operation) Json() string {
22 b, _ := json.Marshal(j)
23 return string(b)
24 }
25
26 func (j *Operation) MarshalJSON() ([]byte, error) {
27
28 if j.Value == nil && (j.Operation == "replace" || j.Operation == "add") {
29 return json.Marshal(struct {
30 Operation string `json:"op"`
31 Path string `json:"path"`
32 Value interface{} `json:"value"`
33 }{
34 Operation: j.Operation,
35 Path: j.Path,
36 })
37 }
38
39
40 return json.Marshal(struct {
41 Operation string `json:"op"`
42 Path string `json:"path"`
43 Value interface{} `json:"value,omitempty"`
44 }{
45 Operation: j.Operation,
46 Path: j.Path,
47 Value: j.Value,
48 })
49 }
50
51 type ByPath []Operation
52
53 func (a ByPath) Len() int { return len(a) }
54 func (a ByPath) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
55 func (a ByPath) Less(i, j int) bool { return a[i].Path < a[j].Path }
56
57 func NewOperation(op, path string, value interface{}) Operation {
58 return Operation{Operation: op, Path: path, Value: value}
59 }
60
61
62
63
64
65
66
67 func CreatePatch(a, b []byte) ([]Operation, error) {
68 if bytes.Equal(a, b) {
69 return []Operation{}, nil
70 }
71 var aI interface{}
72 var bI interface{}
73 err := json.Unmarshal(a, &aI)
74 if err != nil {
75 return nil, errBadJSONDoc
76 }
77 err = json.Unmarshal(b, &bI)
78 if err != nil {
79 return nil, errBadJSONDoc
80 }
81 return handleValues(aI, bI, "", []Operation{})
82 }
83
84
85
86
87 func matchesValue(av, bv interface{}) bool {
88 if reflect.TypeOf(av) != reflect.TypeOf(bv) {
89 return false
90 }
91 switch at := av.(type) {
92 case string:
93 bt, ok := bv.(string)
94 if ok && bt == at {
95 return true
96 }
97 case float64:
98 bt, ok := bv.(float64)
99 if ok && bt == at {
100 return true
101 }
102 case bool:
103 bt, ok := bv.(bool)
104 if ok && bt == at {
105 return true
106 }
107 case map[string]interface{}:
108 bt, ok := bv.(map[string]interface{})
109 if !ok {
110 return false
111 }
112 for key := range at {
113 if !matchesValue(at[key], bt[key]) {
114 return false
115 }
116 }
117 for key := range bt {
118 if !matchesValue(at[key], bt[key]) {
119 return false
120 }
121 }
122 return true
123 case []interface{}:
124 bt, ok := bv.([]interface{})
125 if !ok {
126 return false
127 }
128 if len(bt) != len(at) {
129 return false
130 }
131 for key := range at {
132 if !matchesValue(at[key], bt[key]) {
133 return false
134 }
135 }
136 for key := range bt {
137 if !matchesValue(at[key], bt[key]) {
138 return false
139 }
140 }
141 return true
142 }
143 return false
144 }
145
146
147
148
149
150
151
152
153
154
155 var rfc6901Encoder = strings.NewReplacer("~", "~0", "/", "~1")
156
157 func makePath(path string, newPart interface{}) string {
158 key := rfc6901Encoder.Replace(fmt.Sprintf("%v", newPart))
159 if path == "" {
160 return "/" + key
161 }
162 return path + "/" + key
163 }
164
165
166 func diff(a, b map[string]interface{}, path string, patch []Operation) ([]Operation, error) {
167 for key, bv := range b {
168 p := makePath(path, key)
169 av, ok := a[key]
170
171 if !ok {
172 patch = append(patch, NewOperation("add", p, bv))
173 continue
174 }
175
176 var err error
177 patch, err = handleValues(av, bv, p, patch)
178 if err != nil {
179 return nil, err
180 }
181 }
182
183 for key := range a {
184 _, found := b[key]
185 if !found {
186 p := makePath(path, key)
187
188 patch = append(patch, NewOperation("remove", p, nil))
189 }
190 }
191 return patch, nil
192 }
193
194 func handleValues(av, bv interface{}, p string, patch []Operation) ([]Operation, error) {
195 {
196 at := reflect.TypeOf(av)
197 bt := reflect.TypeOf(bv)
198 if at == nil && bt == nil {
199
200 return patch, nil
201 } else if at != bt {
202
203 return append(patch, NewOperation("replace", p, bv)), nil
204 }
205 }
206
207 var err error
208 switch at := av.(type) {
209 case map[string]interface{}:
210 bt := bv.(map[string]interface{})
211 patch, err = diff(at, bt, p, patch)
212 if err != nil {
213 return nil, err
214 }
215 case string, float64, bool:
216 if !matchesValue(av, bv) {
217 patch = append(patch, NewOperation("replace", p, bv))
218 }
219 case []interface{}:
220 bt := bv.([]interface{})
221 n := min(len(at), len(bt))
222 for i := len(at) - 1; i >= n; i-- {
223 patch = append(patch, NewOperation("remove", makePath(p, i), nil))
224 }
225 for i := n; i < len(bt); i++ {
226 patch = append(patch, NewOperation("add", makePath(p, i), bt[i]))
227 }
228 for i := 0; i < n; i++ {
229 var err error
230 patch, err = handleValues(at[i], bt[i], makePath(p, i), patch)
231 if err != nil {
232 return nil, err
233 }
234 }
235 default:
236 panic(fmt.Sprintf("Unknown type:%T ", av))
237 }
238 return patch, nil
239 }
240
241 func min(x int, y int) int {
242 if y < x {
243 return y
244 }
245 return x
246 }
247
View as plain text