Skip to content

Commit

Permalink
Ability to generate test operations for original values in the f… (#228)
Browse files Browse the repository at this point in the history
Ability to generate test operations for original values in the first object (continuation)

Co-authored-by: Thomas Pytleski <pytlesk4@gmail.com>
  • Loading branch information
warpech and pytlesk4 committed Jul 25, 2019
2 parents 996c967 + fe85212 commit 8e59102
Show file tree
Hide file tree
Showing 7 changed files with 646 additions and 305 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
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
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
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

0 comments on commit 8e59102

Please sign in to comment.