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["hgetall"] = defaultFunc
|
||||||
routerMap["hincrby"] = defaultFunc
|
routerMap["hincrby"] = defaultFunc
|
||||||
routerMap["hincrbyfloat"] = defaultFunc
|
routerMap["hincrbyfloat"] = defaultFunc
|
||||||
|
routerMap["hrandfield"] = defaultFunc
|
||||||
|
|
||||||
routerMap["sadd"] = defaultFunc
|
routerMap["sadd"] = defaultFunc
|
||||||
routerMap["sismember"] = defaultFunc
|
routerMap["sismember"] = defaultFunc
|
||||||
|
@@ -60,6 +60,7 @@
|
|||||||
- hgetall
|
- hgetall
|
||||||
- hincrby
|
- hincrby
|
||||||
- hincrbyfloat
|
- hincrbyfloat
|
||||||
|
- hrandfield
|
||||||
- Set
|
- Set
|
||||||
- sadd
|
- sadd
|
||||||
- sismember
|
- sismember
|
||||||
|
@@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/hdt3213/godis/redis/protocol"
|
"github.com/hdt3213/godis/redis/protocol"
|
||||||
"github.com/shopspring/decimal"
|
"github.com/shopspring/decimal"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (db *DB) getAsDict(key string) (Dict.Dict, protocol.ErrorReply) {
|
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)
|
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() {
|
func init() {
|
||||||
RegisterCommand("HSet", execHSet, writeFirstKey, undoHSet, 4)
|
RegisterCommand("HSet", execHSet, writeFirstKey, undoHSet, 4)
|
||||||
RegisterCommand("HSetNX", execHSetNX, writeFirstKey, undoHSet, 4)
|
RegisterCommand("HSetNX", execHSetNX, writeFirstKey, undoHSet, 4)
|
||||||
@@ -413,4 +490,5 @@ func init() {
|
|||||||
RegisterCommand("HGetAll", execHGetAll, readFirstKey, nil, 2)
|
RegisterCommand("HGetAll", execHGetAll, readFirstKey, nil, 2)
|
||||||
RegisterCommand("HIncrBy", execHIncrBy, writeFirstKey, undoHIncr, 4)
|
RegisterCommand("HIncrBy", execHIncrBy, writeFirstKey, undoHIncr, 4)
|
||||||
RegisterCommand("HIncrByFloat", execHIncrByFloat, 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))
|
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) {
|
func TestHIncrBy(t *testing.T) {
|
||||||
|
Reference in New Issue
Block a user