Skip to content

Add support for delete by value #103

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@ go get -u github.com/evanphx/json-patch
functionality can be disabled by setting `jsonpatch.SupportNegativeIndices =
false`.

* There is a global configuration variable `jsonpatch.SupportDeleteByValue`.
This defaults to `true` and enables the support for the non-standard
practice of deleting from an array with value. This functionality
can be disabled by setting `jsonpatch.SupportNegativeIndices = false`.
This can be used by using `-` instead of the array index and specifying the
value to remove in "value". For example:
`[{ "op": "remove", "path": "/foo/-", "value": "qux"}]` will delete
value `qux` from the array `foo`. This works also with values that are objects.

* There is a global configuration variable `jsonpatch.AccumulatedCopySizeLimit`,
which limits the total size increase in bytes caused by "copy" operations in a
patch. It defaults to 0, which means there is no limit.
Expand Down
26 changes: 25 additions & 1 deletion patch.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ var (
// AccumulatedCopySizeLimit limits the total size increase in bytes caused by
// "copy" operations in a patch.
AccumulatedCopySizeLimit int64 = 0
// SupportDeleteByValue decides whether to support non-standard practice of
// allowing deleting from array with value.
SupportDeleteByValue bool = true
)

var (
Expand Down Expand Up @@ -505,6 +508,16 @@ func (d *partialArray) remove(key string) error {

}

func (d *partialArray) removeByValue(key *lazyNode) error {
for i, v := range *d {
if key.equal(v) {
return d.remove(strconv.Itoa(i))
}
}

return errors.Wrapf(ErrInvalidIndex, "value not found")
}

func (p Patch) add(doc *container, op Operation) error {
path, err := op.Path()
if err != nil {
Expand Down Expand Up @@ -537,7 +550,18 @@ func (p Patch) remove(doc *container, op Operation) error {
return errors.Wrapf(ErrMissing, "remove operation does not apply: doc is missing path: \"%s\"", path)
}

err = con.remove(key)
if key == "-" && SupportDeleteByValue {
value := op.value()
switch v := con.(type) {
case *partialArray:
err = v.removeByValue(value)
default:
return errors.Wrapf(ErrInvalid, "cannot delete by value from a non-array")
}
} else {
err = con.remove(key)
}

if err != nil {
return errors.Wrapf(err, "error in remove for path: '%s'", path)
}
Expand Down
19 changes: 19 additions & 0 deletions patch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,21 @@ var Cases = []Case{
`[ { "op": "remove", "path": "/foo/1" } ]`,
`{ "foo": [ "bar", "baz" ] }`,
},
{
`{ "foo": [ "bar", "qux", "baz" ] }`,
`[ { "op": "remove", "path": "/foo/-" , "value": "qux" }]`,
`{ "foo": [ "bar", "baz" ] }`,
},
{
`{ "foo": [ "3", "2", "1" ] }`,
`[ { "op": "remove", "path": "/foo/-" , "value": "1" }]`,
`{ "foo": [ "3", "2" ] }`,
},
{
`{ "foo": [ [ "bar", "qux", "baz" ], [ "bar", "baz" ], "1" ] }`,
`[ { "op": "remove", "path": "/foo/-" , "value": [ "bar", "baz" ] }]`,
`{ "foo": [ [ "bar", "qux", "baz" ], "1" ] }`,
},
{
`{ "baz": "qux", "foo": "bar" }`,
`[ { "op": "replace", "path": "/baz", "value": "boo" } ]`,
Expand Down Expand Up @@ -295,6 +310,10 @@ var BadCases = []BadCase{
`{ "foo": []}`,
`[ {"op": "remove", "path": "/foo/-"}]`,
},
{
`{ "foo": []}`,
`[ {"op": "remove", "path": "/foo/-", "value": "asd"}]`,
},
{
`{ "foo": []}`,
`[ {"op": "remove", "path": "/foo/-1"}]`,
Expand Down