From 9d7a8df7850ae5ac649c794b9186c73e7cd4c370 Mon Sep 17 00:00:00 2001 From: Sam Ward Date: Wed, 29 May 2019 17:11:39 -0700 Subject: [PATCH 1/3] Expose Operation and methods, fix lint errors --- patch.go | 108 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 77 insertions(+), 31 deletions(-) diff --git a/patch.go b/patch.go index c9cf590..38aff8e 100644 --- a/patch.go +++ b/patch.go @@ -3,6 +3,7 @@ package jsonpatch import ( "bytes" "encoding/json" + "errors" "fmt" "strconv" "strings" @@ -18,10 +19,10 @@ var ( // SupportNegativeIndices decides whether to support non-standard practice of // allowing negative indices to mean indices starting at the end of an array. // Default to true. - SupportNegativeIndices bool = true + SupportNegativeIndices = true // AccumulatedCopySizeLimit limits the total size increase in bytes caused by // "copy" operations in a patch. - AccumulatedCopySizeLimit int64 = 0 + AccumulatedCopySizeLimit int64 ) type lazyNode struct { @@ -31,10 +32,11 @@ type lazyNode struct { which int } -type operation map[string]*json.RawMessage +// Operation is a single JSON-Patch step, such as a single 'add' operation. +type Operation map[string]*json.RawMessage -// Patch is an ordered collection of operations. -type Patch []operation +// Patch is an ordered collection of Operations. +type Patch []Operation type partialDoc map[string]*lazyNode type partialArray []*lazyNode @@ -227,7 +229,8 @@ func (n *lazyNode) equal(o *lazyNode) bool { return true } -func (o operation) kind() string { +// Kind reads the "op" field of the Operation. +func (o Operation) Kind() string { if obj, ok := o["op"]; ok && obj != nil { var op string @@ -243,39 +246,41 @@ func (o operation) kind() string { return "unknown" } -func (o operation) path() string { +// Path reads the "path" field of the Operation. +func (o Operation) Path() (string, error) { if obj, ok := o["path"]; ok && obj != nil { var op string err := json.Unmarshal(*obj, &op) if err != nil { - return "unknown" + return "unknown", err } - return op + return op, nil } - return "unknown" + return "unknown", errors.New("operation missing path field") } -func (o operation) from() string { +// From reads the "from" field of the Operation. +func (o Operation) From() (string, error) { if obj, ok := o["from"]; ok && obj != nil { var op string err := json.Unmarshal(*obj, &op) if err != nil { - return "unknown" + return "unknown", err } - return op + return op, nil } - return "unknown" + return "unknown", errors.New("operation missing from field") } -func (o operation) value() *lazyNode { +func (o Operation) value() *lazyNode { if obj, ok := o["value"]; ok { return newLazyNode(obj) } @@ -283,6 +288,23 @@ func (o operation) value() *lazyNode { return nil } +// ValueInterface decodes the operation value into an interface. +func (o Operation) ValueInterface() (interface{}, error) { + if obj, ok := o["value"]; ok && obj != nil { + var v interface{} + + err := json.Unmarshal(*obj, &v) + + if err != nil { + return nil, err + } + + return v, nil + } + + return nil, errors.New("operation missing value field") +} + func isArray(buf []byte) bool { Loop: for _, c := range buf { @@ -462,8 +484,11 @@ func (d *partialArray) remove(key string) error { } -func (p Patch) add(doc *container, op operation) error { - path := op.path() +func (p Patch) add(doc *container, op Operation) error { + path, err := op.Path() + if err != nil { + return fmt.Errorf("jsonpatch add operation failed to decode path: %s", err) + } con, key := findObject(doc, path) @@ -474,8 +499,11 @@ func (p Patch) add(doc *container, op operation) error { return con.add(key, op.value()) } -func (p Patch) remove(doc *container, op operation) error { - path := op.path() +func (p Patch) remove(doc *container, op Operation) error { + path, err := op.Path() + if err != nil { + return fmt.Errorf("jsonpatch remove operation failed to decode path: %s", err) + } con, key := findObject(doc, path) @@ -486,8 +514,11 @@ func (p Patch) remove(doc *container, op operation) error { return con.remove(key) } -func (p Patch) replace(doc *container, op operation) error { - path := op.path() +func (p Patch) replace(doc *container, op Operation) error { + path, err := op.Path() + if err != nil { + return fmt.Errorf("jsonpatch replace operation failed to decode path: %s", err) + } con, key := findObject(doc, path) @@ -503,8 +534,11 @@ func (p Patch) replace(doc *container, op operation) error { return con.set(key, op.value()) } -func (p Patch) move(doc *container, op operation) error { - from := op.from() +func (p Patch) move(doc *container, op Operation) error { + from, err := op.From() + if err != nil { + return fmt.Errorf("jsonpatch _ operation failed to decode from: %s", err) + } con, key := findObject(doc, from) @@ -522,7 +556,10 @@ func (p Patch) move(doc *container, op operation) error { return err } - path := op.path() + path, err := op.Path() + if err != nil { + return fmt.Errorf("jsonpatch _ operation failed to decode path: %s", err) + } con, key = findObject(doc, path) @@ -533,8 +570,11 @@ func (p Patch) move(doc *container, op operation) error { return con.add(key, val) } -func (p Patch) test(doc *container, op operation) error { - path := op.path() +func (p Patch) test(doc *container, op Operation) error { + path, err := op.Path() + if err != nil { + return fmt.Errorf("jsonpatch _ operation failed to decode path: %s", err) + } con, key := findObject(doc, path) @@ -564,8 +604,11 @@ func (p Patch) test(doc *container, op operation) error { return fmt.Errorf("Testing value %s failed", path) } -func (p Patch) copy(doc *container, op operation, accumulatedCopySize *int64) error { - from := op.from() +func (p Patch) copy(doc *container, op Operation, accumulatedCopySize *int64) error { + from, err := op.From() + if err != nil { + return fmt.Errorf("jsonpatch _ operation failed to decode from: %s", err) + } con, key := findObject(doc, from) @@ -578,7 +621,10 @@ func (p Patch) copy(doc *container, op operation, accumulatedCopySize *int64) er return err } - path := op.path() + path, err := op.Path() + if err != nil { + return fmt.Errorf("jsonpatch _ operation failed to decode path: %s", err) + } con, key = findObject(doc, path) @@ -651,7 +697,7 @@ func (p Patch) ApplyIndent(doc []byte, indent string) ([]byte, error) { var accumulatedCopySize int64 for _, op := range p { - switch op.kind() { + switch op.Kind() { case "add": err = p.add(&pd, op) case "remove": @@ -665,7 +711,7 @@ func (p Patch) ApplyIndent(doc []byte, indent string) ([]byte, error) { case "copy": err = p.copy(&pd, op, &accumulatedCopySize) default: - err = fmt.Errorf("Unexpected kind: %s", op.kind()) + err = fmt.Errorf("Unexpected kind: %s", op.Kind()) } if err != nil { From 250db642d4b83e9a56efd4ea28854f5b4debe07b Mon Sep 17 00:00:00 2001 From: Sam Ward Date: Wed, 29 May 2019 17:19:17 -0700 Subject: [PATCH 2/3] Update error messages --- patch.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/patch.go b/patch.go index 38aff8e..cc4f66e 100644 --- a/patch.go +++ b/patch.go @@ -537,7 +537,7 @@ func (p Patch) replace(doc *container, op Operation) error { func (p Patch) move(doc *container, op Operation) error { from, err := op.From() if err != nil { - return fmt.Errorf("jsonpatch _ operation failed to decode from: %s", err) + return fmt.Errorf("jsonpatch move operation failed to decode from: %s", err) } con, key := findObject(doc, from) @@ -558,7 +558,7 @@ func (p Patch) move(doc *container, op Operation) error { path, err := op.Path() if err != nil { - return fmt.Errorf("jsonpatch _ operation failed to decode path: %s", err) + return fmt.Errorf("jsonpatch move operation failed to decode path: %s", err) } con, key = findObject(doc, path) @@ -573,7 +573,7 @@ func (p Patch) move(doc *container, op Operation) error { func (p Patch) test(doc *container, op Operation) error { path, err := op.Path() if err != nil { - return fmt.Errorf("jsonpatch _ operation failed to decode path: %s", err) + return fmt.Errorf("jsonpatch test operation failed to decode path: %s", err) } con, key := findObject(doc, path) @@ -607,7 +607,7 @@ func (p Patch) test(doc *container, op Operation) error { func (p Patch) copy(doc *container, op Operation, accumulatedCopySize *int64) error { from, err := op.From() if err != nil { - return fmt.Errorf("jsonpatch _ operation failed to decode from: %s", err) + return fmt.Errorf("jsonpatch copy operation failed to decode from: %s", err) } con, key := findObject(doc, from) @@ -623,7 +623,7 @@ func (p Patch) copy(doc *container, op Operation, accumulatedCopySize *int64) er path, err := op.Path() if err != nil { - return fmt.Errorf("jsonpatch _ operation failed to decode path: %s", err) + return fmt.Errorf("jsonpatch copy operation failed to decode path: %s", err) } con, key = findObject(doc, path) From 72d00a977af0798c589689fff0a6d06e1651129c Mon Sep 17 00:00:00 2001 From: Sam Ward Date: Mon, 3 Jun 2019 17:32:21 -0700 Subject: [PATCH 3/3] Revert govet fixes --- patch.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/patch.go b/patch.go index cc4f66e..2714a1e 100644 --- a/patch.go +++ b/patch.go @@ -19,10 +19,10 @@ var ( // SupportNegativeIndices decides whether to support non-standard practice of // allowing negative indices to mean indices starting at the end of an array. // Default to true. - SupportNegativeIndices = true + SupportNegativeIndices bool = true // AccumulatedCopySizeLimit limits the total size increase in bytes caused by // "copy" operations in a patch. - AccumulatedCopySizeLimit int64 + AccumulatedCopySizeLimit int64 = 0 ) type lazyNode struct {