This is an automated email from the ASF dual-hosted git repository.

twice pushed a commit to branch unstable
in repository https://gitbox.apache.org/repos/asf/kvrocks.git


The following commit(s) were added to refs/heads/unstable by this push:
     new 963861d5f feat(hash): support NOVALUES in HSCAN (#3109)
963861d5f is described below

commit 963861d5fe378ac4d8b22336fc509ae3593e21ab
Author: Qiang-Liu <[email protected]>
AuthorDate: Wed Aug 13 09:55:02 2025 +0800

    feat(hash): support NOVALUES in HSCAN (#3109)
---
 src/commands/cmd_hash.cc                 | 12 +++++++++---
 src/commands/scan_base.h                 |  3 +++
 tests/gocase/unit/type/hash/hash_test.go | 17 +++++++++++++++++
 3 files changed, 29 insertions(+), 3 deletions(-)

diff --git a/src/commands/cmd_hash.cc b/src/commands/cmd_hash.cc
index 13d13de8a..35e7c9856 100644
--- a/src/commands/cmd_hash.cc
+++ b/src/commands/cmd_hash.cc
@@ -408,17 +408,23 @@ class CommandHScan : public CommandSubkeyScanBase {
     std::vector<std::string> values;
     auto key_name = srv->GetKeyNameFromCursor(cursor_, CursorType::kTypeHash);
 
-    auto s = hash_db.Scan(ctx, key_, key_name, limit_, prefix_, &fields, 
&values);
+    auto s = hash_db.Scan(ctx, key_, key_name, limit_, prefix_, &fields, 
no_values_ ? nullptr : &values);
     if (!s.ok() && !s.IsNotFound()) {
       return {Status::RedisExecErr, s.ToString()};
     }
 
     auto cursor = GetNextCursor(srv, fields, CursorType::kTypeHash);
     std::vector<std::string> entries;
-    entries.reserve(2 * fields.size());
+    if (no_values_) {
+      entries.reserve(fields.size());
+    } else {
+      entries.reserve(2 * fields.size());
+    }
     for (size_t i = 0; i < fields.size(); i++) {
       entries.emplace_back(redis::BulkString(fields[i]));
-      entries.emplace_back(redis::BulkString(values[i]));
+      if (!no_values_) {
+        entries.emplace_back(redis::BulkString(values[i]));
+      }
     }
     *output = redis::Array({redis::BulkString(cursor), redis::Array(entries)});
     return Status::OK();
diff --git a/src/commands/scan_base.h b/src/commands/scan_base.h
index 5a0d4ca17..d80c1e4e1 100644
--- a/src/commands/scan_base.h
+++ b/src/commands/scan_base.h
@@ -64,6 +64,8 @@ class CommandScanBase : public Commander {
         } else {
           return {Status::RedisExecErr, "Invalid type"};
         }
+      } else if (parser.EatEqICase("novalues")) {
+        no_values_ = true;
       } else {
         return parser.InvalidSyntax();
       }
@@ -102,6 +104,7 @@ class CommandScanBase : public Commander {
   std::string suffix_glob_ = "*";
   int limit_ = 20;
   RedisType type_ = kRedisNone;
+  bool no_values_ = false;
 };
 
 class CommandSubkeyScanBase : public CommandScanBase {
diff --git a/tests/gocase/unit/type/hash/hash_test.go 
b/tests/gocase/unit/type/hash/hash_test.go
index 8d1536796..eb568b257 100644
--- a/tests/gocase/unit/type/hash/hash_test.go
+++ b/tests/gocase/unit/type/hash/hash_test.go
@@ -775,6 +775,23 @@ var testHash = func(t *testing.T, configs 
util.KvrocksServerConfigs) {
                require.Equal(t, "b", rdb.HGet(ctx, "hash", strings.Repeat("k", 
336)).Val())
        })
 
+       t.Run("HSCAN without NOVALUES", func(t *testing.T) {
+               rdb.Del(ctx, "langhash")
+               rdb.HMSet(ctx, "langhash", []string{"lang1", "C++", "lang2", 
"JavaScript", "lang3", "Python", "lang4", "GoLanguage"})
+               res, _, _ := rdb.HScan(ctx, "langhash", 0, "lang1", 0).Result()
+               require.Equal(t, 2, len(res))
+               require.Equal(t, "lang1", res[0])
+               require.Equal(t, "C++", res[1])
+       })
+
+       t.Run("HSCAN with NOVALUES", func(t *testing.T) {
+               rdb.Del(ctx, "langhash")
+               rdb.HMSet(ctx, "langhash", []string{"lang1", "C++", "lang2", 
"JavaScript", "lang3", "Python", "lang4", "GoLanguage"})
+               res, _, _ := rdb.HScanNoValues(ctx, "langhash", 0, "lang1", 
0).Result()
+               require.Equal(t, 1, len(res))
+               require.Equal(t, "lang1", res[0])
+       })
+
        for _, size := range []int64{10, 512} {
                t.Run(fmt.Sprintf("Hash fuzzing #1 - %d fields", size), func(t 
*testing.T) {
                        for times := 0; times < 10; times++ {

Reply via email to