update json-patch to fix nil value issue when creating mergepatch

This commit is contained in:
Di Xu 2017-07-20 10:48:18 +08:00
parent 3f887171dd
commit 8447cee0e0
9 changed files with 75 additions and 37 deletions

2
Godeps/Godeps.json generated
View File

@ -1090,7 +1090,7 @@
}, },
{ {
"ImportPath": "github.com/evanphx/json-patch", "ImportPath": "github.com/evanphx/json-patch",
"Rev": "ba18e35c5c1b36ef6334cad706eb681153d2d379" "Rev": "944e07253867aacae43c04b2e6a239005443f33a"
}, },
{ {
"ImportPath": "github.com/exponent-io/jsonpath", "ImportPath": "github.com/exponent-io/jsonpath",

View File

@ -104,7 +104,7 @@
}, },
{ {
"ImportPath": "github.com/evanphx/json-patch", "ImportPath": "github.com/evanphx/json-patch",
"Rev": "ba18e35c5c1b36ef6334cad706eb681153d2d379" "Rev": "944e07253867aacae43c04b2e6a239005443f33a"
}, },
{ {
"ImportPath": "github.com/ghodss/yaml", "ImportPath": "github.com/ghodss/yaml",

View File

@ -40,7 +40,7 @@
}, },
{ {
"ImportPath": "github.com/evanphx/json-patch", "ImportPath": "github.com/evanphx/json-patch",
"Rev": "ba18e35c5c1b36ef6334cad706eb681153d2d379" "Rev": "944e07253867aacae43c04b2e6a239005443f33a"
}, },
{ {
"ImportPath": "github.com/ghodss/yaml", "ImportPath": "github.com/ghodss/yaml",

View File

@ -324,7 +324,7 @@
}, },
{ {
"ImportPath": "github.com/evanphx/json-patch", "ImportPath": "github.com/evanphx/json-patch",
"Rev": "ba18e35c5c1b36ef6334cad706eb681153d2d379" "Rev": "944e07253867aacae43c04b2e6a239005443f33a"
}, },
{ {
"ImportPath": "github.com/ghodss/yaml", "ImportPath": "github.com/ghodss/yaml",

View File

@ -112,7 +112,7 @@
}, },
{ {
"ImportPath": "github.com/evanphx/json-patch", "ImportPath": "github.com/evanphx/json-patch",
"Rev": "ba18e35c5c1b36ef6334cad706eb681153d2d379" "Rev": "944e07253867aacae43c04b2e6a239005443f33a"
}, },
{ {
"ImportPath": "github.com/ghodss/yaml", "ImportPath": "github.com/ghodss/yaml",

View File

@ -104,7 +104,7 @@
}, },
{ {
"ImportPath": "github.com/evanphx/json-patch", "ImportPath": "github.com/evanphx/json-patch",
"Rev": "ba18e35c5c1b36ef6334cad706eb681153d2d379" "Rev": "944e07253867aacae43c04b2e6a239005443f33a"
}, },
{ {
"ImportPath": "github.com/ghodss/yaml", "ImportPath": "github.com/ghodss/yaml",

View File

@ -1,13 +1,15 @@
language: go language: go
go: go:
- 1.4 - 1.8
- 1.3 - 1.7
install: install:
- if ! go get code.google.com/p/go.tools/cmd/cover; then go get golang.org/x/tools/cmd/cover; fi - if ! go get code.google.com/p/go.tools/cmd/cover; then go get golang.org/x/tools/cmd/cover; fi
- go get github.com/jessevdk/go-flags
script: script:
- go get
- go test -cover ./... - go test -cover ./...
notifications: notifications:

View File

@ -4,7 +4,6 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"reflect" "reflect"
"strings"
) )
func merge(cur, patch *lazyNode, mergeMerge bool) *lazyNode { func merge(cur, patch *lazyNode, mergeMerge bool) *lazyNode {
@ -28,7 +27,6 @@ func merge(cur, patch *lazyNode, mergeMerge bool) *lazyNode {
func mergeDocs(doc, patch *partialDoc, mergeMerge bool) { func mergeDocs(doc, patch *partialDoc, mergeMerge bool) {
for k, v := range *patch { for k, v := range *patch {
k := decodePatchKey(k)
if v == nil { if v == nil {
if mergeMerge { if mergeMerge {
(*doc)[k] = nil (*doc)[k] = nil
@ -226,6 +224,9 @@ func matchesValue(av, bv interface{}) bool {
if bt == at { if bt == at {
return true return true
} }
case nil:
// Both nil, fine.
return true
case map[string]interface{}: case map[string]interface{}:
bt := bv.(map[string]interface{}) bt := bv.(map[string]interface{})
for key := range at { for key := range at {
@ -250,16 +251,15 @@ func matchesValue(av, bv interface{}) bool {
func getDiff(a, b map[string]interface{}) (map[string]interface{}, error) { func getDiff(a, b map[string]interface{}) (map[string]interface{}, error) {
into := map[string]interface{}{} into := map[string]interface{}{}
for key, bv := range b { for key, bv := range b {
escapedKey := encodePatchKey(key)
av, ok := a[key] av, ok := a[key]
// value was added // value was added
if !ok { if !ok {
into[escapedKey] = bv into[key] = bv
continue continue
} }
// If types have changed, replace completely // If types have changed, replace completely
if reflect.TypeOf(av) != reflect.TypeOf(bv) { if reflect.TypeOf(av) != reflect.TypeOf(bv) {
into[escapedKey] = bv into[key] = bv
continue continue
} }
// Types are the same, compare values // Types are the same, compare values
@ -272,23 +272,23 @@ func getDiff(a, b map[string]interface{}) (map[string]interface{}, error) {
return nil, err return nil, err
} }
if len(dst) > 0 { if len(dst) > 0 {
into[escapedKey] = dst into[key] = dst
} }
case string, float64, bool: case string, float64, bool:
if !matchesValue(av, bv) { if !matchesValue(av, bv) {
into[escapedKey] = bv into[key] = bv
} }
case []interface{}: case []interface{}:
bt := bv.([]interface{}) bt := bv.([]interface{})
if !matchesArray(at, bt) { if !matchesArray(at, bt) {
into[escapedKey] = bv into[key] = bv
} }
case nil: case nil:
switch bv.(type) { switch bv.(type) {
case nil: case nil:
// Both nil, fine. // Both nil, fine.
default: default:
into[escapedKey] = bv into[key] = bv
} }
default: default:
panic(fmt.Sprintf("Unknown type:%T in key %s", av, key)) panic(fmt.Sprintf("Unknown type:%T in key %s", av, key))
@ -303,23 +303,3 @@ func getDiff(a, b map[string]interface{}) (map[string]interface{}, error) {
} }
return into, nil return into, nil
} }
// From http://tools.ietf.org/html/rfc6901#section-4 :
//
// Evaluation of each reference token begins by decoding any escaped
// character sequence. This is performed by first transforming any
// occurrence of the sequence '~1' to '/', and then transforming any
// occurrence of the sequence '~0' to '~'.
var (
rfc6901Encoder = strings.NewReplacer("~", "~0", "/", "~1")
rfc6901Decoder = strings.NewReplacer("~1", "/", "~0", "~")
)
func decodePatchKey(k string) string {
return rfc6901Decoder.Replace(k)
}
func encodePatchKey(k string) string {
return rfc6901Encoder.Replace(k)
}

View File

@ -369,6 +369,15 @@ func (d *partialArray) add(key string, val *lazyNode) error {
cur := *d cur := *d
if idx < 0 {
idx *= -1
if idx > len(ary) {
return fmt.Errorf("Unable to access invalid index: %d", idx)
}
idx = len(ary) - idx
}
copy(ary[0:idx], cur[0:idx]) copy(ary[0:idx], cur[0:idx])
ary[idx] = val ary[idx] = val
copy(ary[idx+1:], cur[idx:]) copy(ary[idx+1:], cur[idx:])
@ -446,6 +455,11 @@ func (p Patch) replace(doc *container, op operation) error {
return fmt.Errorf("jsonpatch replace operation does not apply: doc is missing path: %s", path) return fmt.Errorf("jsonpatch replace operation does not apply: doc is missing path: %s", path)
} }
val, ok := con.get(key)
if val == nil || ok != nil {
return fmt.Errorf("jsonpatch replace operation does not apply: doc is missing key: %s", path)
}
return con.set(key, op.value()) return con.set(key, op.value())
} }
@ -508,6 +522,31 @@ func (p Patch) test(doc *container, op operation) error {
return fmt.Errorf("Testing value %s failed", path) return fmt.Errorf("Testing value %s failed", path)
} }
func (p Patch) copy(doc *container, op operation) error {
from := op.from()
con, key := findObject(doc, from)
if con == nil {
return fmt.Errorf("jsonpatch copy operation does not apply: doc is missing from path: %s", from)
}
val, err := con.get(key)
if err != nil {
return err
}
path := op.path()
con, key = findObject(doc, path)
if con == nil {
return fmt.Errorf("jsonpatch copy operation does not apply: doc is missing destination path: %s", path)
}
return con.set(key, val)
}
// Equal indicates if 2 JSON documents have the same structural equality. // Equal indicates if 2 JSON documents have the same structural equality.
func Equal(a, b []byte) bool { func Equal(a, b []byte) bool {
ra := make(json.RawMessage, len(a)) ra := make(json.RawMessage, len(a))
@ -570,6 +609,8 @@ func (p Patch) ApplyIndent(doc []byte, indent string) ([]byte, error) {
err = p.move(&pd, op) err = p.move(&pd, op)
case "test": case "test":
err = p.test(&pd, op) err = p.test(&pd, op)
case "copy":
err = p.copy(&pd, op)
default: default:
err = fmt.Errorf("Unexpected kind: %s", op.kind()) err = fmt.Errorf("Unexpected kind: %s", op.kind())
} }
@ -585,3 +626,18 @@ func (p Patch) ApplyIndent(doc []byte, indent string) ([]byte, error) {
return json.Marshal(pd) return json.Marshal(pd)
} }
// From http://tools.ietf.org/html/rfc6901#section-4 :
//
// Evaluation of each reference token begins by decoding any escaped
// character sequence. This is performed by first transforming any
// occurrence of the sequence '~1' to '/', and then transforming any
// occurrence of the sequence '~0' to '~'.
var (
rfc6901Decoder = strings.NewReplacer("~1", "/", "~0", "~")
)
func decodePatchKey(k string) string {
return rfc6901Decoder.Replace(k)
}