From a5a183c3a65f1bd4cc53c481015aeaf307127856 Mon Sep 17 00:00:00 2001 From: richard <56808540+littensy@users.noreply.github.com> Date: Fri, 5 Jul 2024 13:14:07 -0700 Subject: [PATCH] fix: handle sparse array patches (#10) --- src/__tests__/sync/client.spec.luau | 16 ++++++++++++++++ src/sync/patch.luau | 8 ++++++++ 2 files changed, 24 insertions(+) diff --git a/src/__tests__/sync/client.spec.luau b/src/__tests__/sync/client.spec.luau index 5aac613..d9a3c65 100644 --- a/src/__tests__/sync/client.spec.luau +++ b/src/__tests__/sync/client.spec.luau @@ -28,4 +28,20 @@ return function() expect(a().b).to.equal(3) expect(a().c).to.equal(2) end) + + it("fixes sparse array patches", function() + local a = atom({ 1 }) + local client = sync.client({ atoms = { a = a } }) + + -- This patch would be the result of a diff between { 1 } and { 1, 2 } that + -- was JSON-serialized and deserialized. The client should be able to catch + -- this and convert the string key back to a number. + client:sync({ + type = "patch", + data = { a = { ["2"] = 2 } }, + }) + + expect(a()["2" :: any]).to.never.be.ok() + expect(a()[2]).to.equal(2) + end) end diff --git a/src/sync/patch.luau b/src/sync/patch.luau index 0ae53f1..d4c9893 100644 --- a/src/sync/patch.luau +++ b/src/sync/patch.luau @@ -44,8 +44,16 @@ local function apply(state: any, patches: any): any end local nextState = table.clone(state) + local stateIsArray = state[1] ~= nil for key, patch in patches do + -- Diff-checking an array produces a sparse array, which will not be + -- preserved when converted to JSON. To prevent this, we turn string + -- keys back into numeric keys. + if stateIsArray and type(key) == "string" then + key = tonumber(key) or key + end + nextState[key] = apply(nextState[key], patch) end