This is an automated email from the ASF dual-hosted git repository.
twice pushed a commit to branch unstable
in repository https://gitbox.apache.org/repos/asf/kvrocks.git
The following commit(s) were added to refs/heads/unstable by this push:
new 9d83653f Support value setting for nonexistent paths in JSON.SET
(#2178)
9d83653f is described below
commit 9d83653f5bbed5b13610697a357c0fe0870f9c4a
Author: Twice <[email protected]>
AuthorDate: Mon Mar 18 21:06:41 2024 +0900
Support value setting for nonexistent paths in JSON.SET (#2178)
---
src/types/json.h | 32 +++++++++++++++++++++++++++++---
tests/cppunit/types/json_test.cc | 8 ++++++++
2 files changed, 37 insertions(+), 3 deletions(-)
diff --git a/src/types/json.h b/src/types/json.h
index 4b786834..5caf212e 100644
--- a/src/types/json.h
+++ b/src/types/json.h
@@ -151,11 +151,34 @@ struct JsonValue {
Status Set(std::string_view path, JsonValue &&new_value) {
try {
- jsoncons::jsonpath::json_replace(value, path, [&new_value](const
std::string & /*path*/, jsoncons::json &origin) {
- origin = new_value.value;
- });
+ bool is_set = false;
+ jsoncons::jsonpath::json_replace(value, path,
+ [&new_value, &is_set](const std::string
& /*path*/, jsoncons::json &origin) {
+ origin = new_value.value;
+ is_set = true;
+ });
+
+ if (!is_set) {
+ // NOTE: this is a workaround since jsonpath doesn't support replace
for nonexistent paths in jsoncons
+ // and in this workaround we can only accept normalized path
+ // refer to https://github.com/danielaparker/jsoncons/issues/496
+ jsoncons::jsonpath::json_location location =
jsoncons::jsonpath::json_location::parse(path);
+ jsoncons::jsonpointer::json_pointer ptr{};
+
+ for (const auto &element : location) {
+ if (element.has_name())
+ ptr /= element.name();
+ else {
+ ptr /= element.index();
+ }
+ }
+
+ jsoncons::jsonpointer::replace(value, ptr, new_value.value, true);
+ }
} catch (const jsoncons::jsonpath::jsonpath_error &e) {
return {Status::NotOK, e.what()};
+ } catch (const jsoncons::jsonpointer::jsonpointer_error &e) {
+ return {Status::NotOK, e.what()};
}
return Status::OK();
@@ -413,6 +436,9 @@ struct JsonValue {
bool not_exists = jsoncons::jsonpath::json_query(value, path).empty();
if (not_exists) {
+ // NOTE: this is a workaround since jsonpath doesn't support replace
for nonexistent paths in jsoncons
+ // and in this workaround we can only accept normalized path
+ // refer to https://github.com/danielaparker/jsoncons/issues/496
jsoncons::jsonpath::json_location location =
jsoncons::jsonpath::json_location::parse(path);
jsoncons::jsonpointer::json_pointer ptr{};
diff --git a/tests/cppunit/types/json_test.cc b/tests/cppunit/types/json_test.cc
index 82bfa944..40b8f2a1 100644
--- a/tests/cppunit/types/json_test.cc
+++ b/tests/cppunit/types/json_test.cc
@@ -96,6 +96,14 @@ TEST_F(RedisJsonTest, Set) {
ASSERT_EQ(json_val_.Dump().GetValue(), "[{},[]]");
ASSERT_THAT(json_->Set(key_, "$[1]", "invalid").ToString(),
MatchesRegex(".*syntax_error.*"));
ASSERT_TRUE(json_->Del(key_, "$", &result).ok());
+
+ ASSERT_TRUE(json_->Set(key_, "$", R"({"a":1})").ok());
+ ASSERT_TRUE(json_->Set(key_, "$.b", "2").ok());
+ ASSERT_TRUE(json_->Set(key_, "$.c", R"({"x":3})").ok());
+ ASSERT_TRUE(json_->Set(key_, "$.c.y", "4").ok());
+
+ ASSERT_TRUE(json_->Get(key_, {}, &json_val_).ok());
+ ASSERT_EQ(json_val_.value,
jsoncons::json::parse(R"({"a":1,"b":2,"c":{"x":3,"y":4}})"));
}
TEST_F(RedisJsonTest, Get) {