Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JSON: support basic legacy path #1829

Open
wants to merge 13 commits into
base: unstable
Choose a base branch
from
5 changes: 4 additions & 1 deletion src/commands/cmd_json.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@

namespace redis {

///
/// JSON.SET <key> <path> <json>
///
class CommandJsonSet : public Commander {
public:
Status Execute(Server *svr, Connection *conn, std::string *output) override {
Expand Down Expand Up @@ -52,7 +55,7 @@ class CommandJsonGet : public Commander {
}
};

REDIS_REGISTER_COMMANDS(MakeCmdAttr<CommandJsonSet>("json.set", -3, "write", 1, 1, 1),
REDIS_REGISTER_COMMANDS(MakeCmdAttr<CommandJsonSet>("json.set", 3, "write", 1, 1, 1),
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should use -3 after set with NX support.

Now I think we only support 3 arguments.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, seems this should be 4 (or -4 if implement NX and other options)

MakeCmdAttr<CommandJsonGet>("json.get", -2, "read-only", 1, 1, 1), );

} // namespace redis
10 changes: 10 additions & 0 deletions src/types/json.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,13 @@ struct JsonValue {

jsoncons::json value;
};

// https://redis.io/docs/data-types/json/path/#legacy-path-syntax
inline std::optional<std::string_view> tryConvertLegacyToJsonPath(std::string_view path) {
// TODO(mwish): currently I only handling the simplest logic,
// port from RedisJson JsonPathParser::parse later.
if (path == ".") {
return "$";
}
return std::nullopt;
}
23 changes: 18 additions & 5 deletions src/types/redis_json.cc
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,13 @@ rocksdb::Status Json::Set(const std::string &user_key, const std::string &path,
Slice rest;
auto s = GetMetadata(kRedisJson, ns_key, &bytes, &metadata, &rest);

std::string_view real_path = path;
if (auto legacy_path = tryConvertLegacyToJsonPath(path); legacy_path.has_value()) {
real_path = legacy_path.value();
}

if (s.IsNotFound()) {
if (path != "$") return rocksdb::Status::InvalidArgument("new objects must be created at the root");
if (real_path != "$") return rocksdb::Status::InvalidArgument("new objects must be created at the root");

auto json_res = JsonValue::FromString(value);
if (!json_res) return rocksdb::Status::InvalidArgument(json_res.Msg());
Expand All @@ -75,7 +80,7 @@ rocksdb::Status Json::Set(const std::string &user_key, const std::string &path,
if (!origin_res) return rocksdb::Status::Corruption(origin_res.Msg());
auto origin = *std::move(origin_res);

auto set_res = origin.Set(path, std::move(new_val));
auto set_res = origin.Set(real_path, std::move(new_val));
if (!set_res) return rocksdb::Status::InvalidArgument(set_res.Msg());

return write(ns_key, &metadata, origin);
Expand All @@ -102,14 +107,22 @@ rocksdb::Status Json::Get(const std::string &user_key, const std::vector<std::st
if (paths.empty()) {
res = std::move(json_val);
} else if (paths.size() == 1) {
auto get_res = json_val.Get(paths[0]);
std::string_view real_path = paths[0];
if (auto legacy_path = tryConvertLegacyToJsonPath(paths[0]); legacy_path.has_value()) {
real_path = legacy_path.value();
}
auto get_res = json_val.Get(real_path);
if (!get_res) return rocksdb::Status::InvalidArgument(get_res.Msg());
res = *std::move(get_res);
} else {
for (const auto &path : paths) {
auto get_res = json_val.Get(path);
std::string_view real_path = path;
if (auto legacy_path = tryConvertLegacyToJsonPath(paths[0]); legacy_path.has_value()) {
real_path = legacy_path.value();
}
auto get_res = json_val.Get(real_path);
if (!get_res) return rocksdb::Status::InvalidArgument(get_res.Msg());
res.value.insert_or_assign(path, std::move(get_res->value));
res.value.insert_or_assign(real_path, std::move(get_res->value));
}
}

Expand Down
18 changes: 18 additions & 0 deletions tests/cppunit/types/json_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,21 @@ TEST_F(RedisJsonTest, Get) {
ASSERT_TRUE(json_->Get(key_, {"$..x", "$..y", "$..z"}, &json_val_).ok());
ASSERT_EQ(json_val_.Dump(), R"({"$..x":[{"y":1},4],"$..y":[[2,{"z":3}],1],"$..z":[{"a":{"x":4}},3]})");
}

TEST_F(RedisJsonTest, LegacyPath) {
ASSERT_THAT(json_->Set(key_, ".", "invalid").ToString(), MatchesRegex(".*syntax_error.*"));
ASSERT_THAT(json_->Set(key_, ".", "{").ToString(), MatchesRegex(".*Unexpected end of file.*"));

ASSERT_TRUE(json_->Set(key_, ".", " \t{\n } ").ok());
ASSERT_TRUE(json_->Get(key_, {"."}, &json_val_).ok());
ASSERT_EQ(json_val_.Dump(), "[{}]");

auto s = json_->Set(key_, ".", "1");
ASSERT_TRUE(s.ok()) << s.ToString();
ASSERT_TRUE(json_->Get(key_, {"."}, &json_val_).ok());
ASSERT_EQ(json_val_.Dump(), "[1]");

ASSERT_TRUE(json_->Set(key_, ".", "[1, 2, 3]").ok());
ASSERT_TRUE(json_->Get(key_, {"."}, &json_val_).ok());
ASSERT_EQ(json_val_.Dump(), "[[1,2,3]]");
mapleFU marked this conversation as resolved.
Show resolved Hide resolved
}