mirror of
https://github.com/HDT3213/godis.git
synced 2025-10-06 01:07:06 +08:00
Feat:Add hrandfield Command.
This commit is contained in:
@@ -67,6 +67,7 @@ func makeRouter() map[string]CmdFunc {
|
||||
routerMap["hgetall"] = defaultFunc
|
||||
routerMap["hincrby"] = defaultFunc
|
||||
routerMap["hincrbyfloat"] = defaultFunc
|
||||
routerMap["hrandfield"] = defaultFunc
|
||||
|
||||
routerMap["sadd"] = defaultFunc
|
||||
routerMap["sismember"] = defaultFunc
|
||||
|
@@ -60,6 +60,7 @@
|
||||
- hgetall
|
||||
- hincrby
|
||||
- hincrbyfloat
|
||||
- hrandfield
|
||||
- Set
|
||||
- sadd
|
||||
- sismember
|
||||
|
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/hdt3213/godis/redis/protocol"
|
||||
"github.com/shopspring/decimal"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (db *DB) getAsDict(key string) (Dict.Dict, protocol.ErrorReply) {
|
||||
@@ -398,6 +399,82 @@ func execHIncrByFloat(db *DB, args [][]byte) redis.Reply {
|
||||
return protocol.MakeBulkReply(resultBytes)
|
||||
}
|
||||
|
||||
// execHRandField return a random field(or field-value) from the hash value stored at key.
|
||||
func execHRandField(db *DB, args [][]byte) redis.Reply {
|
||||
key := string(args[0])
|
||||
count := 1
|
||||
withvalues := 0
|
||||
|
||||
if len(args) > 3 {
|
||||
return protocol.MakeErrReply("ERR wrong number of arguments for 'hrandfield' command")
|
||||
}
|
||||
|
||||
if len(args) == 3 {
|
||||
if strings.ToLower(string(args[2])) == "withvalues" {
|
||||
withvalues = 1
|
||||
} else {
|
||||
return protocol.MakeSyntaxErrReply()
|
||||
}
|
||||
}
|
||||
|
||||
if len(args) >= 2 {
|
||||
count64, err := strconv.ParseInt(string(args[1]), 10, 64)
|
||||
if err != nil {
|
||||
return protocol.MakeErrReply("ERR value is not an integer or out of range")
|
||||
}
|
||||
count = int(count64)
|
||||
}
|
||||
|
||||
dict, errReply := db.getAsDict(key)
|
||||
if errReply != nil {
|
||||
return errReply
|
||||
}
|
||||
if dict == nil {
|
||||
return &protocol.EmptyMultiBulkReply{}
|
||||
}
|
||||
|
||||
if count > 0 {
|
||||
fields := dict.RandomDistinctKeys(count)
|
||||
Numfield := len(fields)
|
||||
if withvalues == 0 {
|
||||
result := make([][]byte, Numfield)
|
||||
for i, v := range fields {
|
||||
result[i] = []byte(v)
|
||||
}
|
||||
return protocol.MakeMultiBulkReply(result)
|
||||
} else {
|
||||
result := make([][]byte, 2*Numfield)
|
||||
for i, v := range fields {
|
||||
result[2*i] = []byte(v)
|
||||
raw, _ := dict.Get(v)
|
||||
result[2*i+1] = raw.([]byte)
|
||||
}
|
||||
return protocol.MakeMultiBulkReply(result)
|
||||
}
|
||||
} else if count < 0 {
|
||||
fields := dict.RandomKeys(-count)
|
||||
Numfield := len(fields)
|
||||
if withvalues == 0 {
|
||||
result := make([][]byte, Numfield)
|
||||
for i, v := range fields {
|
||||
result[i] = []byte(v)
|
||||
}
|
||||
return protocol.MakeMultiBulkReply(result)
|
||||
} else {
|
||||
result := make([][]byte, 2*Numfield)
|
||||
for i, v := range fields {
|
||||
result[2*i] = []byte(v)
|
||||
raw, _ := dict.Get(v)
|
||||
result[2*i+1] = raw.([]byte)
|
||||
}
|
||||
return protocol.MakeMultiBulkReply(result)
|
||||
}
|
||||
}
|
||||
|
||||
// 'count' is 0 will reach.
|
||||
return &protocol.EmptyMultiBulkReply{}
|
||||
}
|
||||
|
||||
func init() {
|
||||
RegisterCommand("HSet", execHSet, writeFirstKey, undoHSet, 4)
|
||||
RegisterCommand("HSetNX", execHSetNX, writeFirstKey, undoHSet, 4)
|
||||
@@ -413,4 +490,5 @@ func init() {
|
||||
RegisterCommand("HGetAll", execHGetAll, readFirstKey, nil, 2)
|
||||
RegisterCommand("HIncrBy", execHIncrBy, writeFirstKey, undoHIncr, 4)
|
||||
RegisterCommand("HIncrByFloat", execHIncrByFloat, writeFirstKey, undoHIncr, 4)
|
||||
RegisterCommand("HRandField", execHRandField, readFirstKey, nil, -2)
|
||||
}
|
||||
|
@@ -174,6 +174,57 @@ func TestHGetAll(t *testing.T) {
|
||||
t.Error(fmt.Sprintf("unexpected value %s", value))
|
||||
}
|
||||
}
|
||||
|
||||
// test HRandField
|
||||
// test HRandField count of 0 is handled correctly -- "emptyarray"
|
||||
result = testDB.Exec(nil, utils.ToCmdLine("hrandfield", key, "0"))
|
||||
multiBulk, ok = result.(*protocol.MultiBulkReply)
|
||||
if !ok {
|
||||
resultBytes := string(result.ToBytes())
|
||||
if resultBytes != "*0\r\n" {
|
||||
t.Error(fmt.Sprintf("expected MultiBulkReply, actually %s", resultBytes))
|
||||
}
|
||||
}
|
||||
|
||||
// test HRandField count > size
|
||||
result = testDB.Exec(nil, utils.ToCmdLine("hrandfield", key, strconv.Itoa(size+100)))
|
||||
multiBulk, ok = result.(*protocol.MultiBulkReply)
|
||||
if !ok {
|
||||
t.Error(fmt.Sprintf("expected MultiBulkReply, actually %s", string(result.ToBytes())))
|
||||
}
|
||||
if len(fields) != len(multiBulk.Args) {
|
||||
t.Error(fmt.Sprintf("expected %d items , actually %d ", len(fields), len(multiBulk.Args)))
|
||||
}
|
||||
|
||||
// test HRandField count > size withvalues
|
||||
result = testDB.Exec(nil, utils.ToCmdLine("hrandfield", key, strconv.Itoa(size+100), "withvalues"))
|
||||
multiBulk, ok = result.(*protocol.MultiBulkReply)
|
||||
if !ok {
|
||||
t.Error(fmt.Sprintf("expected MultiBulkReply, actually %s", string(result.ToBytes())))
|
||||
}
|
||||
if 2*len(fields) != len(multiBulk.Args) {
|
||||
t.Error(fmt.Sprintf("expected %d items , actually %d ", 2*len(fields), len(multiBulk.Args)))
|
||||
}
|
||||
|
||||
// test HRandField count < size
|
||||
result = testDB.Exec(nil, utils.ToCmdLine("hrandfield", key, strconv.Itoa(-size-10)))
|
||||
multiBulk, ok = result.(*protocol.MultiBulkReply)
|
||||
if !ok {
|
||||
t.Error(fmt.Sprintf("expected MultiBulkReply, actually %s", string(result.ToBytes())))
|
||||
}
|
||||
if len(fields)+10 != len(multiBulk.Args) {
|
||||
t.Error(fmt.Sprintf("expected %d items , actually %d ", len(fields)+10, len(multiBulk.Args)))
|
||||
}
|
||||
|
||||
// test HRandField count < size withvalues
|
||||
result = testDB.Exec(nil, utils.ToCmdLine("hrandfield", key, strconv.Itoa(-size-10), "withvalues"))
|
||||
multiBulk, ok = result.(*protocol.MultiBulkReply)
|
||||
if !ok {
|
||||
t.Error(fmt.Sprintf("expected MultiBulkReply, actually %s", string(result.ToBytes())))
|
||||
}
|
||||
if 2*(len(fields)+10) != len(multiBulk.Args) {
|
||||
t.Error(fmt.Sprintf("expected %d items , actually %d ", 2*(len(fields)+10), len(multiBulk.Args)))
|
||||
}
|
||||
}
|
||||
|
||||
func TestHIncrBy(t *testing.T) {
|
||||
|
Reference in New Issue
Block a user