Skip to content

Commit b6f59dc

Browse files
dballanceshockey
authored andcommitted
improve: optimize deep merging for mergeDeep patches (#1217)
* Limit deep merging for mergeDeep patches when properties do not conflict * fix lint * remove invalid comparison * reimplement for more predictable and readable merges + rebase * fix trailing space
1 parent 0a8bd8f commit b6f59dc

File tree

1 file changed

+29
-8
lines changed

1 file changed

+29
-8
lines changed

src/specmap/lib/index.js

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,17 +43,38 @@ function applyPatch(obj, patch, opts) {
4343
}
4444
else if (patch.op === 'mergeDeep') {
4545
const currentValue = getInByJsonPath(obj, patch.path)
46-
const origValPatchValue = Object.assign({}, currentValue)
47-
deepExtend(currentValue, patch.value)
4846

49-
// deepExtend doesn't merge arrays, so we will do it manually
47+
// Iterate the properties of the patch
5048
for (const prop in patch.value) {
51-
if (Object.prototype.hasOwnProperty.call(patch.value, prop)) {
52-
const propVal = patch.value[prop]
53-
if (Array.isArray(propVal)) {
54-
const existing = origValPatchValue[prop] || []
55-
currentValue[prop] = existing.concat(propVal)
49+
const propVal = patch.value[prop]
50+
const isArray = Array.isArray(propVal)
51+
if (isArray) {
52+
// deepExtend doesn't merge arrays, so we will do it manually
53+
const existing = currentValue[prop] || []
54+
currentValue[prop] = existing.concat(propVal)
55+
}
56+
else if (isObject(propVal) && !isArray) {
57+
// If it's an object, iterate it's keys and merge
58+
// if there are conflicting keys, merge deep, otherwise shallow merge
59+
const existing = currentValue[prop] || {}
60+
for (const key in propVal) {
61+
if (Object.prototype.hasOwnProperty.call(existing, key)) {
62+
// if there is a single conflicting key, just deepExtend the entire value
63+
// and break from the loop (since all future keys are also merged)
64+
// We do this because we can't deepExtend two primitives
65+
// (existing[key] & propVal[key] may be primitives)
66+
deepExtend(existing, propVal)
67+
break
68+
}
69+
else {
70+
Object.assign(existing, {[key]: propVal[key]})
71+
}
5672
}
73+
currentValue[prop] = existing
74+
}
75+
else {
76+
// It's a primitive, just replace existing
77+
currentValue[prop] = propVal
5778
}
5879
}
5980
}

0 commit comments

Comments
 (0)