mirror of
https://github.com/dragonflydb/dragonfly.git
synced 2024-12-14 11:58:02 +00:00
Signed-off-by: iko1 <me@remotecpp.dev>
This commit is contained in:
parent
40c24d2d25
commit
ad46e5e854
3 changed files with 120 additions and 0 deletions
|
@ -491,8 +491,69 @@ OpResult<long> OpDel(const OpArgs& op_args, string_view key, string_view path) {
|
|||
return total_deletions;
|
||||
}
|
||||
|
||||
// Returns a vector of string vectors,
|
||||
// keys within the same object are stored in the same string vector.
|
||||
OpResult<vector<StringVec>> OpObjKeys(const OpArgs& op_args, string_view key,
|
||||
JsonExpression expression) {
|
||||
OpResult<json> result = GetJson(op_args, key);
|
||||
if (!result) {
|
||||
return result.status();
|
||||
}
|
||||
|
||||
vector<StringVec> vec;
|
||||
auto cb = [&vec](const string_view& path, const json& val) {
|
||||
// Aligned with ElastiCache flavor.
|
||||
if (!val.is_object()) {
|
||||
vec.emplace_back();
|
||||
return;
|
||||
}
|
||||
|
||||
auto& current_object = vec.emplace_back();
|
||||
for (const auto& member : val.object_range()) {
|
||||
current_object.emplace_back(member.key());
|
||||
}
|
||||
};
|
||||
|
||||
expression.evaluate(*result, cb);
|
||||
return vec;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void JsonFamily::ObjKeys(CmdArgList args, ConnectionContext* cntx) {
|
||||
string_view key = ArgS(args, 1);
|
||||
string_view path = ArgS(args, 2);
|
||||
|
||||
error_code ec;
|
||||
JsonExpression expression = jsonpath::make_expression<json>(path, ec);
|
||||
|
||||
if (ec) {
|
||||
VLOG(1) << "Invalid JSONPath syntax: " << ec.message();
|
||||
(*cntx)->SendError(kSyntaxErr);
|
||||
return;
|
||||
}
|
||||
|
||||
auto cb = [&](Transaction* t, EngineShard* shard) {
|
||||
return OpObjKeys(t->GetOpArgs(shard), key, move(expression));
|
||||
};
|
||||
|
||||
Transaction* trans = cntx->transaction;
|
||||
OpResult<vector<StringVec>> result = trans->ScheduleSingleHopT(move(cb));
|
||||
|
||||
if (result) {
|
||||
(*cntx)->StartArray(result->size());
|
||||
for (auto& it : *result) {
|
||||
if (it.empty()) {
|
||||
(*cntx)->SendNullArray();
|
||||
} else {
|
||||
(*cntx)->SendStringArr(it);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
(*cntx)->SendError(result.status());
|
||||
}
|
||||
}
|
||||
|
||||
void JsonFamily::Del(CmdArgList args, ConnectionContext* cntx) {
|
||||
string_view key = ArgS(args, 1);
|
||||
string_view path;
|
||||
|
@ -742,6 +803,7 @@ void JsonFamily::Register(CommandRegistry* registry) {
|
|||
*registry << CI{"JSON.NUMMULTBY", CO::WRITE | CO::DENYOOM | CO::FAST, 4, 1, 1, 1}.HFUNC(
|
||||
NumMultBy);
|
||||
*registry << CI{"JSON.DEL", CO::WRITE, -2, 1, 1, 1}.HFUNC(Del);
|
||||
*registry << CI{"JSON.OBJKEYS", CO::READONLY | CO::FAST, 3, 1, 1, 1}.HFUNC(ObjKeys);
|
||||
}
|
||||
|
||||
} // namespace dfly
|
||||
|
|
|
@ -29,6 +29,7 @@ class JsonFamily {
|
|||
static void NumIncrBy(CmdArgList args, ConnectionContext* cntx);
|
||||
static void NumMultBy(CmdArgList args, ConnectionContext* cntx);
|
||||
static void Del(CmdArgList args, ConnectionContext* cntx);
|
||||
static void ObjKeys(CmdArgList args, ConnectionContext* cntx);
|
||||
};
|
||||
|
||||
} // namespace dfly
|
||||
|
|
|
@ -514,4 +514,61 @@ TEST_F(JsonFamilyTest, Del) {
|
|||
EXPECT_EQ(resp, R"({})");
|
||||
}
|
||||
|
||||
TEST_F(JsonFamilyTest, ObjKeys) {
|
||||
string json = R"(
|
||||
{"a":{}, "b":{"a":"a"}, "c":{"a":"a", "b":"bb"}, "d":{"a":1, "b":"b", "c":{"a":3,"b":4}}, "e":1}
|
||||
)";
|
||||
|
||||
auto resp = Run({"set", "json", json});
|
||||
ASSERT_THAT(resp, "OK");
|
||||
|
||||
resp = Run({"JSON.OBJKEYS", "json", "$.a"});
|
||||
EXPECT_THAT(resp, ArgType(RespExpr::NIL_ARRAY));
|
||||
|
||||
resp = Run({"JSON.OBJKEYS", "json", "$.b"});
|
||||
EXPECT_THAT(resp.GetVec(), ElementsAre("a"));
|
||||
|
||||
resp = Run({"JSON.OBJKEYS", "json", "$.*"});
|
||||
ASSERT_THAT(resp, ArrLen(5));
|
||||
const auto& arr = resp.GetVec();
|
||||
EXPECT_THAT(arr[0], ArgType(RespExpr::NIL_ARRAY));
|
||||
EXPECT_THAT(arr[1].GetVec(), ElementsAre("a"));
|
||||
EXPECT_THAT(arr[2].GetVec(), ElementsAre("a", "b"));
|
||||
EXPECT_THAT(arr[3].GetVec(), ElementsAre("a", "b", "c"));
|
||||
EXPECT_THAT(arr[4], ArgType(RespExpr::NIL_ARRAY));
|
||||
|
||||
resp = Run({"JSON.OBJKEYS", "json", "$.notfound"});
|
||||
EXPECT_THAT(resp, ArgType(RespExpr::ARRAY));
|
||||
EXPECT_THAT(resp, ArrLen(0));
|
||||
|
||||
json = R"(
|
||||
{"a":[7], "inner": {"a": {"b": 2, "c": 1337}}}
|
||||
)";
|
||||
|
||||
resp = Run({"set", "json", json});
|
||||
ASSERT_THAT(resp, "OK");
|
||||
|
||||
resp = Run({"JSON.OBJKEYS", "json", "$..a"});
|
||||
ASSERT_THAT(resp, ArrLen(2));
|
||||
const auto& arr1 = resp.GetVec();
|
||||
EXPECT_THAT(arr1[0], ArgType(RespExpr::NIL_ARRAY));
|
||||
EXPECT_THAT(arr1[1].GetVec(), ElementsAre("b", "c"));
|
||||
|
||||
json = R"(
|
||||
{"a":{}, "b":{"c":{"d": {"e": 1337}}}}
|
||||
)";
|
||||
|
||||
resp = Run({"set", "json", json});
|
||||
ASSERT_THAT(resp, "OK");
|
||||
|
||||
resp = Run({"JSON.OBJKEYS", "json", "$..*"});
|
||||
ASSERT_THAT(resp, ArrLen(5));
|
||||
const auto& arr2 = resp.GetVec();
|
||||
EXPECT_THAT(arr2[0], ArgType(RespExpr::NIL_ARRAY));
|
||||
EXPECT_THAT(arr2[1].GetVec(), ElementsAre("c"));
|
||||
EXPECT_THAT(arr2[2].GetVec(), ElementsAre("d"));
|
||||
EXPECT_THAT(arr2[3].GetVec(), ElementsAre("e"));
|
||||
EXPECT_THAT(arr2[4], ArgType(RespExpr::NIL_ARRAY));
|
||||
}
|
||||
|
||||
} // namespace dfly
|
||||
|
|
Loading…
Reference in a new issue