From 88a01e104f27b65f7ce7944c0d6052b2577c4406 Mon Sep 17 00:00:00 2001 From: longfar Date: Fri, 5 Jan 2024 22:53:00 +0800 Subject: [PATCH] feat: hash command hscan --- src/base_cmd.h | 1 + src/client.cc | 3 +++ src/client.h | 1 + src/cmd_hash.cc | 56 ++++++++++++++++++++++++++++++++++++++++ src/cmd_hash.h | 14 ++++++++++ src/cmd_table_manager.cc | 1 + 6 files changed, 76 insertions(+) diff --git a/src/base_cmd.h b/src/base_cmd.h index 8f4cca721..63ae1687c 100644 --- a/src/base_cmd.h +++ b/src/base_cmd.h @@ -69,6 +69,7 @@ const std::string kCmdNameHGetAll = "hgetall"; const std::string kCmdNameHKeys = "hkeys"; const std::string kCmdNameHLen = "hlen"; const std::string kCmdNameHStrLen = "hstrlen"; +const std::string kCmdNameHScan = "hscan"; // set cmd const std::string kCmdNameSIsMember = "sismember"; diff --git a/src/client.cc b/src/client.cc index 53df63a42..0d717f277 100644 --- a/src/client.cc +++ b/src/client.cc @@ -129,6 +129,9 @@ void CmdRes::SetRes(CmdRes::CmdRet _ret, const std::string& content) { AppendStringRaw(content); AppendStringRaw(CRLF); break; + case kInvalidCursor: + AppendStringRaw("-ERR invalid cursor"); + break; default: break; } diff --git a/src/client.h b/src/client.h index 4b3396b4b..8521acd24 100644 --- a/src/client.h +++ b/src/client.h @@ -47,6 +47,7 @@ class CmdRes { kInconsistentHashTag, kErrOther, KIncrByOverFlow, + kInvalidCursor, }; CmdRes() = default; diff --git a/src/cmd_hash.cc b/src/cmd_hash.cc index e0262b5fc..1e0bb2f57 100644 --- a/src/cmd_hash.cc +++ b/src/cmd_hash.cc @@ -9,6 +9,7 @@ #include +#include "pstd/pstd_string.h" #include "store.h" namespace pikiwidb { @@ -227,4 +228,59 @@ void HStrLenCmd::DoCmd(PClient* client) { } } +HScanCmd::HScanCmd(const std::string& name, int16_t arity) + : BaseCmd(name, arity, kCmdFlagsReadonly, kAclCategoryRead | kAclCategoryHash) {} + +bool HScanCmd::DoInitial(PClient* client) { + if (auto size = client->argv_.size(); size != 3 && size != 5 && size != 7) { + client->SetRes(CmdRes::kSyntaxErr); + return false; + } + client->SetKey(client->argv_[1]); + return true; +} + +void HScanCmd::DoCmd(PClient* client) { + const auto& argv = client->argv_; + // parse arguments + int64_t cursor{}; + int64_t count{10}; + std::string pattern{"*"}; + if (pstd::String2int(argv[2], &cursor) == 0) { + client->SetRes(CmdRes::kInvalidCursor); + return; + } + for (size_t i = 3; i < argv.size(); i += 2) { + if (auto lower = pstd::StringToLower(argv[i]); kMatchSymbol == lower) { + pattern = argv[i + 1]; + } else if (kCountSymbol == lower) { + if (pstd::String2int(argv[i + 1], &count) == 0) { + client->SetRes(CmdRes::kInvalidInt, kCmdNameHScan); + return; + } + } else { + client->SetRes(CmdRes::kErrOther, kCmdNameHScan); + return; + } + } + + // execute command + std::vector fvs; + int64_t next_cursor{}; + auto status = PSTORE.GetBackend()->HScan(client->Key(), cursor, pattern, count, &fvs, &next_cursor); + if (!status.ok() && !status.IsNotFound()) { + client->SetRes(CmdRes::kErrOther, status.ToString()); + return; + } + + // reply to client + client->AppendArrayLen(2); + client->AppendString(std::to_string(next_cursor)); + client->AppendArrayLenUint64(fvs.size() * 2); + for (const auto& [field, value] : fvs) { + client->AppendString(field); + client->AppendString(value); + } +} + } // namespace pikiwidb diff --git a/src/cmd_hash.h b/src/cmd_hash.h index 16a820ff6..c73c739fc 100644 --- a/src/cmd_hash.h +++ b/src/cmd_hash.h @@ -99,4 +99,18 @@ class HStrLenCmd : public BaseCmd { void DoCmd(PClient *client) override; }; +class HScanCmd : public BaseCmd { + public: + HScanCmd(const std::string &name, int16_t arity); + + protected: + bool DoInitial(PClient *client) override; + + private: + void DoCmd(PClient *client) override; + + static constexpr const char *kMatchSymbol = "match"; + static constexpr const char *kCountSymbol = "count"; +}; + } // namespace pikiwidb diff --git a/src/cmd_table_manager.cc b/src/cmd_table_manager.cc index fef921df3..2e61dff10 100644 --- a/src/cmd_table_manager.cc +++ b/src/cmd_table_manager.cc @@ -73,6 +73,7 @@ void CmdTableManager::InitCmdTable() { ADD_COMMAND(HKeys, 2); ADD_COMMAND(HLen, 2); ADD_COMMAND(HStrLen, 3); + ADD_COMMAND(HScan, -3); // set ADD_COMMAND(SIsMember, 3);