Skip to content

Commit 6da2fe3

Browse files
authored
Implement deep-merging support in JSON::merge (#1789)
Fixes: #1788 Signed-off-by: Juan Cruz Viotti <jv@jviotti.com>
1 parent 5ff00f3 commit 6da2fe3

File tree

2 files changed

+47
-1
lines changed

2 files changed

+47
-1
lines changed

src/core/json/json_value.cc

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -861,7 +861,12 @@ auto JSON::clear_except(std::initializer_list<JSON::String> keys) -> void {
861861
auto JSON::merge(const JSON::Object &other) -> void {
862862
assert(this->is_object());
863863
for (const auto &pair : other) {
864-
this->assign(pair.first, pair.second);
864+
const auto maybe_key{this->try_at(pair.first, pair.hash)};
865+
if (maybe_key && maybe_key->is_object() && pair.second.is_object()) {
866+
this->at(pair.first, pair.hash).merge(pair.second.as_object());
867+
} else {
868+
this->assign(pair.first, pair.second);
869+
}
865870
}
866871
}
867872

test/json/json_object_test.cc

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -780,6 +780,47 @@ TEST(JSON_object, merge_with_overlap) {
780780
EXPECT_EQ(document.at("baz").to_integer(), 9);
781781
}
782782

783+
TEST(JSON_object, merge_deep_object) {
784+
auto document{sourcemeta::core::parse_json(R"JSON({
785+
"foo": {
786+
"bar": {
787+
"baz": 1,
788+
"array": [ { "x": 1 } ]
789+
}
790+
},
791+
"x": true
792+
})JSON")};
793+
794+
const auto other{sourcemeta::core::parse_json(R"JSON({
795+
"foo": {
796+
"bar": {
797+
"qux": 2,
798+
"array": [ { "y": 2 }, 2, 3 ]
799+
}
800+
},
801+
"x": {
802+
"y": 1
803+
}
804+
})JSON")};
805+
806+
document.merge(other.as_object());
807+
808+
const auto expected{sourcemeta::core::parse_json(R"JSON({
809+
"foo": {
810+
"bar": {
811+
"baz": 1,
812+
"qux": 2,
813+
"array": [ { "y": 2 }, 2, 3 ]
814+
}
815+
},
816+
"x": {
817+
"y": 1
818+
}
819+
})JSON")};
820+
821+
EXPECT_EQ(document, expected);
822+
}
823+
783824
TEST(JSON_object, at_or_defined) {
784825
const sourcemeta::core::JSON document{{"foo", sourcemeta::core::JSON{true}},
785826
{"bar", sourcemeta::core::JSON{1}}};

0 commit comments

Comments
 (0)