Skip to content

Commit

Permalink
✨ implemented JSON Merge Patch (RFC 7396)
Browse files Browse the repository at this point in the history
SQLite's json1 extension (https://www.sqlite.org/json1.html) supports JSON Merge Patch (https://tools.ietf.org/html/rfc7396). As the implementation is trivial and we already support JSON Patch, I think this could be a nice extension to the library.
  • Loading branch information
nlohmann committed Dec 13, 2017
1 parent f7ae143 commit c6e7eae
Show file tree
Hide file tree
Showing 6 changed files with 393 additions and 0 deletions.
40 changes: 40 additions & 0 deletions doc/examples/merge_patch.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#include <iostream>
#include "json.hpp"
#include <iomanip> // for std::setw

using json = nlohmann::json;

int main()
{
// the original document
json document = R"({
"title": "Goodbye!",
"author": {
"givenName": "John",
"familyName": "Doe"
},
"tags": [
"example",
"sample"
],
"content": "This will be unchanged"
})"_json;

// the patch
json patch = R"({
"title": "Hello!",
"phoneNumber": "+01-123-456-7890",
"author": {
"familyName": null
},
"tags": [
"example"
]
})"_json;

// apply the patch
document.merge_patch(patch);

// output original and patched document
std::cout << std::setw(4) << document << std::endl;
}
1 change: 1 addition & 0 deletions doc/examples/merge_patch.link
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<a target="_blank" href="https://wandbox.org/permlink/h13IsbffwmMfqsej"><b>online</b></a>
11 changes: 11 additions & 0 deletions doc/examples/merge_patch.output
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"author": {
"givenName": "John"
},
"content": "This will be unchanged",
"phoneNumber": "+01-123-456-7890",
"tags": [
"example"
],
"title": "Hello!"
}
79 changes: 79 additions & 0 deletions src/json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14165,6 +14165,7 @@ class basic_json
diff for two JSON values.,diff}

@sa @ref patch -- apply a JSON patch
@sa @ref merge_patch -- apply a JSON Merge Patch

@sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902)

Expand Down Expand Up @@ -14296,6 +14297,84 @@ class basic_json
}

/// @}

////////////////////////////////
// JSON Merge Patch functions //
////////////////////////////////

/// @name JSON Merge Patch functions
/// @{

/*!
@brief applies a JSON Merge Patch

The merge patch format is primarily intended for use with the HTTP PATCH
method as a means of describing a set of modifications to a target
resource's content. This function applies a merge patch to the current
JSON value.

The function implements the following algorithm from Section 2 of
[RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396):

```
define MergePatch(Target, Patch):
if Patch is an Object:
if Target is not an Object:
Target = {} // Ignore the contents and set it to an empty Object
for each Name/Value pair in Patch:
if Value is null:
if Name exists in Target:
remove the Name/Value pair from Target
else:
Target[Name] = MergePatch(Target[Name], Value)
return Target
else:
return Patch
```

Thereby, `Target` is the current object; that is, the patch is applied to
the current value.

@param[in] patch the patch to apply

@complexity Linear in the lengths of @a patch.

@liveexample{The following code shows how a JSON Merge Patch is applied to
a JSON document.,merge_patch}

@sa @ref patch -- apply a JSON patch
@sa [RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396)

@since version 3.0.0
*/
void merge_patch(const basic_json& patch)
{
if (patch.is_object())
{
if (not is_object())
{
*this = object();
}
for (auto it = patch.begin(); it != patch.end(); ++it)
{
if (it.value().is_null())
{
erase(it.key());
}
else
{
operator[](it.key()).merge_patch(it.value());
}
}
}
else
{
*this = patch;
}
}

/// @}

};

/////////////
Expand Down
1 change: 1 addition & 0 deletions test/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ SOURCES = src/unit.cpp \
src/unit-iterator_wrapper.cpp \
src/unit-iterators1.cpp \
src/unit-iterators2.cpp \
src/unit-merge_patch.cpp \
src/unit-json_patch.cpp \
src/unit-json_pointer.cpp \
src/unit-meta.cpp \
Expand Down
Loading

0 comments on commit c6e7eae

Please sign in to comment.