Skip to content
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

Ability to generate test operations for original values in the first object (continuation) #228

Merged
merged 16 commits into from
Jul 25, 2019
Merged
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
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ before_script:
- npm install
- npm run serve &
script:
- npm run test-sauce
- npm run test
40 changes: 35 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,24 @@ var patch = jsonpatch.generate(observer);
// ];
```

Generating patches with test operations for values in the first object:

```js
var document = { firstName: "Joachim", lastName: "Wester", contactDetails: { phoneNumbers: [ { number:"555-123" }] } };
var observer = jsonpatch.observe(document);
document.firstName = "Albert";
document.contactDetails.phoneNumbers[0].number = "123";
document.contactDetails.phoneNumbers.push({ number:"456" });
var patch = jsonpatch.generate(observer, true);
// patch == [
// { op: "test", path: "/firstName", value: "Joachim"},
// { op: "replace", path: "/firstName", value: "Albert"},
// { op: "test", path: "/contactDetails/phoneNumbers/0/number", value: "555-123" },
// { op: "replace", path: "/contactDetails/phoneNumbers/0/number", value: "123" },
// { op: "add", path: "/contactDetails/phoneNumbers/1", value: {number:"456"}}
// ];
```

Comparing two object trees:

```js
Expand All @@ -163,6 +181,18 @@ var diff = jsonpatch.compare(documentA, documentB);
//diff == [{op: "replace", path: "/user/lastName", value: "Collins"}]
```

Comparing two object trees with test operations for values in the first object:

```js
var documentA = {user: {firstName: "Albert", lastName: "Einstein"}};
var documentB = {user: {firstName: "Albert", lastName: "Collins"}};
var diff = jsonpatch.compare(documentA, documentB, true);
//diff == [
// {op: "test", path: "/user/lastName", value: "Einstein"},
// {op: "replace", path: "/user/lastName", value: "Collins"}
// ];
```

Validating a sequence of patches:

```js
Expand Down Expand Up @@ -269,10 +299,10 @@ callback is called with the generated patches array as the parameter.

Returns `observer`.

#### `jsonpatch.generate(document: any, observer: Observer): Operation[]`
#### `jsonpatch.generate(document: any, observer: Observer, invertible = false): Operation[]`

If there are pending changes in `obj`, returns them synchronously. If a `callback` was defined in `observe`
method, it will be triggered synchronously as well.
method, it will be triggered synchronously as well. If `invertible` is true, then each change will be preceded by a test operation of the value before the change.

If there are no pending changes in `obj`, returns an empty array (length 0).

Expand All @@ -282,9 +312,9 @@ Destroys the observer set up on `document`.

Any remaining changes are delivered synchronously (as in `jsonpatch.generate`). Note: this is different that ES6/7 `Object.unobserve`, which delivers remaining changes asynchronously.

#### `jsonpatch.compare(document1: any, document2: any): Operation[]`
#### `jsonpatch.compare(document1: any, document2: any, invertible = false): Operation[]`

Compares object trees `document1` and `document2` and returns the difference relative to `document1` as a patches array.
Compares object trees `document1` and `document2` and returns the difference relative to `document1` as a patches array. If `invertible` is true, then each change will be preceded by a test operation of the value in `document1`.

If there are no differences, returns an empty array (length 0).

