718 lines
11 KiB
JavaScript
718 lines
11 KiB
JavaScript
"use strict";
|
|
|
|
const {
|
|
cleverMerge,
|
|
DELETE,
|
|
removeOperations,
|
|
resolveByProperty,
|
|
cachedCleverMerge
|
|
} = require("../lib/util/cleverMerge");
|
|
|
|
describe("cleverMerge", () => {
|
|
const base = {
|
|
a1: [1],
|
|
a2: [1],
|
|
a3: [1],
|
|
b1: [1, "...", 2],
|
|
b2: [1, "...", 2],
|
|
b3: [1, "...", 2],
|
|
bySomething: {
|
|
x: {
|
|
a2: [5],
|
|
a3: [5, "...", 6],
|
|
a4: [5],
|
|
a5: [5, "...", 6],
|
|
b2: [5],
|
|
b3: [5, "...", 6],
|
|
b4: [5],
|
|
b5: [5, "...", 6]
|
|
}
|
|
}
|
|
};
|
|
const cases = {
|
|
"different properties": [{ a: 1 }, { b: 2 }, { a: 1, b: 2 }],
|
|
"same property": [{ a: 1 }, { a: 2 }, { a: 2 }],
|
|
arrays: [
|
|
{ a1: 1, a2: 1, b1: [], b2: [], c1: [1], c2: [1] },
|
|
{
|
|
a1: [2],
|
|
a2: [2, "...", 3],
|
|
b1: [2],
|
|
b2: [2, "...", 3],
|
|
c1: [2],
|
|
c2: [2, "...", 3]
|
|
},
|
|
{
|
|
a1: [2],
|
|
a2: [2, 1, 3],
|
|
b1: [2],
|
|
b2: [2, 3],
|
|
c1: [2],
|
|
c2: [2, 1, 3]
|
|
}
|
|
],
|
|
"by field override": [
|
|
base,
|
|
{
|
|
a1: [8],
|
|
a2: [8],
|
|
a3: [8],
|
|
a4: [8],
|
|
a5: [8],
|
|
b1: [8],
|
|
b2: [8],
|
|
b3: [8],
|
|
b4: [8],
|
|
b5: [8]
|
|
},
|
|
{
|
|
a1: [8],
|
|
a2: [8],
|
|
a3: [8],
|
|
a4: [8],
|
|
a5: [8],
|
|
b1: [8],
|
|
b2: [8],
|
|
b3: [8],
|
|
b4: [8],
|
|
b5: [8]
|
|
}
|
|
],
|
|
"by field extend default": [
|
|
base,
|
|
{
|
|
a1: [8, "..."],
|
|
a2: [8, "..."],
|
|
a3: [8, "..."],
|
|
a4: [8, "..."],
|
|
a5: [8, "..."],
|
|
b1: [8, "..."],
|
|
b2: [8, "..."],
|
|
b3: [8, "..."]
|
|
},
|
|
{
|
|
a1: [8, 1],
|
|
a2: [8, 1],
|
|
a3: [1],
|
|
a4: [8, "..."],
|
|
b1: [8, 1, "...", 2],
|
|
b2: [8, 1, "...", 2],
|
|
b3: [1, "...", 2],
|
|
bySomething: {
|
|
x: {
|
|
a2: [8, 5],
|
|
a3: [8, 5, "...", 6],
|
|
a4: [8, 5],
|
|
a5: [8, 5, "...", 6],
|
|
b2: [8, 5],
|
|
b3: [8, 5, "...", 6],
|
|
b4: [5],
|
|
b5: [5, "...", 6]
|
|
},
|
|
default: {
|
|
a3: [8, "..."],
|
|
a5: [8, "..."],
|
|
b3: [8, "..."]
|
|
}
|
|
}
|
|
}
|
|
],
|
|
"by field override other": [
|
|
base,
|
|
{
|
|
bySomething: {
|
|
y: {
|
|
a1: [8],
|
|
a2: [8],
|
|
a3: [8],
|
|
a4: [8],
|
|
a5: [8],
|
|
b1: [8],
|
|
b2: [8],
|
|
b3: [8],
|
|
b4: [8],
|
|
b5: [8]
|
|
}
|
|
}
|
|
},
|
|
{
|
|
a1: [1],
|
|
a2: [1],
|
|
a3: [1],
|
|
b1: [1, "...", 2],
|
|
b2: [1, "...", 2],
|
|
b3: [1, "...", 2],
|
|
bySomething: {
|
|
x: {
|
|
a2: [5],
|
|
a3: [5, "...", 6],
|
|
a4: [5],
|
|
a5: [5, "...", 6],
|
|
b2: [5],
|
|
b3: [5, "...", 6],
|
|
b4: [5],
|
|
b5: [5, "...", 6]
|
|
},
|
|
y: {
|
|
a1: [8],
|
|
a2: [8],
|
|
a3: [8],
|
|
a4: [8],
|
|
a5: [8],
|
|
b1: [8],
|
|
b2: [8],
|
|
b3: [8],
|
|
b4: [8],
|
|
b5: [8]
|
|
}
|
|
}
|
|
}
|
|
],
|
|
"by field override same": [
|
|
base,
|
|
{
|
|
bySomething: {
|
|
x: {
|
|
a1: [8],
|
|
a2: [8],
|
|
a3: [8],
|
|
a4: [8],
|
|
a5: [8],
|
|
b1: [8],
|
|
b2: [8],
|
|
b3: [8],
|
|
b4: [8],
|
|
b5: [8]
|
|
}
|
|
}
|
|
},
|
|
{
|
|
a1: [1],
|
|
a2: [1],
|
|
a3: [1],
|
|
b1: [1, "...", 2],
|
|
b2: [1, "...", 2],
|
|
b3: [1, "...", 2],
|
|
bySomething: {
|
|
x: {
|
|
a1: [8],
|
|
a2: [8],
|
|
a3: [8],
|
|
a4: [8],
|
|
a5: [8],
|
|
b1: [8],
|
|
b2: [8],
|
|
b3: [8],
|
|
b4: [8],
|
|
b5: [8]
|
|
}
|
|
}
|
|
}
|
|
],
|
|
"by field extend other": [
|
|
base,
|
|
{
|
|
bySomething: {
|
|
y: {
|
|
a1: [8, "..."],
|
|
a2: [8, "..."],
|
|
a3: [8, "..."],
|
|
a4: [8, "..."],
|
|
a5: [8, "..."],
|
|
b1: [8, "..."],
|
|
b2: [8, "..."],
|
|
b3: [8, "..."]
|
|
}
|
|
}
|
|
},
|
|
{
|
|
a1: [1],
|
|
a2: [1],
|
|
a3: [1],
|
|
b1: [1, "...", 2],
|
|
b2: [1, "...", 2],
|
|
b3: [1, "...", 2],
|
|
bySomething: {
|
|
x: {
|
|
a2: [5],
|
|
a3: [5, "...", 6],
|
|
a4: [5],
|
|
a5: [5, "...", 6],
|
|
b2: [5],
|
|
b3: [5, "...", 6],
|
|
b4: [5],
|
|
b5: [5, "...", 6]
|
|
},
|
|
y: {
|
|
a1: [8, "..."],
|
|
a2: [8, "..."],
|
|
a3: [8, "..."],
|
|
a4: [8, "..."],
|
|
a5: [8, "..."],
|
|
b1: [8, "..."],
|
|
b2: [8, "..."],
|
|
b3: [8, "..."]
|
|
}
|
|
}
|
|
}
|
|
],
|
|
"by field extend same": [
|
|
base,
|
|
{
|
|
bySomething: {
|
|
x: {
|
|
a1: [8, "..."],
|
|
a2: [8, "..."],
|
|
a3: [8, "..."],
|
|
a4: [8, "..."],
|
|
a5: [8, "..."],
|
|
b1: [8, "..."],
|
|
b2: [8, "..."],
|
|
b3: [8, "..."]
|
|
}
|
|
}
|
|
},
|
|
{
|
|
a1: [1],
|
|
a2: [1],
|
|
a3: [1],
|
|
b1: [1, "...", 2],
|
|
b2: [1, "...", 2],
|
|
b3: [1, "...", 2],
|
|
bySomething: {
|
|
x: {
|
|
a1: [8, "..."],
|
|
a2: [8, 5],
|
|
a3: [8, 5, "...", 6],
|
|
a4: [8, 5],
|
|
a5: [8, 5, "...", 6],
|
|
b1: [8, "..."],
|
|
b2: [8, 5],
|
|
b3: [8, 5, "...", 6],
|
|
b4: [5],
|
|
b5: [5, "...", 6]
|
|
}
|
|
}
|
|
}
|
|
],
|
|
"by field extend base, same and other": [
|
|
base,
|
|
{
|
|
a1: [7, "..."],
|
|
a2: [7, "..."],
|
|
a3: [7, "..."],
|
|
a4: [7, "..."],
|
|
a5: [7, "..."],
|
|
b1: [7, "..."],
|
|
b2: [7, "..."],
|
|
b3: [7, "..."],
|
|
bySomething: {
|
|
x: {
|
|
a1: [8, "..."],
|
|
a2: [8, "..."],
|
|
a3: [8, "..."],
|
|
a4: [8, "..."],
|
|
a5: [8, "..."],
|
|
b1: [8, "..."],
|
|
b2: [8, "..."],
|
|
b3: [8, "..."]
|
|
},
|
|
y: {
|
|
a1: [9, "..."],
|
|
a2: [9, "..."],
|
|
a3: [9, "..."],
|
|
a4: [9, "..."],
|
|
a5: [9, "..."],
|
|
b1: [9, "..."],
|
|
b2: [9, "..."],
|
|
b3: [9, "..."]
|
|
}
|
|
}
|
|
},
|
|
{
|
|
a1: [7, 1],
|
|
a2: [7, 1],
|
|
a3: [1],
|
|
a4: [7, "..."],
|
|
b1: [7, 1, "...", 2],
|
|
b2: [7, 1, "...", 2],
|
|
b3: [1, "...", 2],
|
|
bySomething: {
|
|
x: {
|
|
a1: [8, "..."],
|
|
a2: [8, 7, 5],
|
|
a3: [8, 7, 5, "...", 6],
|
|
a4: [8, 7, 5],
|
|
a5: [8, 7, 5, "...", 6],
|
|
b1: [8, "..."],
|
|
b2: [8, 7, 5],
|
|
b3: [8, 7, 5, "...", 6],
|
|
b4: [5],
|
|
b5: [5, "...", 6]
|
|
},
|
|
y: {
|
|
a1: [9, "..."],
|
|
a2: [9, "..."],
|
|
a3: [9, 7, "..."],
|
|
a4: [9, "..."],
|
|
a5: [9, 7, "..."],
|
|
b1: [9, "..."],
|
|
b2: [9, "..."],
|
|
b3: [9, 7, "..."]
|
|
},
|
|
default: {
|
|
a3: [7, "..."],
|
|
a5: [7, "..."],
|
|
b3: [7, "..."]
|
|
}
|
|
}
|
|
}
|
|
],
|
|
"by field promoting edge cases": [
|
|
{
|
|
a: [1, "...", 2],
|
|
b: [1, "...", 2],
|
|
c: [1, "...", 2],
|
|
d: [1, "...", 2],
|
|
bySomething: {
|
|
x: {
|
|
a: [3, "...", 4],
|
|
b: [3, "...", 4],
|
|
d: [3, "...", 4]
|
|
},
|
|
y: {
|
|
a: [5],
|
|
b: [5]
|
|
},
|
|
default: {
|
|
a: [6, "...", 7],
|
|
c: [6, "...", 7]
|
|
}
|
|
}
|
|
},
|
|
{
|
|
a: [8, "...", 9],
|
|
b: [8, "...", 9],
|
|
c: [8, "...", 9],
|
|
d: [8, "...", 9]
|
|
},
|
|
{
|
|
a: [1, "...", 2],
|
|
b: [1, "...", 2],
|
|
c: [1, "...", 2],
|
|
d: [1, "...", 2],
|
|
bySomething: {
|
|
x: {
|
|
a: [8, 3, "...", 4, 9],
|
|
b: [8, 3, "...", 4, 9],
|
|
c: [8, "...", 9],
|
|
d: [8, 3, "...", 4, 9]
|
|
},
|
|
y: {
|
|
a: [8, 5, 9],
|
|
b: [8, 5, 9],
|
|
c: [8, "...", 9],
|
|
d: [8, "...", 9]
|
|
},
|
|
default: {
|
|
a: [8, 6, "...", 7, 9],
|
|
b: [8, "...", 9],
|
|
c: [8, 6, "...", 7, 9],
|
|
d: [8, "...", 9]
|
|
}
|
|
}
|
|
}
|
|
],
|
|
"by field clone default": [
|
|
{
|
|
a: 1,
|
|
bySomething: {
|
|
x: {
|
|
b: 2
|
|
},
|
|
default: {
|
|
c: 3
|
|
}
|
|
}
|
|
},
|
|
{
|
|
bySomething: {
|
|
y: {
|
|
d: 4
|
|
}
|
|
}
|
|
},
|
|
{
|
|
a: 1,
|
|
bySomething: {
|
|
x: {
|
|
b: 2
|
|
},
|
|
y: {
|
|
c: 3,
|
|
d: 4
|
|
},
|
|
default: {
|
|
c: 3
|
|
}
|
|
}
|
|
}
|
|
],
|
|
deleting: [
|
|
base,
|
|
{
|
|
a1: DELETE,
|
|
a2: DELETE,
|
|
a3: DELETE,
|
|
a4: DELETE,
|
|
a5: DELETE,
|
|
b1: DELETE,
|
|
b2: DELETE,
|
|
b3: DELETE
|
|
},
|
|
{
|
|
a1: DELETE,
|
|
a2: DELETE,
|
|
a3: DELETE,
|
|
a4: DELETE,
|
|
a5: DELETE,
|
|
b1: DELETE,
|
|
b2: DELETE,
|
|
b3: DELETE,
|
|
bySomething: {
|
|
x: {
|
|
b4: [5],
|
|
b5: [5, "...", 6]
|
|
}
|
|
}
|
|
}
|
|
],
|
|
"merge objects": [
|
|
{
|
|
nested: base
|
|
},
|
|
{
|
|
nested: base
|
|
},
|
|
{
|
|
nested: {
|
|
a1: [1],
|
|
a2: [1],
|
|
a3: [1],
|
|
b1: [1, 1, "...", 2, 2],
|
|
b2: [1, 1, "...", 2, 2],
|
|
b3: [1, "...", 2],
|
|
bySomething: {
|
|
x: {
|
|
a2: [5],
|
|
a3: [5, "...", 6],
|
|
a4: [5],
|
|
a5: [5, 5, "...", 6, 6],
|
|
b2: [5],
|
|
b3: [5, 1, 5, "...", 6, 2, 6],
|
|
b4: [5],
|
|
b5: [5, 5, "...", 6, 6]
|
|
},
|
|
default: {
|
|
b3: [1, "...", 2]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
],
|
|
dynamicSecond: [
|
|
{
|
|
a: 4, // keep
|
|
b: 5, // static override
|
|
c: 6 // dynamic override
|
|
},
|
|
{
|
|
b: 50,
|
|
y: 20,
|
|
byArguments: (x, y, z) => ({
|
|
c: 60,
|
|
x,
|
|
y,
|
|
z
|
|
})
|
|
},
|
|
{
|
|
a: 4,
|
|
b: 50,
|
|
c: 60,
|
|
x: 1,
|
|
y: 2,
|
|
z: 3
|
|
}
|
|
],
|
|
dynamicBoth: [
|
|
{
|
|
a: 4, // keep
|
|
b: 5, // static override
|
|
c: 6, // dynamic override
|
|
byArguments: (x, y, z) => ({
|
|
x, // keep
|
|
y, // static override
|
|
z // dynamic override
|
|
})
|
|
},
|
|
{
|
|
b: 50,
|
|
y: 20,
|
|
byArguments: (x, y, z) => ({
|
|
c: 60,
|
|
z: z * 10
|
|
})
|
|
},
|
|
{
|
|
a: 4,
|
|
b: 50,
|
|
c: 60,
|
|
x: 1,
|
|
y: 20,
|
|
z: 30
|
|
}
|
|
],
|
|
dynamicChained: [
|
|
cleverMerge(
|
|
{
|
|
a: 6, // keep
|
|
b: 7, // static override
|
|
c: 8, // dynamic override
|
|
d: 9, // static override (3rd)
|
|
e: 10, // dynamic override (3rd)
|
|
byArguments: (x, y, z, v, w) => ({
|
|
x, // keep
|
|
y, // static override
|
|
z, // dynamic override
|
|
v, // static override (3rd)
|
|
w // dynamic override (3rd)
|
|
})
|
|
},
|
|
{
|
|
b: 70,
|
|
y: 20,
|
|
byArguments: (x, y, z) => ({
|
|
c: 80,
|
|
z: z * 10
|
|
})
|
|
}
|
|
),
|
|
{
|
|
d: 90,
|
|
v: 40,
|
|
byArguments: (x, y, z, v, w) => ({
|
|
e: 100,
|
|
w: w * 10
|
|
})
|
|
},
|
|
{
|
|
a: 6,
|
|
b: 70,
|
|
c: 80,
|
|
d: 90,
|
|
e: 100,
|
|
x: 1,
|
|
y: 20,
|
|
z: 30,
|
|
v: 40,
|
|
w: 50
|
|
}
|
|
],
|
|
dynamicFalse1: [
|
|
{
|
|
a: 1,
|
|
byArguments: () => false
|
|
},
|
|
{
|
|
b: 2
|
|
},
|
|
false
|
|
],
|
|
dynamicFalse2: [
|
|
{
|
|
a: 1
|
|
},
|
|
{
|
|
b: 2,
|
|
byArguments: () => false
|
|
},
|
|
false
|
|
],
|
|
dynamicFalse3: [
|
|
{
|
|
a: 1,
|
|
byArguments: () => false
|
|
},
|
|
{
|
|
b: 2,
|
|
byArguments: () => false
|
|
},
|
|
false
|
|
],
|
|
nonObject1: [1, 2, 2],
|
|
nonObject2: [1, { a: 1 }, 1],
|
|
nonObject3: [{ a: 1 }, 1, 1],
|
|
nonObject4: [{ a: 1 }, undefined, { a: 1 }],
|
|
nonObject5: [undefined, { a: 1 }, { a: 1 }]
|
|
};
|
|
for (const key of Object.keys(cases)) {
|
|
const testCase = cases[key];
|
|
it(`should merge ${key} correctly`, () => {
|
|
let merged = cleverMerge(testCase[0], testCase[1]);
|
|
let merged1 = cachedCleverMerge(testCase[0], testCase[1]);
|
|
let merged2 = cachedCleverMerge(testCase[0], testCase[1]);
|
|
expect(merged2).toBe(merged1);
|
|
merged = resolveByProperty(merged, "byArguments", 1, 2, 3, 4, 5);
|
|
merged1 = resolveByProperty(merged1, "byArguments", 1, 2, 3, 4, 5);
|
|
merged2 = resolveByProperty(merged2, "byArguments", 1, 2, 3, 4, 5);
|
|
expect(merged).toEqual(testCase[2]);
|
|
expect(merged1).toEqual(testCase[2]);
|
|
expect(merged2).toEqual(testCase[2]);
|
|
});
|
|
}
|
|
|
|
it("should allow to remove operations", () => {
|
|
expect(
|
|
removeOperations({
|
|
a: 1,
|
|
b: DELETE,
|
|
c: ["..."],
|
|
d: [1, "...", 2],
|
|
e: [1, 2, 3],
|
|
f: {
|
|
a: 1,
|
|
b: DELETE,
|
|
c: ["..."],
|
|
d: [1, "...", 2],
|
|
e: [1, 2, 3],
|
|
f: {
|
|
a: 1,
|
|
b: DELETE,
|
|
c: ["..."],
|
|
d: [1, "...", 2],
|
|
e: [1, 2, 3]
|
|
}
|
|
}
|
|
})
|
|
).toEqual({
|
|
a: 1,
|
|
c: [],
|
|
d: [1, 2],
|
|
e: [1, 2, 3],
|
|
f: {
|
|
a: 1,
|
|
c: [],
|
|
d: [1, 2],
|
|
e: [1, 2, 3],
|
|
f: {
|
|
a: 1,
|
|
c: [],
|
|
d: [1, 2],
|
|
e: [1, 2, 3]
|
|
}
|
|
}
|
|
});
|
|
});
|
|
});
|