objpatch/src/objpatch.nim

57 lines
1.6 KiB
Nim

import hashes, json, strformat, tables
proc diff(old, new: JsonNode): JsonNode =
## return the json fields that are different between the two objects
result = newJObject()
var
oldFields = old.getFields
newFields = new.getFields
oldHashes = newOrderedTable[string, Hash]()
newHashes = newOrderedTable[string, Hash]()
for k, v in old.getFields.pairs:
oldHashes[k] = v.hash
for k, v in new.getFields.pairs:
newHashes[k] = v.hash
if not old.contains(k):
result.add k, v
for k, v in oldHashes.pairs:
if newHashes.contains(k) and newHashes[k] != v:
if oldFields[k].kind == JObject:
result.add k, diff(oldFields[k], newFields[k])
else:
result.add k, newFields[k]
proc combine(old, patch: JsonNode): JsonNode =
## Applies the patch on top of the old data to get the resulting aggregate
## object.
result = newJObject()
var
oldFields = old.getFields
newFields = patch.getFields
for k, v in oldFields.pairs:
result.add k, v
for k, v in newFields.pairs:
if v.kind == JObject:
result.add k, combine(oldFields[k], newFields[k])
else:
result.add k, v
when isMainModule:
let
old = """{"foo": "bar", "shouldnt": "change", "obj": {"is": "fine", "too": false}}""".parseJson
new = """{"foo": "baz", "bar": "boz", "new": "data", "with_an_array": ["foo", "bar", "baz"], "obj": {"hi": "mom"}}""".parseJson
patch = old.diff new
res = old.combine patch
echo fmt"old: {old.pretty}"
echo fmt"new: {new.pretty}"
echo fmt"patch: {patch.pretty}"
echo fmt"result: {res.pretty}"