Skip to content
This repository has been archived by the owner on Nov 20, 2024. It is now read-only.

Commit

Permalink
Implement Dictionary.patchDiff (closes #19)
Browse files Browse the repository at this point in the history
  • Loading branch information
cxmeel committed Mar 15, 2024
1 parent c6a0ce9 commit 83e21ec
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/Dictionary/init.luau
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ local dictionary = {
map = require("./map"),
merge = require("./merge"),
mergeDeep = require("./mergeDeep"),
patchDiff = require("./patchDiff"),
removeKey = require("./removeKey"),
removeKeys = require("./removeKeys"),
removeValue = require("./removeValue"),
Expand Down
88 changes: 88 additions & 0 deletions src/Dictionary/patchDiff.luau
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
export type Operation = "add" | "remove" | "replace"

export type Patch<K, V> = {
op: Operation,
path: { K },
value: V,
}

--[=[
@within Dictionary
Returns an array of patches that can be applied to `dictionary` to make it equal to `other`. This is a deep comparison. The patches are similar to those used in [JSON Patch](https://jsonpatch.com/).
```lua
local dictionary1 = {
foo = "bar",
qux = {
baz = "quux",
},
}
local dictionary2 = {
foo = "bar",
qux = {
baz = "quuz",
},
baz = "quux",
}
patchDiff(dictionary1, dictionary2) --[[
{
{ op = "replace", path = { "qux", "baz" }, value = "quuz" },
{ op = "add", path = { "baz" }, value = "quux" },
}
]]
```
]=]
local function patchDiff<K, V, T>(dictionary: { [K]: V }, other: { [K]: V }): { Patch<K, V> }
local out: { any } = {}

for key, value in dictionary do
if other[key] == nil then
table.insert(out, {
op = "remove",
path = { key },
value = value,
})

continue
end

if typeof(value) == "table" then
local subpatches = patchDiff(value, other[key])

for _, patch in subpatches do
table.insert(out, {
op = patch.op :: any,
path = { key, table.unpack(patch.path) },
value = patch.value,
})
end

continue
end

if value ~= other[key] then
table.insert(out, {
op = "replace",
path = { key },
value = other[key],
})
end
end

for key, value in other do
if dictionary[key] == nil then
table.insert(out, {
op = "add",
path = { key },
value = value,
})
end
end

return out
end

return patchDiff

0 comments on commit 83e21ec

Please sign in to comment.