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) {

Reply via email to