commit d0f1b8287d3af5533178183ed715ffd474311a5c Author: Christine Dodrill Date: Wed Sep 18 19:30:14 2019 +0000 initial commit diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..87df039 --- /dev/null +++ b/LICENSE @@ -0,0 +1,12 @@ +Copyright (c) 2019 Christine Dodrill + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. \ No newline at end of file diff --git a/objpatch.nimble b/objpatch.nimble new file mode 100644 index 0000000..634dece --- /dev/null +++ b/objpatch.nimble @@ -0,0 +1,14 @@ +# Package + +version = "0.1.0" +author = "Christine Dodrill" +description = "Store JSON objects and patches to them, then query the aggregate object" +license = "0BSD" +srcDir = "src" +bin = @["objpatch"] + + + +# Dependencies + +requires "nim >= 0.20.2" diff --git a/src/objpatch.nim b/src/objpatch.nim new file mode 100644 index 0000000..d38bc9b --- /dev/null +++ b/src/objpatch.nim @@ -0,0 +1,56 @@ +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}"