Expand Down Expand Up @@ -346,7 +376,7 @@ Functions `applyPatch`, `applyOperation`, and `validate` accept a `validate`/ `v
If you pass a validator, it will be called with four parameters for each operation, `function(operation, index, tree, existingPath)` and it is expected to throw `JsonPatchError` when your conditions are not met.

- `operation` The operation it self.
- `index` `operation`'s index in the patch array (if application).
- `index` `operation`'s index in the patch array (if application).
- `tree` The object that is supposed to be patched.
- `existingPath` the path `operation` points to.

Expand Down
29 changes: 20 additions & 9 deletions dist/fast-json-patch.js
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
*/
var helpers_1 = __webpack_require__(0);
var core_1 = __webpack_require__(1);
/* export all core functions */
/* export all core functions and types */
var core_2 = __webpack_require__(1);
exports.applyOperation = core_2.applyOperation;
exports.applyPatch = core_2.applyPatch;
Expand Down Expand Up @@ -722,7 +722,8 @@ exports.unobserve = unobserve;
/**
* Observes changes made to an object, which can then be retrieved using generate
*/
function observe(obj, callback) {
function observe(obj, callback, inversible) {
if (inversible === void 0) { inversible = false; }
var patches = [];
var observer;
var mirror = getMirror(obj);
Expand All @@ -737,7 +738,7 @@ function observe(obj, callback) {
if (observer) {
return observer;
}
observer = {};
observer = { inversible: inversible };
mirror.value = helpers_1._deepClone(obj);
if (callback) {
observer.callback = callback;
Expand Down Expand Up @@ -794,9 +795,11 @@ exports.observe = observe;
/**
* Generate an array of patches from an observer
*/
function generate(observer) {
function generate(observer, opts) {
if (opts === void 0) { opts = {}; }
var mirror = beforeDict.get(observer.object);
_generate(mirror.value, observer.object, observer.patches, "");
var inversible = typeof opts.inversible !== "undefined" ? opts.inversible : observer.inversible;
_generate(mirror.value, observer.object, observer.patches, "", { inversible: inversible });
if (observer.patches.length) {
core_1.applyPatch(mirror.value, observer.patches);
}
Expand All @@ -811,7 +814,8 @@ function generate(observer) {
}
exports.generate = generate;
// Dirty check if obj is different from mirror, generate patches and update mirror
function _generate(mirror, obj, patches, path) {
function _generate(mirror, obj, patches, path, opts) {
if (opts === void 0) { opts = { inversible: false }; }
if (obj === mirror) {
return;
}
Expand All @@ -822,27 +826,34 @@ function _generate(mirror, obj, patches, path) {
var oldKeys = helpers_1._objectKeys(mirror);
var changed = false;
var deleted = false;
var inversible = opts.inversible;
//if ever "move" operation is implemented here, make sure this test runs OK: "should not generate the same patch twice (move)"
for (var t = oldKeys.length - 1; t >= 0; t--) {
var key = oldKeys[t];
var oldVal = mirror[key];
if (helpers_1.hasOwnProperty(obj, key) && !(obj[key] === undefined && oldVal !== undefined && Array.isArray(obj) === false)) {
var newVal = obj[key];
if (typeof oldVal == "object" && oldVal != null && typeof newVal == "object" && newVal != null) {
_generate(oldVal, newVal, patches, path + "/" + helpers_1.escapePathComponent(key));
_generate(oldVal, newVal, patches, path + "/" + helpers_1.escapePathComponent(key), opts);
}
else {
if (oldVal !== newVal) {
changed = true;
if (inversible)
patches.push({ op: "test", path: path + "/" + helpers_1.escapePathComponent(key), value: helpers_1._deepClone(oldVal) });
patches.push({ op: "replace", path: path + "/" + helpers_1.escapePathComponent(key), value: helpers_1._deepClone(newVal) });
}
}
}
else if (Array.isArray(mirror) === Array.isArray(obj)) {
if (inversible)
patches.push({ op: "test", path: path + "/" + helpers_1.escapePathComponent(key), value: helpers_1._deepClone(oldVal) });
patches.push({ op: "remove", path: path + "/" + helpers_1.escapePathComponent(key) });
deleted = true; // property has been deleted
}
else {
if (inversible)
patches.push({ op: "test", path: path, value: mirror });
patches.push({ op: "replace", path: path, value: obj });
changed = true;
}
Expand All @@ -860,9 +871,9 @@ function _generate(mirror, obj, patches, path) {
/**
* Create an array of patches from the differences in two objects
*/
function compare(tree1, tree2) {
function compare(tree1, tree2, opts) {
var patches = [];
_generate(tree1, tree2, patches, '');
_generate(tree1, tree2, patches, '', opts);
return patches;
}
exports.compare = compare;
Expand Down
Loading