Skip to content

Commit

Permalink
docs: JSON Patch guide
Browse files Browse the repository at this point in the history
  • Loading branch information
jg-rp committed Sep 22, 2023
1 parent 4eccc05 commit 4dd2a01
Show file tree
Hide file tree
Showing 3 changed files with 178 additions and 2 deletions.
169 changes: 168 additions & 1 deletion docs/docs/guides/json-patch.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,170 @@
# JSON Patch

TODO:
[JSON Patch](./quick-start.md#json-patch) ([RFC 6902](https://datatracker.ietf.org/doc/html/rfc6902)) is a standard for describing update operations to perform on JSON-like data. Each operation includes, at least, an `op` string and a `path`, which is a [JSON Pointer](./json-pointer.md).

Use [`jsonpatch.apply(ops, data)`](../api/namespaces/jsonpatch.md#apply) to apply _ops_ to _data_, where _ops_ should be an array of [`OpObject`s](../api/namespaces/jsonpatch.md#opobject), as per RFC 6902. Patch operation are applied sequentially and, unless the target JSON document's root value is replaced, **data is modified in place**.

```javascript
import { jsonpatch } from "json-p3";

const ops = [
{ op: "add", path: "/some/foo", value: { foo: {} } },
{ op: "add", path: "/some/foo", value: { bar: [] } },
{ op: "copy", from: "/some/other", path: "/some/foo/else" },
{ op: "add", path: "/some/foo/bar/-", value: 1 },
];

const data = { some: { other: "thing" } };
jsonpatch.apply(ops, data);
console.log(data);
// { some: { other: 'thing', foo: { bar: [Array], else: 'thing' } } }
```

Use the [`JSONPatch`](../api/classes/jsonpatch.JSONPatch.md) constructor to create a patch for repeated application.

```javascript
import { JSONPatch } from "json-p3";

const patch = new JSONPatch([
{ op: "add", path: "/some/foo", value: { foo: {} } },
{ op: "add", path: "/some/foo", value: { bar: [] } },
{ op: "copy", from: "/some/other", path: "/some/foo/else" },
{ op: "add", path: "/some/foo/bar/-", value: 1 },
]);

const data = { some: { other: "thing" } };
patch.apply(data);
console.log(data);
// { some: { other: 'thing', foo: { bar: [Array], else: 'thing' } } }
```

## Builder API

[`JSONPatch`](../api/classes/jsonpatch.JSONPatch.md) implements a builder interface for constructing JSON Patch documents. Each of the following methods appends an operation to the patch and returns the patch instance, so method calls can be chained.

### `add()`

[`JSONPatch.add(pointer, value)`](../api/classes/jsonpatch.JSONPatch.md#add) appends an [_add_](https://datatracker.ietf.org/doc/html/rfc6902#section-4.1) operation to the patch. _pointer_ can be a string following RFC 6901 or an instance of [`JSONPointer`](../api/classes/jsonpointer.JSONPointer.md).

```javascript
import { JSONPatch } from "json-p3";

const patch = new JSONPatch().add("/some/foo", { foo: [] });
console.log(JSON.stringify(patch.toArray(), undefined, " "));
```

```json title="output"
[
{
"op": "add",
"path": "/some/foo",
"value": {
"foo": []
}
}
]
```

### `remove()`

[`JSONPatch.remove(pointer)`](../api/classes/jsonpatch.JSONPatch.md#add) appends an [_remove_](https://datatracker.ietf.org/doc/html/rfc6902#section-4.2) operation to the patch. _pointer_ can be a string following RFC 6901 or an instance of [`JSONPointer`](../api/classes/jsonpointer.JSONPointer.md).

```javascript
import { JSONPatch } from "json-p3";

const patch = new JSONPatch().remove("/some/foo");
console.log(JSON.stringify(patch.toArray(), undefined, " "));
```

```json title="output"
[
{
"op": "remove",
"path": "/some/foo"
}
]
```

### `replace()`

[`JSONPatch.replace(pointer, value)`](../api/classes/jsonpatch.JSONPatch.md#add) appends an [_replace_](https://datatracker.ietf.org/doc/html/rfc6902#section-4.3) operation to the patch. _pointer_ can be a string following RFC 6901 or an instance of [`JSONPointer`](../api/classes/jsonpointer.JSONPointer.md).

```javascript
import { JSONPatch } from "json-p3";

const patch = new JSONPatch().replace("/some/foo", [1, 2, 3]);
console.log(JSON.stringify(patch.toArray(), undefined, " "));
```

```json title="output"
[
{
"op": "replace",
"path": "/some/foo",
"value": [1, 2, 3]
}
]
```

### `move()`

[`JSONPatch.move(fromPointer, toPointer)`](../api/classes/jsonpatch.JSONPatch.md#add) appends an [_move_](https://datatracker.ietf.org/doc/html/rfc6902#section-4.4) operation to the patch. _fromPointer_ and _toPointer_ can be a string following RFC 6901 or an instance of [`JSONPointer`](../api/classes/jsonpointer.JSONPointer.md).

```javascript
import { JSONPatch } from "json-p3";

const patch = new JSONPatch().move("/some/foo", "/other/bar");
console.log(JSON.stringify(patch.toArray(), undefined, " "));
```

```json title="output"
[
{
"op": "move",
"from": "/some/foo",
"path": "/other/bar"
}
]
```

### `copy()`

[`JSONPatch.copy(fromPointer, toPointer)`](../api/classes/jsonpatch.JSONPatch.md#add) appends an [_copy_](https://datatracker.ietf.org/doc/html/rfc6902#section-4.5) operation to the patch. _fromPointer_ and _toPointer_ can be a string following RFC 6901 or an instance of [`JSONPointer`](../api/classes/jsonpointer.JSONPointer.md).

```javascript
import { JSONPatch } from "json-p3";

const patch = new JSONPatch().copy("/some/foo", "/other/bar");
console.log(JSON.stringify(patch.toArray(), undefined, " "));
```

```json title="output"
[
{
"op": "copy",
"from": "/some/foo",
"path": "/other/bar"
}
]
```

### `test()`

[`JSONPatch.copy(pointer, value)`](../api/classes/jsonpatch.JSONPatch.md#add) appends an [_test_](https://datatracker.ietf.org/doc/html/rfc6902#section-4.6) operation to the patch. _pointer_ can be a string following RFC 6901 or an instance of [`JSONPointer`](../api/classes/jsonpointer.JSONPointer.md).

```javascript
import { JSONPatch } from "json-p3";

const patch = new JSONPatch().test("/some/foo", "hello");
console.log(JSON.stringify(patch.toArray(), undefined, " "));
```

```json title="output"
[
{
"op": "test",
"path": "/some/foo",
"value": "hello"
}
]
```
2 changes: 1 addition & 1 deletion docs/docs/guides/jsonpath-syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ We use the terms "target JSON document", "target document" and "query argument"

`$` is the root node identifier, pointing to the first node in the target JSON document.

```text title="Example query"
```text
$.users
```

Expand Down
9 changes: 9 additions & 0 deletions src/patch/patch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,15 @@ export class JSONPatch {
}
}

/**
* @returns an iterator over ops in this patch.
*/
*[Symbol.iterator](): Iterator<OpObject> {
for (const op of this.ops) {
yield op.toObject();
}
}

/**
*
* @param path -
Expand Down

0 comments on commit 4dd2a01

Please sign in to comment.