Skip to content

Commit 23edf22

Browse files
committed
Switch to passing ApplyOptions to low-level private methods; Update README
1 parent 680774c commit 23edf22

File tree

3 files changed

+52
-32
lines changed

3 files changed

+52
-32
lines changed

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,22 @@ go get -u github.com/evanphx/json-patch/v5
3939
which limits the total size increase in bytes caused by "copy" operations in a
4040
patch. It defaults to 0, which means there is no limit.
4141

42+
These global variables control the behavior of `jsonpatch.Apply`.
43+
44+
An alternative to `jsonpatch.Apply` is `jsonpatch.ApplyWithOptions` whose behavior
45+
is controlled by an `options` parameter of type `*jsonpatch.ApplyOptions`.
46+
47+
Structure `jsonpatch.ApplyOptions` includes the configuration options above
48+
and adds a new option: `AllowMissingPathOnRemove`.
49+
50+
When `AllowMissingPathOnRemove` is set to `true`, `jsonpatch.ApplyWithOptions` will ignore
51+
`remove` operations whose `path` points to a non-existent location in the JSON document.
52+
`AllowMissingPathOnRemove` defaults to `false` which will lead to `jsonpatch.ApplyWithOptions`
53+
returning an error when hitting a missing `path` on `remove`.
54+
55+
Use `jsonpatch.NewApplyOptions` to create an instance of `jsonpatch.ApplyOptions`
56+
whose values are populated from the global configuration variables.
57+
4258
## Create and apply a merge patch
4359
Given both an original JSON document and a modified JSON document, you can create
4460
a [Merge Patch](https://tools.ietf.org/html/rfc7396) document.

v5/patch.go

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ type partialArray []*lazyNode
5353
type container interface {
5454
get(key string) (*lazyNode, error)
5555
set(key string, val *lazyNode) error
56-
add(key string, val *lazyNode, supportNegativeIndices bool) error
57-
remove(key string, allowMissingPathOnRemove bool, supportNegativeIndices bool) error
56+
add(key string, val *lazyNode, options *ApplyOptions) error
57+
remove(key string, options *ApplyOptions) error
5858
}
5959

6060
// ApplyOptions specifies options for calls to ApplyWithOptions.
@@ -410,7 +410,7 @@ func (d *partialDoc) set(key string, val *lazyNode) error {
410410
return nil
411411
}
412412

413-
func (d *partialDoc) add(key string, val *lazyNode, supportNegativeIndices bool) error {
413+
func (d *partialDoc) add(key string, val *lazyNode, options *ApplyOptions) error {
414414
(*d)[key] = val
415415
return nil
416416
}
@@ -423,10 +423,10 @@ func (d *partialDoc) get(key string) (*lazyNode, error) {
423423
return v, nil
424424
}
425425

426-
func (d *partialDoc) remove(key string, allowMissingPathOnRemove bool, supportNegativeIndices bool) error {
426+
func (d *partialDoc) remove(key string, options *ApplyOptions) error {
427427
_, ok := (*d)[key]
428428
if !ok {
429-
if allowMissingPathOnRemove {
429+
if options.AllowMissingPathOnRemove {
430430
return nil
431431
}
432432
return errors.Wrapf(ErrMissing, "unable to remove nonexistent key: %s", key)
@@ -447,7 +447,7 @@ func (d *partialArray) set(key string, val *lazyNode) error {
447447
return nil
448448
}
449449

450-
func (d *partialArray) add(key string, val *lazyNode, supportNegativeIndices bool) error {
450+
func (d *partialArray) add(key string, val *lazyNode, options *ApplyOptions) error {
451451
if key == "-" {
452452
*d = append(*d, val)
453453
return nil
@@ -469,7 +469,7 @@ func (d *partialArray) add(key string, val *lazyNode, supportNegativeIndices boo
469469
}
470470

471471
if idx < 0 {
472-
if !supportNegativeIndices {
472+
if !options.SupportNegativeIndices {
473473
return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx)
474474
}
475475
if idx < -len(ary) {
@@ -500,7 +500,7 @@ func (d *partialArray) get(key string) (*lazyNode, error) {
500500
return (*d)[idx], nil
501501
}
502502

503-
func (d *partialArray) remove(key string, allowMissingPathOnRemove bool, supportNegativeIndices bool) error {
503+
func (d *partialArray) remove(key string, options *ApplyOptions) error {
504504
idx, err := strconv.Atoi(key)
505505
if err != nil {
506506
return err
@@ -509,18 +509,18 @@ func (d *partialArray) remove(key string, allowMissingPathOnRemove bool, support
509509
cur := *d
510510

511511
if idx >= len(cur) {
512-
if allowMissingPathOnRemove {
512+
if options.AllowMissingPathOnRemove {
513513
return nil
514514
}
515515
return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx)
516516
}
517517

518518
if idx < 0 {
519-
if !supportNegativeIndices {
519+
if !options.SupportNegativeIndices {
520520
return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx)
521521
}
522522
if idx < -len(cur) {
523-
if allowMissingPathOnRemove {
523+
if options.AllowMissingPathOnRemove {
524524
return nil
525525
}
526526
return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx)
@@ -537,7 +537,7 @@ func (d *partialArray) remove(key string, allowMissingPathOnRemove bool, support
537537
return nil
538538
}
539539

540-
func (p Patch) add(doc *container, op Operation, supportNegativeIndices bool) error {
540+
func (p Patch) add(doc *container, op Operation, options *ApplyOptions) error {
541541
path, err := op.Path()
542542
if err != nil {
543543
return errors.Wrapf(ErrMissing, "add operation failed to decode path")
@@ -549,15 +549,15 @@ func (p Patch) add(doc *container, op Operation, supportNegativeIndices bool) er
549549
return errors.Wrapf(ErrMissing, "add operation does not apply: doc is missing path: \"%s\"", path)
550550
}
551551

552-
err = con.add(key, op.value(), supportNegativeIndices)
552+
err = con.add(key, op.value(), options)
553553
if err != nil {
554554
return errors.Wrapf(err, "error in add for path: '%s'", path)
555555
}
556556

557557
return nil
558558
}
559559

560-
func (p Patch) remove(doc *container, op Operation, allowMissingPathOnRemove bool, supportNegativeIndices bool) error {
560+
func (p Patch) remove(doc *container, op Operation, options *ApplyOptions) error {
561561
path, err := op.Path()
562562
if err != nil {
563563
return errors.Wrapf(ErrMissing, "remove operation failed to decode path")
@@ -566,21 +566,21 @@ func (p Patch) remove(doc *container, op Operation, allowMissingPathOnRemove boo
566566
con, key := findObject(doc, path)
567567

568568
if con == nil {
569-
if allowMissingPathOnRemove {
569+
if options.AllowMissingPathOnRemove {
570570
return nil
571571
}
572572
return errors.Wrapf(ErrMissing, "remove operation does not apply: doc is missing path: \"%s\"", path)
573573
}
574574

575-
err = con.remove(key, allowMissingPathOnRemove, supportNegativeIndices)
575+
err = con.remove(key, options)
576576
if err != nil {
577577
return errors.Wrapf(err, "error in remove for path: '%s'", path)
578578
}
579579

580580
return nil
581581
}
582582

583-
func (p Patch) replace(doc *container, op Operation) error {
583+
func (p Patch) replace(doc *container, op Operation, options *ApplyOptions) error {
584584
path, err := op.Path()
585585
if err != nil {
586586
return errors.Wrapf(err, "replace operation failed to decode path")
@@ -605,7 +605,7 @@ func (p Patch) replace(doc *container, op Operation) error {
605605
return nil
606606
}
607607

608-
func (p Patch) move(doc *container, op Operation, allowMissingPathOnRemove bool, supportNegativeIndices bool) error {
608+
func (p Patch) move(doc *container, op Operation, options *ApplyOptions) error {
609609
from, err := op.From()
610610
if err != nil {
611611
return errors.Wrapf(err, "move operation failed to decode from")
@@ -622,7 +622,7 @@ func (p Patch) move(doc *container, op Operation, allowMissingPathOnRemove bool,
622622
return errors.Wrapf(err, "error in move for path: '%s'", key)
623623
}
624624

625-
err = con.remove(key, allowMissingPathOnRemove, supportNegativeIndices)
625+
err = con.remove(key, options)
626626
if err != nil {
627627
return errors.Wrapf(err, "error in move for path: '%s'", key)
628628
}
@@ -638,15 +638,15 @@ func (p Patch) move(doc *container, op Operation, allowMissingPathOnRemove bool,
638638
return errors.Wrapf(ErrMissing, "move operation does not apply: doc is missing destination path: %s", path)
639639
}
640640

641-
err = con.add(key, val, supportNegativeIndices)
641+
err = con.add(key, val, options)
642642
if err != nil {
643643
return errors.Wrapf(err, "error in move for path: '%s'", path)
644644
}
645645

646646
return nil
647647
}
648648

649-
func (p Patch) test(doc *container, op Operation) error {
649+
func (p Patch) test(doc *container, op Operation, options *ApplyOptions) error {
650650
path, err := op.Path()
651651
if err != nil {
652652
return errors.Wrapf(err, "test operation failed to decode path")
@@ -679,7 +679,7 @@ func (p Patch) test(doc *container, op Operation) error {
679679
return errors.Wrapf(ErrTestFailed, "testing value %s failed", path)
680680
}
681681

682-
func (p Patch) copy(doc *container, op Operation, accumulatedCopySize *int64, supportNegativeIndices bool, accumulatedCopySizeLimit int64) error {
682+
func (p Patch) copy(doc *container, op Operation, accumulatedCopySize *int64, options *ApplyOptions) error {
683683
from, err := op.From()
684684
if err != nil {
685685
return errors.Wrapf(err, "copy operation failed to decode from")
@@ -713,11 +713,11 @@ func (p Patch) copy(doc *container, op Operation, accumulatedCopySize *int64, su
713713
}
714714

715715
(*accumulatedCopySize) += int64(sz)
716-
if accumulatedCopySizeLimit > 0 && *accumulatedCopySize > accumulatedCopySizeLimit {
717-
return NewAccumulatedCopySizeError(accumulatedCopySizeLimit, *accumulatedCopySize)
716+
if options.AccumulatedCopySizeLimit > 0 && *accumulatedCopySize > options.AccumulatedCopySizeLimit {
717+
return NewAccumulatedCopySizeError(options.AccumulatedCopySizeLimit, *accumulatedCopySize)
718718
}
719719

720-
err = con.add(key, valCopy, supportNegativeIndices)
720+
err = con.add(key, valCopy, options)
721721
if err != nil {
722722
return errors.Wrapf(err, "error while adding value during copy")
723723
}
@@ -792,17 +792,17 @@ func (p Patch) ApplyIndentWithOptions(doc []byte, indent string, options *ApplyO
792792
for _, op := range p {
793793
switch op.Kind() {
794794
case "add":
795-
err = p.add(&pd, op, options.SupportNegativeIndices)
795+
err = p.add(&pd, op, options)
796796
case "remove":
797-
err = p.remove(&pd, op, options.AllowMissingPathOnRemove, options.SupportNegativeIndices)
797+
err = p.remove(&pd, op, options)
798798
case "replace":
799-
err = p.replace(&pd, op)
799+
err = p.replace(&pd, op, options)
800800
case "move":
801-
err = p.move(&pd, op, options.AllowMissingPathOnRemove, options.SupportNegativeIndices)
801+
err = p.move(&pd, op, options)
802802
case "test":
803-
err = p.test(&pd, op)
803+
err = p.test(&pd, op, options)
804804
case "copy":
805-
err = p.copy(&pd, op, &accumulatedCopySize, options.SupportNegativeIndices, options.AccumulatedCopySizeLimit)
805+
err = p.copy(&pd, op, &accumulatedCopySize, options)
806806
default:
807807
err = fmt.Errorf("Unexpected kind: %s", op.Kind())
808808
}

v5/patch_test.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -652,12 +652,16 @@ func TestAdd(t *testing.T) {
652652
err: "Unable to access invalid index: -1: invalid index referenced",
653653
},
654654
}
655+
656+
options := NewApplyOptions()
657+
655658
for _, tc := range testCases {
656659
t.Run(tc.name, func(t *testing.T) {
657660
key := tc.key
658661
arr := &tc.arr
659662
val := &tc.val
660-
err := arr.add(key, val, !tc.rejectNegativeIndicies)
663+
options.SupportNegativeIndices = !tc.rejectNegativeIndicies
664+
err := arr.add(key, val, options)
661665
if err == nil && tc.err != "" {
662666
t.Errorf("Expected error but got none! %v", tc.err)
663667
} else if err != nil && tc.err == "" {

0 commit comments

Comments
 (0)