1
0
Fork 0
mirror of https://github.com/dragonflydb/dragonfly.git synced 2024-12-15 17:51:06 +00:00

Address HSET bugs

1. add hmset
2. hmget returns nulls when key not found
3. test for valid number of arguments in hset
This commit is contained in:
Roman Gershman 2022-04-04 13:08:16 +03:00
parent a845e9bce1
commit 8a1396de31
6 changed files with 31 additions and 43 deletions

View file

@ -87,7 +87,7 @@ void DebugCmd::Run(CmdArgList args) {
string reply = absl::StrCat("Unknown subcommand or wrong number of arguments for '", subcmd,
"'. Try DEBUG HELP.");
return (*cntx_)->SendError(reply);
return (*cntx_)->SendError(reply, kSyntaxErr);
}
void DebugCmd::Reload(CmdArgList args) {

View file

@ -196,7 +196,7 @@ void GenericFamily::Del(CmdArgList args, ConnectionContext* cntx) {
void GenericFamily::Ping(CmdArgList args, ConnectionContext* cntx) {
if (args.size() > 2) {
return (*cntx)->SendError("wrong number of arguments for 'ping' command");
return (*cntx)->SendError(facade::WrongNumArgsError("ping"), kSyntaxErr);
}
// We synchronously block here until the engine sends us the payload and notifies that

View file

@ -158,6 +158,11 @@ void HSetFamily::HMGet(CmdArgList args, ConnectionContext* cntx) {
(*cntx)->SendNull();
}
}
} else if (result.status() == OpStatus::KEY_NOTFOUND) {
(*cntx)->StartArray(args.size());
for (unsigned i = 0; i < args.size(); ++i) {
(*cntx)->SendNull();
}
} else {
(*cntx)->SendError(result.status());
}
@ -253,6 +258,10 @@ void HSetFamily::HSet(CmdArgList args, ConnectionContext* cntx) {
string_view key = ArgS(args, 1);
args.remove_prefix(2);
if (args.size() % 2 != 0) {
return (*cntx)->SendError(facade::WrongNumArgsError("hset"), kSyntaxErr);
}
auto cb = [&](Transaction* t, EngineShard* shard) {
return OpSet(OpArgs{shard, t->db_index()}, key, args, false);
};
@ -265,20 +274,6 @@ void HSetFamily::HSet(CmdArgList args, ConnectionContext* cntx) {
}
}
void HSetFamily::HMSet(CmdArgList args, ConnectionContext* cntx) {
string_view key = ArgS(args, 1);
args.remove_prefix(2);
auto cb = [&](Transaction* t, EngineShard* shard) {
return OpSet(OpArgs{shard, t->db_index()}, key, args, false);
};
OpResult<uint32_t> result = cntx->transaction->ScheduleSingleHopT(std::move(cb));
// Returns "OK", that's all the difference from HSet.
(*cntx)->SendError(result.status());
}
void HSetFamily::HSetNx(CmdArgList args, ConnectionContext* cntx) {
LOG(DFATAL) << "TBD";
}
@ -647,6 +642,7 @@ void HSetFamily::Register(CommandRegistry* registry) {
<< CI{"HGET", CO::FAST | CO::READONLY, 3, 1, 1, 1}.HFUNC(HGet)
<< CI{"HGETALL", CO::FAST | CO::READONLY, 2, 1, 1, 1}.HFUNC(HGetAll)
<< CI{"HMGET", CO::FAST | CO::READONLY, -3, 1, 1, 1}.HFUNC(HMGet)
<< CI{"HMSET", CO::WRITE | CO::FAST | CO::DENYOOM, -4, 1, 1, 1}.HFUNC(HSet)
<< CI{"HINCRBY", CO::WRITE | CO::DENYOOM | CO::FAST, 4, 1, 1, 1}.HFUNC(HIncrBy)
<< CI{"HKEYS", CO::READONLY, 2, 1, 1, 1}.HFUNC(HKeys)
<< CI{"HVALS", CO::READONLY, 2, 1, 1, 1}.HFUNC(HVals)

View file

@ -34,8 +34,6 @@ class HSetFamily {
static void HGetAll(CmdArgList args, ConnectionContext* cntx);
static void HSet(CmdArgList args, ConnectionContext* cntx);
static void HMSet(CmdArgList args, ConnectionContext* cntx);
static void HSetNx(CmdArgList args, ConnectionContext* cntx);
static void HStrLen(CmdArgList args, ConnectionContext* cntx);

View file

@ -41,31 +41,19 @@ TEST_F(HSetFamilyTest, Basic) {
auto resp = Run({"hset", "x", "a"});
EXPECT_THAT(resp[0], ErrArg("wrong number"));
resp = Run({"hset", "x", "a", "b"});
EXPECT_THAT(resp[0], IntArg(1));
resp = Run({"hlen", "x"});
EXPECT_THAT(resp[0], IntArg(1));
EXPECT_THAT(Run({"HSET", "hs", "key1", "val1", "key2"}), ElementsAre(ErrArg("wrong number")));
resp = Run({"hexists", "x", "a"});
EXPECT_THAT(resp[0], IntArg(1));
EXPECT_EQ(1, CheckedInt({"hset", "x", "a", "b"}));
EXPECT_EQ(1, CheckedInt({"hlen", "x"}));
resp = Run({"hexists", "x", "b"});
EXPECT_THAT(resp[0], IntArg(0));
EXPECT_EQ(1, CheckedInt({"hexists", "x", "a"}));
EXPECT_EQ(0, CheckedInt({"hexists", "x", "b"}));
EXPECT_EQ(0, CheckedInt({"hexists", "y", "a"}));
resp = Run({"hexists", "y", "a"});
EXPECT_THAT(resp[0], IntArg(0));
resp = Run({"hset", "x", "a", "b"});
EXPECT_THAT(resp[0], IntArg(0));
resp = Run({"hset", "x", "a", "c"});
EXPECT_THAT(resp[0], IntArg(0));
resp = Run({"hset", "y", "a", "c", "d", "e"});
EXPECT_THAT(resp[0], IntArg(2));
resp = Run({"hdel", "y", "a", "d"});
EXPECT_THAT(resp[0], IntArg(2));
EXPECT_EQ(0, CheckedInt({"hset", "x", "a", "b"}));
EXPECT_EQ(0, CheckedInt({"hset", "x", "a", "c"}));
EXPECT_EQ(2, CheckedInt({"hset", "y", "a", "c", "d", "e"}));
EXPECT_EQ(2, CheckedInt({"hdel", "y", "a", "d"}));
}
TEST_F(HSetFamilyTest, HSetLarge) {
@ -81,6 +69,9 @@ TEST_F(HSetFamilyTest, Get) {
auto resp = Run({"hset", "x", "a", "1", "b", "2", "c", "3"});
EXPECT_THAT(resp[0], IntArg(3));
resp = Run({"hmget", "unkwn", "a", "c"});
EXPECT_THAT(resp, ElementsAre(ArgType(RespExpr::NIL), ArgType(RespExpr::NIL)));
resp = Run({"hkeys", "x"});
EXPECT_THAT(resp, UnorderedElementsAre("a", "b", "c"));

View file

@ -8,11 +8,13 @@
#include "base/logging.h"
#include "core/interpreter.h"
#include "facade/error.h"
#include "server/server_state.h"
namespace dfly {
using namespace std;
using namespace facade;
ScriptMgr::ScriptMgr(EngineShardSet* ess) : ess_(ess) {
}
@ -55,9 +57,10 @@ void ScriptMgr::Run(CmdArgList args, ConnectionContext* cntx) {
return (*cntx)->SendBulkString(error_or_id);
}
cntx->reply_builder()->SendError(absl::StrCat(
"Unknown subcommand or wrong number of arguments for '", subcmd, "'. Try SCRIPT HELP."));
} // namespace dfly
string err = absl::StrCat("Unknown subcommand or wrong number of arguments for '", subcmd,
"'. Try SCRIPT HELP.");
cntx->reply_builder()->SendError(err, kSyntaxErr);
}
bool ScriptMgr::InsertFunction(std::string_view id, std::string_view body) {
ScriptKey key;