Skip to content

Commit

Permalink
handle array splice in merge.apply()
Browse files Browse the repository at this point in the history
  • Loading branch information
sdumetz committed Feb 12, 2024
1 parent 351b3ba commit 34d83f3
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 2 deletions.
6 changes: 6 additions & 0 deletions source/server/utils/merge/apply.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,10 @@ describe("merge.apply()", function(){
expect(apply({a:"A"}, { b:[{name:"A1"}]} as any)).to.deep.equal({a:"A", b:[{name:"A1"}]});
})

it("compacts arrays", function(){
expect(apply({a:[{name: "A"}, {name: "B"}, {name: "C"}]}, {a:{0:{name: "A'"}, 1: DELETE_KEY}} as any)).to.deep.equal({a:[
{name: "A'"},
{name: "C"} // C gets pushed-back to index 2
]});
});
});
11 changes: 9 additions & 2 deletions source/server/utils/merge/apply.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,20 @@ export default function apply<T extends Record<string, any>>(into :T, ...diffs :
const value = diff[key] as T[Extract<keyof T, string>];

if(value === DELETE_KEY){
delete into[key];
if(Array.isArray(into)){
into.splice(key as any, 1);
}else{
delete into[key];
}

}else if(typeof value !== "object" //primitive
|| typeof into[key] === "undefined" //undefined target
){
into[key] = value;
}else if(Array.isArray(value)){
//Replace arrays without looking
//Replace arrays without looking.
//This will generally not happen unles there is an exception in diff() that says so.
//Arrays are generally replaced by a number-indexed object.
into[key] = value;
}else{
//Default case : recurse.
Expand Down
2 changes: 2 additions & 0 deletions source/server/utils/merge/diff.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {Diff, DELETE_KEY} from "./pointers/types.js";
* Computes a diff between two objects.
* Applying deepMerge(a, diff(a,b)) should yield b
* deleted keys are represented using the DELETE_KEY symbol
* It treats arrays as primitives (ie. will overwrite blindly any array)
* @param from origin document
* @param to target document
* @returns
Expand All @@ -30,6 +31,7 @@ export default function diff<T extends Record<string,any>>(from :T, to :T) :Diff
}

//Handle cases where `typeof from[key] === "object"`

if(to[key] == null){
//Null is special because it can't be fed back to diff() recursively
if(from[key] != null ) r[key] = null as T[Extract<keyof T, string>];
Expand Down

0 comments on commit 34d83f3

Please sign in to comment.