* feat(server): Implement ZMSCORE command (#357) Signed-off-by: Logan Raarup <logan@logan.dk>
This commit is contained in:
parent
608a80411a
commit
29fb499d9b
|
@ -4,6 +4,7 @@
|
||||||
* **[Philipp Born](https://github.com/tamcore)**
|
* **[Philipp Born](https://github.com/tamcore)**
|
||||||
* Helm Chart
|
* Helm Chart
|
||||||
* **[Braydn Moore](https://github.com/braydnm)**
|
* **[Braydn Moore](https://github.com/braydnm)**
|
||||||
|
* **[Logan Raarup](https://github.com/logandk)**
|
||||||
* **[Ryan Russell](https://github.com/ryanrussell)**
|
* **[Ryan Russell](https://github.com/ryanrussell)**
|
||||||
* Docs & Code Readability
|
* Docs & Code Readability
|
||||||
* **[Ali-Akber Saifee](https://github.com/alisaifee)**
|
* **[Ali-Akber Saifee](https://github.com/alisaifee)**
|
||||||
|
|
|
@ -1274,6 +1274,35 @@ void ZSetFamily::ZScore(CmdArgList args, ConnectionContext* cntx) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ZSetFamily::ZMScore(CmdArgList args, ConnectionContext* cntx) {
|
||||||
|
string_view key = ArgS(args, 1);
|
||||||
|
|
||||||
|
absl::InlinedVector<string_view, 8> members(args.size() - 2);
|
||||||
|
for (size_t i = 2; i < args.size(); ++i) {
|
||||||
|
members[i - 2] = ArgS(args, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cb = [&](Transaction* t, EngineShard* shard) {
|
||||||
|
return OpMScore(t->GetOpArgs(shard), key, members);
|
||||||
|
};
|
||||||
|
|
||||||
|
OpResult<MScoreResponse> result = cntx->transaction->ScheduleSingleHopT(std::move(cb));
|
||||||
|
|
||||||
|
if (result.status() == OpStatus::WRONG_TYPE) {
|
||||||
|
return (*cntx)->SendError(kWrongTypeErr);
|
||||||
|
}
|
||||||
|
|
||||||
|
(*cntx)->StartArray(result->size());
|
||||||
|
const MScoreResponse& array = result.value();
|
||||||
|
for (const auto& p : array) {
|
||||||
|
if (p) {
|
||||||
|
(*cntx)->SendDouble(*p);
|
||||||
|
} else {
|
||||||
|
(*cntx)->SendNull();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ZSetFamily::ZScan(CmdArgList args, ConnectionContext* cntx) {
|
void ZSetFamily::ZScan(CmdArgList args, ConnectionContext* cntx) {
|
||||||
string_view key = ArgS(args, 1);
|
string_view key = ArgS(args, 1);
|
||||||
string_view token = ArgS(args, 2);
|
string_view token = ArgS(args, 2);
|
||||||
|
@ -1603,6 +1632,32 @@ OpResult<double> ZSetFamily::OpScore(const OpArgs& op_args, string_view key, str
|
||||||
return score;
|
return score;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OpResult<ZSetFamily::MScoreResponse> ZSetFamily::OpMScore(const OpArgs& op_args, string_view key, ArgSlice members) {
|
||||||
|
OpResult<PrimeIterator> res_it = op_args.shard->db_slice().Find(op_args.db_cntx, key, OBJ_ZSET);
|
||||||
|
if (!res_it)
|
||||||
|
return res_it.status();
|
||||||
|
|
||||||
|
MScoreResponse scores(members.size());
|
||||||
|
|
||||||
|
robj* zobj = res_it.value()->second.AsRObj();
|
||||||
|
sds& tmp_str = op_args.shard->tmp_str1;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < members.size(); i++) {
|
||||||
|
const auto& m = members[i];
|
||||||
|
|
||||||
|
tmp_str = sdscpylen(tmp_str, m.data(), m.size());
|
||||||
|
double score;
|
||||||
|
int retval = zsetScore(zobj, tmp_str, &score);
|
||||||
|
if (retval == C_OK) {
|
||||||
|
scores[i] = score;
|
||||||
|
} else {
|
||||||
|
scores[i] = std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return scores;
|
||||||
|
}
|
||||||
|
|
||||||
auto ZSetFamily::OpRange(const ZRangeSpec& range_spec, const OpArgs& op_args, string_view key)
|
auto ZSetFamily::OpRange(const ZRangeSpec& range_spec, const OpArgs& op_args, string_view key)
|
||||||
-> OpResult<ScoredArray> {
|
-> OpResult<ScoredArray> {
|
||||||
OpResult<PrimeIterator> res_it = op_args.shard->db_slice().Find(op_args.db_cntx, key, OBJ_ZSET);
|
OpResult<PrimeIterator> res_it = op_args.shard->db_slice().Find(op_args.db_cntx, key, OBJ_ZSET);
|
||||||
|
@ -1808,6 +1863,7 @@ void ZSetFamily::Register(CommandRegistry* registry) {
|
||||||
<< CI{"ZRANGEBYLEX", CO::READONLY, -4, 1, 1, 1}.HFUNC(ZRangeByLex)
|
<< CI{"ZRANGEBYLEX", CO::READONLY, -4, 1, 1, 1}.HFUNC(ZRangeByLex)
|
||||||
<< CI{"ZRANGEBYSCORE", CO::READONLY, -4, 1, 1, 1}.HFUNC(ZRangeByScore)
|
<< CI{"ZRANGEBYSCORE", CO::READONLY, -4, 1, 1, 1}.HFUNC(ZRangeByScore)
|
||||||
<< CI{"ZSCORE", CO::READONLY | CO::FAST, 3, 1, 1, 1}.HFUNC(ZScore)
|
<< CI{"ZSCORE", CO::READONLY | CO::FAST, 3, 1, 1, 1}.HFUNC(ZScore)
|
||||||
|
<< CI{"ZMSCORE", CO::READONLY | CO::FAST, -3, 1, 1, 1}.HFUNC(ZMScore)
|
||||||
<< CI{"ZREMRANGEBYRANK", CO::WRITE, 4, 1, 1, 1}.HFUNC(ZRemRangeByRank)
|
<< CI{"ZREMRANGEBYRANK", CO::WRITE, 4, 1, 1, 1}.HFUNC(ZRemRangeByRank)
|
||||||
<< CI{"ZREMRANGEBYSCORE", CO::WRITE, 4, 1, 1, 1}.HFUNC(ZRemRangeByScore)
|
<< CI{"ZREMRANGEBYSCORE", CO::WRITE, 4, 1, 1, 1}.HFUNC(ZRemRangeByScore)
|
||||||
<< CI{"ZREMRANGEBYLEX", CO::WRITE, 4, 1, 1, 1}.HFUNC(ZRemRangeByLex)
|
<< CI{"ZREMRANGEBYLEX", CO::WRITE, 4, 1, 1, 1}.HFUNC(ZRemRangeByLex)
|
||||||
|
|
|
@ -62,6 +62,7 @@ class ZSetFamily {
|
||||||
static void ZRank(CmdArgList args, ConnectionContext* cntx);
|
static void ZRank(CmdArgList args, ConnectionContext* cntx);
|
||||||
static void ZRem(CmdArgList args, ConnectionContext* cntx);
|
static void ZRem(CmdArgList args, ConnectionContext* cntx);
|
||||||
static void ZScore(CmdArgList args, ConnectionContext* cntx);
|
static void ZScore(CmdArgList args, ConnectionContext* cntx);
|
||||||
|
static void ZMScore(CmdArgList args, ConnectionContext* cntx);
|
||||||
static void ZRangeByLex(CmdArgList args, ConnectionContext* cntx);
|
static void ZRangeByLex(CmdArgList args, ConnectionContext* cntx);
|
||||||
static void ZRangeByScore(CmdArgList args, ConnectionContext* cntx);
|
static void ZRangeByScore(CmdArgList args, ConnectionContext* cntx);
|
||||||
static void ZRemRangeByRank(CmdArgList args, ConnectionContext* cntx);
|
static void ZRemRangeByRank(CmdArgList args, ConnectionContext* cntx);
|
||||||
|
@ -89,6 +90,9 @@ class ZSetFamily {
|
||||||
static OpResult<unsigned> OpRem(const OpArgs& op_args, std::string_view key, ArgSlice members);
|
static OpResult<unsigned> OpRem(const OpArgs& op_args, std::string_view key, ArgSlice members);
|
||||||
static OpResult<double> OpScore(const OpArgs& op_args, std::string_view key,
|
static OpResult<double> OpScore(const OpArgs& op_args, std::string_view key,
|
||||||
std::string_view member);
|
std::string_view member);
|
||||||
|
using MScoreResponse = std::vector<std::optional<double>>;
|
||||||
|
static OpResult<MScoreResponse> OpMScore(const OpArgs& op_args, std::string_view key,
|
||||||
|
ArgSlice members);
|
||||||
static OpResult<ScoredArray> OpRange(const ZRangeSpec& range_spec, const OpArgs& op_args,
|
static OpResult<ScoredArray> OpRange(const ZRangeSpec& range_spec, const OpArgs& op_args,
|
||||||
std::string_view key);
|
std::string_view key);
|
||||||
static OpResult<unsigned> OpRemRange(const OpArgs& op_args, std::string_view key,
|
static OpResult<unsigned> OpRemRange(const OpArgs& op_args, std::string_view key,
|
||||||
|
|
|
@ -64,6 +64,15 @@ TEST_F(ZSetFamilyTest, ZRem) {
|
||||||
EXPECT_THAT(Run({"zrange", "x", "(-inf", "(+inf", "byscore"}), "a");
|
EXPECT_THAT(Run({"zrange", "x", "(-inf", "(+inf", "byscore"}), "a");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ZSetFamilyTest, ZMScore) {
|
||||||
|
Run({"zadd", "zms", "3.14", "a"});
|
||||||
|
Run({"zadd", "zms", "42", "another"});
|
||||||
|
|
||||||
|
auto resp = Run({"zmscore", "zms", "another", "a", "nofield"});
|
||||||
|
ASSERT_EQ(RespExpr::ARRAY, resp.type);
|
||||||
|
EXPECT_THAT(resp.GetVec(), ElementsAre("42", "3.14", ArgType(RespExpr::NIL)));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(ZSetFamilyTest, ZRangeRank) {
|
TEST_F(ZSetFamilyTest, ZRangeRank) {
|
||||||
Run({"zadd", "x", "1.1", "a", "2.1", "b"});
|
Run({"zadd", "x", "1.1", "a", "2.1", "b"});
|
||||||
EXPECT_THAT(Run({"zrangebyscore", "x", "0", "(1.1"}), ArrLen(0));
|
EXPECT_THAT(Run({"zrangebyscore", "x", "0", "(1.1"}), ArrLen(0));
|
||||||
|
|
Loading…
Reference in New Issue