From 21fcf5808e05abdc11cdf3fd13e198d4d44eb7cc Mon Sep 17 00:00:00 2001 From: Roman Gershman Date: Mon, 6 Jan 2025 21:20:52 +0200 Subject: [PATCH] feat: allow querying of json objects stored as strings (#4399) Signed-off-by: Roman Gershman --- src/server/json_family.cc | 24 +++++++++++++++++++++--- src/server/json_family_test.cc | 19 +++++++++++++++++++ 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/server/json_family.cc b/src/server/json_family.cc index 4b070c236e2b..39164ef1a38d 100644 --- a/src/server/json_family.cc +++ b/src/server/json_family.cc @@ -657,11 +657,29 @@ bool LegacyModeIsEnabled(const std::vector OpJsonGet(const OpArgs& op_args, string_view key, const JsonGetParams& params) { - OpResult result = GetJson(op_args, key); - RETURN_ON_BAD_STATUS(result); + auto it = op_args.GetDbSlice().FindReadOnly(op_args.db_cntx, key).it; + if (!IsValid(it)) + return OpStatus::KEY_NOTFOUND; + + const JsonType* json_ptr = nullptr; + JsonType json; + if (it->second.ObjType() == OBJ_JSON) { + json_ptr = it->second.GetJson(); + } else if (it->second.ObjType() == OBJ_STRING) { + string tmp; + it->second.GetString(&tmp); + auto parsed_json = ShardJsonFromString(tmp); + if (!parsed_json) { + return OpStatus::WRONG_TYPE; + } + json.swap(*parsed_json); + json_ptr = &json; + } else { + return OpStatus::WRONG_TYPE; + } const auto& paths = params.paths; - const JsonType& json_entry = *(result.value()); + const JsonType& json_entry = *json_ptr; if (paths.empty()) { // this implicitly means that we're using . which diff --git a/src/server/json_family_test.cc b/src/server/json_family_test.cc index 78c34716c186..729fb6f91649 100644 --- a/src/server/json_family_test.cc +++ b/src/server/json_family_test.cc @@ -2998,4 +2998,23 @@ TEST_F(JsonFamilyTest, MergeLegacy) { EXPECT_EQ(resp, R"({"y":{"doubled":true},"z":{"answers":["xxx","yyy"],"doubled":false}})"); } +TEST_F(JsonFamilyTest, GetString) { + string json = R"( + { "a": "b", + "c": { + "d": "e", + "f": "g" + } + } + )"; + + auto resp = Run({"SET", "json", json}); + EXPECT_THAT(resp, "OK"); + resp = Run({"JSON.GET", "json", "$.c"}); + EXPECT_EQ(resp, R"([{"d":"e","f":"g"}])"); + Run({"SET", "not_json", "not_json"}); + resp = Run({"JSON.GET", "not_json", "$.c"}); + EXPECT_THAT(resp, ErrArg("WRONGTYPE")); +} + } // namespace dfly