mirror of
https://github.com/HDT3213/godis.git
synced 2025-10-05 16:57:06 +08:00
refactor command table
This commit is contained in:
9
aof.go
9
aof.go
@@ -19,11 +19,11 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var pExpireAtCmd = []byte("PEXPIREAT")
|
var pExpireAtBytes = []byte("PEXPIREAT")
|
||||||
|
|
||||||
func makeExpireCmd(key string, expireAt time.Time) *reply.MultiBulkReply {
|
func makeExpireCmd(key string, expireAt time.Time) *reply.MultiBulkReply {
|
||||||
args := make([][]byte, 3)
|
args := make([][]byte, 3)
|
||||||
args[0] = pExpireAtCmd
|
args[0] = pExpireAtBytes
|
||||||
args[1] = []byte(key)
|
args[1] = []byte(key)
|
||||||
args[2] = []byte(strconv.FormatInt(expireAt.UnixNano()/1e6, 10))
|
args[2] = []byte(strconv.FormatInt(expireAt.UnixNano()/1e6, 10))
|
||||||
return reply.MakeMultiBulkReply(args)
|
return reply.MakeMultiBulkReply(args)
|
||||||
@@ -101,9 +101,10 @@ func (db *DB) loadAof(maxBytes int) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
cmd := strings.ToLower(string(r.Args[0]))
|
cmd := strings.ToLower(string(r.Args[0]))
|
||||||
cmdFunc, ok := router[cmd]
|
command, ok := cmdTable[cmd]
|
||||||
if ok {
|
if ok {
|
||||||
cmdFunc(db, r.Args[1:])
|
handler := command.executor
|
||||||
|
handler(db, r.Args[1:])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
32
aof_test.go
32
aof_test.go
@@ -34,31 +34,31 @@ func TestAof(t *testing.T) {
|
|||||||
for i := 0; i < size; i++ {
|
for i := 0; i < size; i++ {
|
||||||
key := strconv.Itoa(cursor)
|
key := strconv.Itoa(cursor)
|
||||||
cursor++
|
cursor++
|
||||||
Set(aofWriteDB, utils2.ToBytesList(key, utils2.RandString(8), "EX", "10000"))
|
execSet(aofWriteDB, utils2.ToBytesList(key, utils2.RandString(8), "EX", "10000"))
|
||||||
keys = append(keys, key)
|
keys = append(keys, key)
|
||||||
}
|
}
|
||||||
for i := 0; i < size; i++ {
|
for i := 0; i < size; i++ {
|
||||||
key := strconv.Itoa(cursor)
|
key := strconv.Itoa(cursor)
|
||||||
cursor++
|
cursor++
|
||||||
RPush(aofWriteDB, utils2.ToBytesList(key, utils2.RandString(8)))
|
execRPush(aofWriteDB, utils2.ToBytesList(key, utils2.RandString(8)))
|
||||||
keys = append(keys, key)
|
keys = append(keys, key)
|
||||||
}
|
}
|
||||||
for i := 0; i < size; i++ {
|
for i := 0; i < size; i++ {
|
||||||
key := strconv.Itoa(cursor)
|
key := strconv.Itoa(cursor)
|
||||||
cursor++
|
cursor++
|
||||||
HSet(aofWriteDB, utils2.ToBytesList(key, utils2.RandString(8), utils2.RandString(8)))
|
execHSet(aofWriteDB, utils2.ToBytesList(key, utils2.RandString(8), utils2.RandString(8)))
|
||||||
keys = append(keys, key)
|
keys = append(keys, key)
|
||||||
}
|
}
|
||||||
for i := 0; i < size; i++ {
|
for i := 0; i < size; i++ {
|
||||||
key := strconv.Itoa(cursor)
|
key := strconv.Itoa(cursor)
|
||||||
cursor++
|
cursor++
|
||||||
SAdd(aofWriteDB, utils2.ToBytesList(key, utils2.RandString(8)))
|
execSAdd(aofWriteDB, utils2.ToBytesList(key, utils2.RandString(8)))
|
||||||
keys = append(keys, key)
|
keys = append(keys, key)
|
||||||
}
|
}
|
||||||
for i := 0; i < size; i++ {
|
for i := 0; i < size; i++ {
|
||||||
key := strconv.Itoa(cursor)
|
key := strconv.Itoa(cursor)
|
||||||
cursor++
|
cursor++
|
||||||
ZAdd(aofWriteDB, utils2.ToBytesList(key, "10", utils2.RandString(8)))
|
execZAdd(aofWriteDB, utils2.ToBytesList(key, "10", utils2.RandString(8)))
|
||||||
keys = append(keys, key)
|
keys = append(keys, key)
|
||||||
}
|
}
|
||||||
aofWriteDB.Close() // wait for aof finished
|
aofWriteDB.Close() // wait for aof finished
|
||||||
@@ -105,44 +105,44 @@ func TestRewriteAOF(t *testing.T) {
|
|||||||
for i := 0; i < size; i++ {
|
for i := 0; i < size; i++ {
|
||||||
key := "str" + strconv.Itoa(cursor)
|
key := "str" + strconv.Itoa(cursor)
|
||||||
cursor++
|
cursor++
|
||||||
Set(aofWriteDB, utils2.ToBytesList(key, utils2.RandString(8)))
|
execSet(aofWriteDB, utils2.ToBytesList(key, utils2.RandString(8)))
|
||||||
Set(aofWriteDB, utils2.ToBytesList(key, utils2.RandString(8)))
|
execSet(aofWriteDB, utils2.ToBytesList(key, utils2.RandString(8)))
|
||||||
keys = append(keys, key)
|
keys = append(keys, key)
|
||||||
}
|
}
|
||||||
// test ttl
|
// test ttl
|
||||||
for i := 0; i < size; i++ {
|
for i := 0; i < size; i++ {
|
||||||
key := "str" + strconv.Itoa(cursor)
|
key := "str" + strconv.Itoa(cursor)
|
||||||
cursor++
|
cursor++
|
||||||
Set(aofWriteDB, utils2.ToBytesList(key, utils2.RandString(8), "EX", "1000"))
|
execSet(aofWriteDB, utils2.ToBytesList(key, utils2.RandString(8), "EX", "1000"))
|
||||||
ttlKeys = append(ttlKeys, key)
|
ttlKeys = append(ttlKeys, key)
|
||||||
}
|
}
|
||||||
for i := 0; i < size; i++ {
|
for i := 0; i < size; i++ {
|
||||||
key := "list" + strconv.Itoa(cursor)
|
key := "list" + strconv.Itoa(cursor)
|
||||||
cursor++
|
cursor++
|
||||||
RPush(aofWriteDB, utils2.ToBytesList(key, utils2.RandString(8)))
|
execRPush(aofWriteDB, utils2.ToBytesList(key, utils2.RandString(8)))
|
||||||
RPush(aofWriteDB, utils2.ToBytesList(key, utils2.RandString(8)))
|
execRPush(aofWriteDB, utils2.ToBytesList(key, utils2.RandString(8)))
|
||||||
keys = append(keys, key)
|
keys = append(keys, key)
|
||||||
}
|
}
|
||||||
for i := 0; i < size; i++ {
|
for i := 0; i < size; i++ {
|
||||||
key := "hash" + strconv.Itoa(cursor)
|
key := "hash" + strconv.Itoa(cursor)
|
||||||
cursor++
|
cursor++
|
||||||
field := utils2.RandString(8)
|
field := utils2.RandString(8)
|
||||||
HSet(aofWriteDB, utils2.ToBytesList(key, field, utils2.RandString(8)))
|
execHSet(aofWriteDB, utils2.ToBytesList(key, field, utils2.RandString(8)))
|
||||||
HSet(aofWriteDB, utils2.ToBytesList(key, field, utils2.RandString(8)))
|
execHSet(aofWriteDB, utils2.ToBytesList(key, field, utils2.RandString(8)))
|
||||||
keys = append(keys, key)
|
keys = append(keys, key)
|
||||||
}
|
}
|
||||||
for i := 0; i < size; i++ {
|
for i := 0; i < size; i++ {
|
||||||
key := "set" + strconv.Itoa(cursor)
|
key := "set" + strconv.Itoa(cursor)
|
||||||
cursor++
|
cursor++
|
||||||
member := utils2.RandString(8)
|
member := utils2.RandString(8)
|
||||||
SAdd(aofWriteDB, utils2.ToBytesList(key, member))
|
execSAdd(aofWriteDB, utils2.ToBytesList(key, member))
|
||||||
SAdd(aofWriteDB, utils2.ToBytesList(key, member))
|
execSAdd(aofWriteDB, utils2.ToBytesList(key, member))
|
||||||
keys = append(keys, key)
|
keys = append(keys, key)
|
||||||
}
|
}
|
||||||
for i := 0; i < size; i++ {
|
for i := 0; i < size; i++ {
|
||||||
key := "zset" + strconv.Itoa(cursor)
|
key := "zset" + strconv.Itoa(cursor)
|
||||||
cursor++
|
cursor++
|
||||||
ZAdd(aofWriteDB, utils2.ToBytesList(key, "10", utils2.RandString(8)))
|
execZAdd(aofWriteDB, utils2.ToBytesList(key, "10", utils2.RandString(8)))
|
||||||
keys = append(keys, key)
|
keys = append(keys, key)
|
||||||
}
|
}
|
||||||
time.Sleep(time.Second) // wait for async goroutine finish its job
|
time.Sleep(time.Second) // wait for async goroutine finish its job
|
||||||
@@ -167,7 +167,7 @@ func TestRewriteAOF(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, key := range ttlKeys {
|
for _, key := range ttlKeys {
|
||||||
ret := TTL(aofReadDB, utils2.ToBytesList(key))
|
ret := execTTL(aofReadDB, utils2.ToBytesList(key))
|
||||||
intResult, ok := ret.(*reply.IntReply)
|
intResult, ok := ret.(*reply.IntReply)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Errorf("expected int reply, actually %s", ret.ToBytes())
|
t.Errorf("expected int reply, actually %s", ret.ToBytes())
|
||||||
|
@@ -2,7 +2,6 @@ package cluster
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/hdt3213/godis"
|
|
||||||
"github.com/hdt3213/godis/lib/utils"
|
"github.com/hdt3213/godis/lib/utils"
|
||||||
"github.com/hdt3213/godis/redis/reply"
|
"github.com/hdt3213/godis/redis/reply"
|
||||||
"github.com/hdt3213/godis/redis/reply/asserts"
|
"github.com/hdt3213/godis/redis/reply/asserts"
|
||||||
@@ -11,22 +10,22 @@ import (
|
|||||||
|
|
||||||
func TestRename(t *testing.T) {
|
func TestRename(t *testing.T) {
|
||||||
testDB := testCluster.db
|
testDB := testCluster.db
|
||||||
godis.FlushAll(testDB, [][]byte{})
|
testDB.Exec(nil, utils.ToBytesList("FlushALL"))
|
||||||
key := utils.RandString(10)
|
key := utils.RandString(10)
|
||||||
value := utils.RandString(10)
|
value := utils.RandString(10)
|
||||||
newKey := key + utils.RandString(2)
|
newKey := key + utils.RandString(2)
|
||||||
godis.Set(testDB, utils.ToBytesList(key, value, "ex", "1000"))
|
testDB.Exec(nil, utils.ToBytesList("SET", key, value, "ex", "1000"))
|
||||||
result := Rename(testCluster, nil, utils.ToBytesList("RENAME", key, newKey))
|
result := Rename(testCluster, nil, utils.ToBytesList("RENAME", key, newKey))
|
||||||
if _, ok := result.(*reply.OkReply); !ok {
|
if _, ok := result.(*reply.OkReply); !ok {
|
||||||
t.Error("expect ok")
|
t.Error("expect ok")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
result = godis.Exists(testDB, utils.ToBytesList(key))
|
result = testDB.Exec(nil, utils.ToBytesList("EXISTS", key))
|
||||||
asserts.AssertIntReply(t, result, 0)
|
asserts.AssertIntReply(t, result, 0)
|
||||||
result = godis.Exists(testDB, utils.ToBytesList(newKey))
|
result = testDB.Exec(nil, utils.ToBytesList("EXISTS", newKey))
|
||||||
asserts.AssertIntReply(t, result, 1)
|
asserts.AssertIntReply(t, result, 1)
|
||||||
// check ttl
|
// check ttl
|
||||||
result = godis.TTL(testDB, utils.ToBytesList(newKey))
|
result = testDB.Exec(nil, utils.ToBytesList("TTL", newKey))
|
||||||
intResult, ok := result.(*reply.IntReply)
|
intResult, ok := result.(*reply.IntReply)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Error(fmt.Sprintf("expected int reply, actually %s", result.ToBytes()))
|
t.Error(fmt.Sprintf("expected int reply, actually %s", result.ToBytes()))
|
||||||
@@ -40,18 +39,19 @@ func TestRename(t *testing.T) {
|
|||||||
|
|
||||||
func TestRenameNx(t *testing.T) {
|
func TestRenameNx(t *testing.T) {
|
||||||
testDB := testCluster.db
|
testDB := testCluster.db
|
||||||
godis.FlushAll(testDB, [][]byte{})
|
testDB.Exec(nil, utils.ToBytesList("FlushALL"))
|
||||||
key := utils.RandString(10)
|
key := utils.RandString(10)
|
||||||
value := utils.RandString(10)
|
value := utils.RandString(10)
|
||||||
newKey := key + utils.RandString(2)
|
newKey := key + utils.RandString(2)
|
||||||
godis.Set(testCluster.db, utils.ToBytesList(key, value, "ex", "1000"))
|
testCluster.db.Exec(nil, utils.ToBytesList("SET", key, value, "ex", "1000"))
|
||||||
result := RenameNx(testCluster, nil, utils.ToBytesList("RENAMENX", key, newKey))
|
result := RenameNx(testCluster, nil, utils.ToBytesList("RENAMENX", key, newKey))
|
||||||
asserts.AssertIntReply(t, result, 1)
|
asserts.AssertIntReply(t, result, 1)
|
||||||
result = godis.Exists(testDB, utils.ToBytesList(key))
|
result = testDB.Exec(nil, utils.ToBytesList("EXISTS", key))
|
||||||
asserts.AssertIntReply(t, result, 0)
|
asserts.AssertIntReply(t, result, 0)
|
||||||
result = godis.Exists(testDB, utils.ToBytesList(newKey))
|
result = testDB.Exec(nil, utils.ToBytesList("EXISTS", newKey))
|
||||||
|
|
||||||
asserts.AssertIntReply(t, result, 1)
|
asserts.AssertIntReply(t, result, 1)
|
||||||
result = godis.TTL(testDB, utils.ToBytesList(newKey))
|
result = testDB.Exec(nil, utils.ToBytesList("TTL", newKey))
|
||||||
intResult, ok := result.(*reply.IntReply)
|
intResult, ok := result.(*reply.IntReply)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Error(fmt.Sprintf("expected int reply, actually %s", result.ToBytes()))
|
t.Error(fmt.Sprintf("expected int reply, actually %s", result.ToBytes()))
|
||||||
|
77
db.go
77
db.go
@@ -2,7 +2,6 @@
|
|||||||
package godis
|
package godis
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"github.com/hdt3213/godis/config"
|
"github.com/hdt3213/godis/config"
|
||||||
"github.com/hdt3213/godis/datastruct/dict"
|
"github.com/hdt3213/godis/datastruct/dict"
|
||||||
"github.com/hdt3213/godis/datastruct/lock"
|
"github.com/hdt3213/godis/datastruct/lock"
|
||||||
@@ -12,17 +11,10 @@ import (
|
|||||||
"github.com/hdt3213/godis/pubsub"
|
"github.com/hdt3213/godis/pubsub"
|
||||||
"github.com/hdt3213/godis/redis/reply"
|
"github.com/hdt3213/godis/redis/reply"
|
||||||
"os"
|
"os"
|
||||||
"runtime/debug"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DataEntity stores data bound to a key, including a string, list, hash, set and so on
|
|
||||||
type DataEntity struct {
|
|
||||||
Data interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
dataDictSize = 1 << 16
|
dataDictSize = 1 << 16
|
||||||
ttlDictSize = 1 << 10
|
ttlDictSize = 1 << 10
|
||||||
@@ -30,9 +22,6 @@ const (
|
|||||||
aofQueueSize = 1 << 16
|
aofQueueSize = 1 << 16
|
||||||
)
|
)
|
||||||
|
|
||||||
// args don't include cmd line
|
|
||||||
type cmdFunc func(db *DB, args [][]byte) redis.Reply
|
|
||||||
|
|
||||||
// DB stores data and execute user's commands
|
// DB stores data and execute user's commands
|
||||||
type DB struct {
|
type DB struct {
|
||||||
// key -> DataEntity
|
// key -> DataEntity
|
||||||
@@ -43,7 +32,7 @@ type DB struct {
|
|||||||
// dict.Dict will ensure concurrent-safety of its method
|
// dict.Dict will ensure concurrent-safety of its method
|
||||||
// use this mutex for complicated command only, eg. rpush, incr ...
|
// use this mutex for complicated command only, eg. rpush, incr ...
|
||||||
locker *lock.Locks
|
locker *lock.Locks
|
||||||
// stop all data access for FlushDB
|
// stop all data access for execFlushDB
|
||||||
stopWorld sync.WaitGroup
|
stopWorld sync.WaitGroup
|
||||||
// handle publish/subscribe
|
// handle publish/subscribe
|
||||||
hub *pubsub.Hub
|
hub *pubsub.Hub
|
||||||
@@ -60,7 +49,18 @@ type DB struct {
|
|||||||
pausingAof sync.RWMutex
|
pausingAof sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
var router = makeRouter()
|
// PreFunc analyses command line when queued command to `multi`
|
||||||
|
// returns related keys and undo commands
|
||||||
|
type PreFunc func(args [][]byte) ([]string, [][][]byte)
|
||||||
|
|
||||||
|
// ExecFunc is interface for command executor
|
||||||
|
// args don't include cmd line
|
||||||
|
type ExecFunc func(db *DB, args [][]byte) redis.Reply
|
||||||
|
|
||||||
|
// DataEntity stores data bound to a key, including a string, list, hash, set and so on
|
||||||
|
type DataEntity struct {
|
||||||
|
Data interface{}
|
||||||
|
}
|
||||||
|
|
||||||
// MakeDB create DB instance and start it
|
// MakeDB create DB instance and start it
|
||||||
func MakeDB() *DB {
|
func MakeDB() *DB {
|
||||||
@@ -102,49 +102,12 @@ func (db *DB) Close() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exec executes command
|
func validateArity(arity int, cmdArgs [][]byte) bool {
|
||||||
// parameter `cmdArgs` contains command and its arguments, for example: "set key value"
|
argNum := len(cmdArgs)
|
||||||
func (db *DB) Exec(c redis.Connection, cmdArgs [][]byte) (result redis.Reply) {
|
if arity >= 0 {
|
||||||
defer func() {
|
return argNum == arity
|
||||||
if err := recover(); err != nil {
|
|
||||||
logger.Warn(fmt.Sprintf("error occurs: %v\n%s", err, string(debug.Stack())))
|
|
||||||
result = &reply.UnknownErrReply{}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
cmd := strings.ToLower(string(cmdArgs[0]))
|
|
||||||
if cmd == "auth" {
|
|
||||||
return Auth(db, c, cmdArgs[1:])
|
|
||||||
}
|
}
|
||||||
if !isAuthenticated(c) {
|
return argNum >= -arity
|
||||||
return reply.MakeErrReply("NOAUTH Authentication required")
|
|
||||||
}
|
|
||||||
// special commands
|
|
||||||
if cmd == "subscribe" {
|
|
||||||
if len(cmdArgs) < 2 {
|
|
||||||
return &reply.ArgNumErrReply{Cmd: "subscribe"}
|
|
||||||
}
|
|
||||||
return pubsub.Subscribe(db.hub, c, cmdArgs[1:])
|
|
||||||
} else if cmd == "publish" {
|
|
||||||
return pubsub.Publish(db.hub, cmdArgs[1:])
|
|
||||||
} else if cmd == "unsubscribe" {
|
|
||||||
return pubsub.UnSubscribe(db.hub, c, cmdArgs[1:])
|
|
||||||
} else if cmd == "bgrewriteaof" {
|
|
||||||
// aof.go imports router.go, router.go cannot import BGRewriteAOF from aof.go
|
|
||||||
return BGRewriteAOF(db, cmdArgs[1:])
|
|
||||||
}
|
|
||||||
|
|
||||||
// normal commands
|
|
||||||
fun, ok := router[cmd]
|
|
||||||
if !ok {
|
|
||||||
return reply.MakeErrReply("ERR unknown command '" + cmd + "'")
|
|
||||||
}
|
|
||||||
if len(cmdArgs) > 1 {
|
|
||||||
result = fun(db, cmdArgs[1:])
|
|
||||||
} else {
|
|
||||||
result = fun(db, [][]byte{})
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---- Data Access ----- */
|
/* ---- Data Access ----- */
|
||||||
@@ -263,7 +226,7 @@ func genExpireTask(key string) string {
|
|||||||
return "expire:" + key
|
return "expire:" + key
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expire sets TTL of key
|
// Expire sets ttlCmd of key
|
||||||
func (db *DB) Expire(key string, expireTime time.Time) {
|
func (db *DB) Expire(key string, expireTime time.Time) {
|
||||||
db.stopWorld.Wait()
|
db.stopWorld.Wait()
|
||||||
db.ttlMap.Put(key, expireTime)
|
db.ttlMap.Put(key, expireTime)
|
||||||
@@ -274,7 +237,7 @@ func (db *DB) Expire(key string, expireTime time.Time) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Persist cancel TTL of key
|
// Persist cancel ttlCmd of key
|
||||||
func (db *DB) Persist(key string) {
|
func (db *DB) Persist(key string) {
|
||||||
db.stopWorld.Wait()
|
db.stopWorld.Wait()
|
||||||
db.ttlMap.Remove(key)
|
db.ttlMap.Remove(key)
|
||||||
|
63
exec.go
Normal file
63
exec.go
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
package godis
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/hdt3213/godis/interface/redis"
|
||||||
|
"github.com/hdt3213/godis/lib/logger"
|
||||||
|
"github.com/hdt3213/godis/pubsub"
|
||||||
|
"github.com/hdt3213/godis/redis/reply"
|
||||||
|
"runtime/debug"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Exec executes command
|
||||||
|
// parameter `cmdArgs` contains command and its arguments, for example: "set key value"
|
||||||
|
func (db *DB) Exec(c redis.Connection, cmdArgs [][]byte) (result redis.Reply) {
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
logger.Warn(fmt.Sprintf("error occurs: %v\n%s", err, string(debug.Stack())))
|
||||||
|
result = &reply.UnknownErrReply{}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
cmdName := strings.ToLower(string(cmdArgs[0]))
|
||||||
|
// authenticate
|
||||||
|
if cmdName == "auth" {
|
||||||
|
return Auth(db, c, cmdArgs[1:])
|
||||||
|
}
|
||||||
|
if !isAuthenticated(c) {
|
||||||
|
return reply.MakeErrReply("NOAUTH Authentication required")
|
||||||
|
}
|
||||||
|
|
||||||
|
// special commands
|
||||||
|
if cmdName == "subscribe" {
|
||||||
|
if len(cmdArgs) < 2 {
|
||||||
|
return reply.MakeArgNumErrReply("subscribe")
|
||||||
|
}
|
||||||
|
return pubsub.Subscribe(db.hub, c, cmdArgs[1:])
|
||||||
|
} else if cmdName == "publish" {
|
||||||
|
return pubsub.Publish(db.hub, cmdArgs[1:])
|
||||||
|
} else if cmdName == "unsubscribe" {
|
||||||
|
return pubsub.UnSubscribe(db.hub, c, cmdArgs[1:])
|
||||||
|
} else if cmdName == "bgrewriteaof" {
|
||||||
|
// aof.go imports router.go, router.go cannot import BGRewriteAOF from aof.go
|
||||||
|
return BGRewriteAOF(db, cmdArgs[1:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// normal commands
|
||||||
|
cmd, ok := cmdTable[cmdName]
|
||||||
|
if !ok {
|
||||||
|
return reply.MakeErrReply("ERR unknown command '" + cmdName + "'")
|
||||||
|
}
|
||||||
|
if !validateArity(cmd.arity, cmdArgs) {
|
||||||
|
return reply.MakeArgNumErrReply(cmdName)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun := cmd.executor
|
||||||
|
if len(cmdArgs) > 1 {
|
||||||
|
result = fun(db, cmdArgs[1:])
|
||||||
|
} else {
|
||||||
|
result = fun(db, [][]byte{})
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
33
geo.go
33
geo.go
@@ -10,8 +10,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GeoAdd add a location into SortedSet
|
// execGeoAdd add a location into SortedSet
|
||||||
func GeoAdd(db *DB, args [][]byte) redis.Reply {
|
func execGeoAdd(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) < 4 || len(args)%3 != 1 {
|
if len(args) < 4 || len(args)%3 != 1 {
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'geoadd' command")
|
return reply.MakeErrReply("ERR wrong number of arguments for 'geoadd' command")
|
||||||
}
|
}
|
||||||
@@ -61,8 +61,8 @@ func GeoAdd(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeIntReply(int64(i))
|
return reply.MakeIntReply(int64(i))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GeoPos returns location of a member
|
// execGeoPos returns location of a member
|
||||||
func GeoPos(db *DB, args [][]byte) redis.Reply {
|
func execGeoPos(db *DB, args [][]byte) redis.Reply {
|
||||||
// parse args
|
// parse args
|
||||||
if len(args) < 1 {
|
if len(args) < 1 {
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'geopos' command")
|
return reply.MakeErrReply("ERR wrong number of arguments for 'geopos' command")
|
||||||
@@ -94,8 +94,8 @@ func GeoPos(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeMultiRawReply(positions)
|
return reply.MakeMultiRawReply(positions)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GeoDist returns the distance between two locations
|
// execGeoDist returns the distance between two locations
|
||||||
func GeoDist(db *DB, args [][]byte) redis.Reply {
|
func execGeoDist(db *DB, args [][]byte) redis.Reply {
|
||||||
// parse args
|
// parse args
|
||||||
if len(args) != 3 && len(args) != 4 {
|
if len(args) != 3 && len(args) != 4 {
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'geodist' command")
|
return reply.MakeErrReply("ERR wrong number of arguments for 'geodist' command")
|
||||||
@@ -135,8 +135,8 @@ func GeoDist(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeErrReply("ERR unsupported unit provided. please use m, km")
|
return reply.MakeErrReply("ERR unsupported unit provided. please use m, km")
|
||||||
}
|
}
|
||||||
|
|
||||||
// GeoHash return geo-hash-code of given position
|
// execGeoHash return geo-hash-code of given position
|
||||||
func GeoHash(db *DB, args [][]byte) redis.Reply {
|
func execGeoHash(db *DB, args [][]byte) redis.Reply {
|
||||||
// parse args
|
// parse args
|
||||||
if len(args) < 1 {
|
if len(args) < 1 {
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'geohash' command")
|
return reply.MakeErrReply("ERR wrong number of arguments for 'geohash' command")
|
||||||
@@ -165,8 +165,8 @@ func GeoHash(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeMultiBulkReply(strs)
|
return reply.MakeMultiBulkReply(strs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GeoRadius returns members within max distance of given point
|
// execGeoRadius returns members within max distance of given point
|
||||||
func GeoRadius(db *DB, args [][]byte) redis.Reply {
|
func execGeoRadius(db *DB, args [][]byte) redis.Reply {
|
||||||
// parse args
|
// parse args
|
||||||
if len(args) < 5 {
|
if len(args) < 5 {
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'georadius' command")
|
return reply.MakeErrReply("ERR wrong number of arguments for 'georadius' command")
|
||||||
@@ -203,8 +203,8 @@ func GeoRadius(db *DB, args [][]byte) redis.Reply {
|
|||||||
return geoRadius0(sortedSet, lat, lng, radius)
|
return geoRadius0(sortedSet, lat, lng, radius)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GeoRadiusByMember returns members within max distance of given member's location
|
// execGeoRadiusByMember returns members within max distance of given member's location
|
||||||
func GeoRadiusByMember(db *DB, args [][]byte) redis.Reply {
|
func execGeoRadiusByMember(db *DB, args [][]byte) redis.Reply {
|
||||||
// parse args
|
// parse args
|
||||||
if len(args) < 3 {
|
if len(args) < 3 {
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'georadiusbymember' command")
|
return reply.MakeErrReply("ERR wrong number of arguments for 'georadiusbymember' command")
|
||||||
@@ -255,3 +255,12 @@ func geoRadius0(sortedSet *sortedset.SortedSet, lat float64, lng float64, radius
|
|||||||
}
|
}
|
||||||
return reply.MakeMultiBulkReply(members)
|
return reply.MakeMultiBulkReply(members)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
RegisterCommand("GeoAdd", execGeoAdd, nil, -5)
|
||||||
|
RegisterCommand("GeoPos", execGeoPos, nil, -2)
|
||||||
|
RegisterCommand("GeoDist", execGeoDist, nil, -4)
|
||||||
|
RegisterCommand("GeoHash", execGeoHash, nil, -2)
|
||||||
|
RegisterCommand("GeoRadius", execGeoRadius, nil, -6)
|
||||||
|
RegisterCommand("GeoRadiusByMember", execGeoRadiusByMember, nil, -5)
|
||||||
|
}
|
||||||
|
32
geo_test.go
32
geo_test.go
@@ -10,52 +10,52 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestGeoHash(t *testing.T) {
|
func TestGeoHash(t *testing.T) {
|
||||||
FlushDB(testDB, utils.ToBytesList())
|
execFlushDB(testDB, utils.ToBytesList())
|
||||||
key := utils.RandString(10)
|
key := utils.RandString(10)
|
||||||
pos := utils.RandString(10)
|
pos := utils.RandString(10)
|
||||||
result := GeoAdd(testDB, utils.ToBytesList(key, "13.361389", "38.115556", pos))
|
result := execGeoAdd(testDB, utils.ToBytesList(key, "13.361389", "38.115556", pos))
|
||||||
asserts.AssertIntReply(t, result, 1)
|
asserts.AssertIntReply(t, result, 1)
|
||||||
result = GeoHash(testDB, utils.ToBytesList(key, pos))
|
result = execGeoHash(testDB, utils.ToBytesList(key, pos))
|
||||||
asserts.AssertMultiBulkReply(t, result, []string{"sqc8b49rnys00"})
|
asserts.AssertMultiBulkReply(t, result, []string{"sqc8b49rnys00"})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGeoRadius(t *testing.T) {
|
func TestGeoRadius(t *testing.T) {
|
||||||
FlushDB(testDB, utils.ToBytesList())
|
execFlushDB(testDB, utils.ToBytesList())
|
||||||
key := utils.RandString(10)
|
key := utils.RandString(10)
|
||||||
pos1 := utils.RandString(10)
|
pos1 := utils.RandString(10)
|
||||||
pos2 := utils.RandString(10)
|
pos2 := utils.RandString(10)
|
||||||
GeoAdd(testDB, utils.ToBytesList(key,
|
execGeoAdd(testDB, utils.ToBytesList(key,
|
||||||
"13.361389", "38.115556", pos1,
|
"13.361389", "38.115556", pos1,
|
||||||
"15.087269", "37.502669", pos2,
|
"15.087269", "37.502669", pos2,
|
||||||
))
|
))
|
||||||
result := GeoRadius(testDB, utils.ToBytesList(key, "15", "37", "200", "km"))
|
result := execGeoRadius(testDB, utils.ToBytesList(key, "15", "37", "200", "km"))
|
||||||
asserts.AssertMultiBulkReplySize(t, result, 2)
|
asserts.AssertMultiBulkReplySize(t, result, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGeoRadiusByMember(t *testing.T) {
|
func TestGeoRadiusByMember(t *testing.T) {
|
||||||
FlushDB(testDB, utils.ToBytesList())
|
execFlushDB(testDB, utils.ToBytesList())
|
||||||
key := utils.RandString(10)
|
key := utils.RandString(10)
|
||||||
pos1 := utils.RandString(10)
|
pos1 := utils.RandString(10)
|
||||||
pos2 := utils.RandString(10)
|
pos2 := utils.RandString(10)
|
||||||
pivot := utils.RandString(10)
|
pivot := utils.RandString(10)
|
||||||
GeoAdd(testDB, utils.ToBytesList(key,
|
execGeoAdd(testDB, utils.ToBytesList(key,
|
||||||
"13.361389", "38.115556", pos1,
|
"13.361389", "38.115556", pos1,
|
||||||
"17.087269", "38.502669", pos2,
|
"17.087269", "38.502669", pos2,
|
||||||
"13.583333", "37.316667", pivot,
|
"13.583333", "37.316667", pivot,
|
||||||
))
|
))
|
||||||
result := GeoRadiusByMember(testDB, utils.ToBytesList(key, pivot, "100", "km"))
|
result := execGeoRadiusByMember(testDB, utils.ToBytesList(key, pivot, "100", "km"))
|
||||||
asserts.AssertMultiBulkReplySize(t, result, 2)
|
asserts.AssertMultiBulkReplySize(t, result, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGeoPos(t *testing.T) {
|
func TestGeoPos(t *testing.T) {
|
||||||
FlushDB(testDB, utils.ToBytesList())
|
execFlushDB(testDB, utils.ToBytesList())
|
||||||
key := utils.RandString(10)
|
key := utils.RandString(10)
|
||||||
pos1 := utils.RandString(10)
|
pos1 := utils.RandString(10)
|
||||||
pos2 := utils.RandString(10)
|
pos2 := utils.RandString(10)
|
||||||
GeoAdd(testDB, utils.ToBytesList(key,
|
execGeoAdd(testDB, utils.ToBytesList(key,
|
||||||
"13.361389", "38.115556", pos1,
|
"13.361389", "38.115556", pos1,
|
||||||
))
|
))
|
||||||
result := GeoPos(testDB, utils.ToBytesList(key, pos1, pos2))
|
result := execGeoPos(testDB, utils.ToBytesList(key, pos1, pos2))
|
||||||
expected := "*2\r\n*2\r\n$18\r\n13.361386698670685\r\n$17\r\n38.11555536696687\r\n*0\r\n"
|
expected := "*2\r\n*2\r\n$18\r\n13.361386698670685\r\n$17\r\n38.11555536696687\r\n*0\r\n"
|
||||||
if string(result.ToBytes()) != expected {
|
if string(result.ToBytes()) != expected {
|
||||||
t.Error("test failed")
|
t.Error("test failed")
|
||||||
@@ -63,15 +63,15 @@ func TestGeoPos(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestGeoDist(t *testing.T) {
|
func TestGeoDist(t *testing.T) {
|
||||||
FlushDB(testDB, utils.ToBytesList())
|
execFlushDB(testDB, utils.ToBytesList())
|
||||||
key := utils.RandString(10)
|
key := utils.RandString(10)
|
||||||
pos1 := utils.RandString(10)
|
pos1 := utils.RandString(10)
|
||||||
pos2 := utils.RandString(10)
|
pos2 := utils.RandString(10)
|
||||||
GeoAdd(testDB, utils.ToBytesList(key,
|
execGeoAdd(testDB, utils.ToBytesList(key,
|
||||||
"13.361389", "38.115556", pos1,
|
"13.361389", "38.115556", pos1,
|
||||||
"15.087269", "37.502669", pos2,
|
"15.087269", "37.502669", pos2,
|
||||||
))
|
))
|
||||||
result := GeoDist(testDB, utils.ToBytesList(key, pos1, pos2, "km"))
|
result := execGeoDist(testDB, utils.ToBytesList(key, pos1, pos2, "km"))
|
||||||
bulkReply, ok := result.(*reply.BulkReply)
|
bulkReply, ok := result.(*reply.BulkReply)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Error(fmt.Sprintf("expected bulk reply, actually %s", result.ToBytes()))
|
t.Error(fmt.Sprintf("expected bulk reply, actually %s", result.ToBytes()))
|
||||||
@@ -86,7 +86,7 @@ func TestGeoDist(t *testing.T) {
|
|||||||
t.Errorf("expected 166.274, actual: %f", dist)
|
t.Errorf("expected 166.274, actual: %f", dist)
|
||||||
}
|
}
|
||||||
|
|
||||||
result = GeoDist(testDB, utils.ToBytesList(key, pos1, pos2, "m"))
|
result = execGeoDist(testDB, utils.ToBytesList(key, pos1, pos2, "m"))
|
||||||
bulkReply, ok = result.(*reply.BulkReply)
|
bulkReply, ok = result.(*reply.BulkReply)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Error(fmt.Sprintf("expected bulk reply, actually %s", result.ToBytes()))
|
t.Error(fmt.Sprintf("expected bulk reply, actually %s", result.ToBytes()))
|
||||||
|
104
hash.go
104
hash.go
@@ -36,12 +36,9 @@ func (db *DB) getOrInitDict(key string) (dict Dict.Dict, inited bool, errReply r
|
|||||||
return dict, inited, nil
|
return dict, inited, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// HSet sets field in hash table
|
// execHSet sets field in hash table
|
||||||
func HSet(db *DB, args [][]byte) redis.Reply {
|
func execHSet(db *DB, args [][]byte) redis.Reply {
|
||||||
// parse args
|
// parse args
|
||||||
if len(args) != 3 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'hset' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
field := string(args[1])
|
field := string(args[1])
|
||||||
value := args[2]
|
value := args[2]
|
||||||
@@ -61,12 +58,9 @@ func HSet(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeIntReply(int64(result))
|
return reply.MakeIntReply(int64(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
// HSetNX sets field in hash table only if field not exists
|
// execHSetNX sets field in hash table only if field not exists
|
||||||
func HSetNX(db *DB, args [][]byte) redis.Reply {
|
func execHSetNX(db *DB, args [][]byte) redis.Reply {
|
||||||
// parse args
|
// parse args
|
||||||
if len(args) != 3 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'hsetnx' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
field := string(args[1])
|
field := string(args[1])
|
||||||
value := args[2]
|
value := args[2]
|
||||||
@@ -87,12 +81,9 @@ func HSetNX(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeIntReply(int64(result))
|
return reply.MakeIntReply(int64(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
// HGet gets field value of hash table
|
// execHGet gets field value of hash table
|
||||||
func HGet(db *DB, args [][]byte) redis.Reply {
|
func execHGet(db *DB, args [][]byte) redis.Reply {
|
||||||
// parse args
|
// parse args
|
||||||
if len(args) != 2 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'hget' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
field := string(args[1])
|
field := string(args[1])
|
||||||
|
|
||||||
@@ -116,12 +107,9 @@ func HGet(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeBulkReply(value)
|
return reply.MakeBulkReply(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HExists checks if a hash field exists
|
// execHExists checks if a hash field exists
|
||||||
func HExists(db *DB, args [][]byte) redis.Reply {
|
func execHExists(db *DB, args [][]byte) redis.Reply {
|
||||||
// parse args
|
// parse args
|
||||||
if len(args) != 2 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'hexists' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
field := string(args[1])
|
field := string(args[1])
|
||||||
|
|
||||||
@@ -144,12 +132,9 @@ func HExists(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeIntReply(0)
|
return reply.MakeIntReply(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HDel deletes a hash field
|
// execHDel deletes a hash field
|
||||||
func HDel(db *DB, args [][]byte) redis.Reply {
|
func execHDel(db *DB, args [][]byte) redis.Reply {
|
||||||
// parse args
|
// parse args
|
||||||
if len(args) < 2 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'hdel' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
fields := make([]string, len(args)-1)
|
fields := make([]string, len(args)-1)
|
||||||
fieldArgs := args[1:]
|
fieldArgs := args[1:]
|
||||||
@@ -184,12 +169,9 @@ func HDel(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeIntReply(int64(deleted))
|
return reply.MakeIntReply(int64(deleted))
|
||||||
}
|
}
|
||||||
|
|
||||||
// HLen gets number of fields in hash table
|
// execHLen gets number of fields in hash table
|
||||||
func HLen(db *DB, args [][]byte) redis.Reply {
|
func execHLen(db *DB, args [][]byte) redis.Reply {
|
||||||
// parse args
|
// parse args
|
||||||
if len(args) != 1 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'hlen' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
|
|
||||||
db.RLock(key)
|
db.RLock(key)
|
||||||
@@ -205,11 +187,11 @@ func HLen(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeIntReply(int64(dict.Len()))
|
return reply.MakeIntReply(int64(dict.Len()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// HMSet sets multi fields in hash table
|
// execHMSet sets multi fields in hash table
|
||||||
func HMSet(db *DB, args [][]byte) redis.Reply {
|
func execHMSet(db *DB, args [][]byte) redis.Reply {
|
||||||
// parse args
|
// parse args
|
||||||
if len(args) < 3 || len(args)%2 != 1 {
|
if len(args)%2 != 1 {
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'hmset' command")
|
return reply.MakeSyntaxErrReply()
|
||||||
}
|
}
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
size := (len(args) - 1) / 2
|
size := (len(args) - 1) / 2
|
||||||
@@ -241,9 +223,6 @@ func HMSet(db *DB, args [][]byte) redis.Reply {
|
|||||||
|
|
||||||
// HMGet gets multi fields in hash table
|
// HMGet gets multi fields in hash table
|
||||||
func HMGet(db *DB, args [][]byte) redis.Reply {
|
func HMGet(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) < 2 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'hmget' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
size := len(args) - 1
|
size := len(args) - 1
|
||||||
fields := make([]string, size)
|
fields := make([]string, size)
|
||||||
@@ -276,11 +255,8 @@ func HMGet(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeMultiBulkReply(result)
|
return reply.MakeMultiBulkReply(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HKeys gets all field names in hash table
|
// execHKeys gets all field names in hash table
|
||||||
func HKeys(db *DB, args [][]byte) redis.Reply {
|
func execHKeys(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) != 1 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'hkeys' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
|
|
||||||
db.RLock(key)
|
db.RLock(key)
|
||||||
@@ -304,11 +280,8 @@ func HKeys(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeMultiBulkReply(fields[:i])
|
return reply.MakeMultiBulkReply(fields[:i])
|
||||||
}
|
}
|
||||||
|
|
||||||
// HVals gets all field value in hash table
|
// execHVals gets all field value in hash table
|
||||||
func HVals(db *DB, args [][]byte) redis.Reply {
|
func execHVals(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) != 1 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'hvals' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
|
|
||||||
db.RLock(key)
|
db.RLock(key)
|
||||||
@@ -333,11 +306,8 @@ func HVals(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeMultiBulkReply(values[:i])
|
return reply.MakeMultiBulkReply(values[:i])
|
||||||
}
|
}
|
||||||
|
|
||||||
// HGetAll gets all key-value entries in hash table
|
// execHGetAll gets all key-value entries in hash table
|
||||||
func HGetAll(db *DB, args [][]byte) redis.Reply {
|
func execHGetAll(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) != 1 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'hgetAll' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
|
|
||||||
db.RLock(key)
|
db.RLock(key)
|
||||||
@@ -365,11 +335,8 @@ func HGetAll(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeMultiBulkReply(result[:i])
|
return reply.MakeMultiBulkReply(result[:i])
|
||||||
}
|
}
|
||||||
|
|
||||||
// HIncrBy increments the integer value of a hash field by the given number
|
// execHIncrBy increments the integer value of a hash field by the given number
|
||||||
func HIncrBy(db *DB, args [][]byte) redis.Reply {
|
func execHIncrBy(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) != 3 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'hincrby' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
field := string(args[1])
|
field := string(args[1])
|
||||||
rawDelta := string(args[2])
|
rawDelta := string(args[2])
|
||||||
@@ -403,11 +370,8 @@ func HIncrBy(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeBulkReply(bytes)
|
return reply.MakeBulkReply(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HIncrByFloat increments the float value of a hash field by the given number
|
// execHIncrByFloat increments the float value of a hash field by the given number
|
||||||
func HIncrByFloat(db *DB, args [][]byte) redis.Reply {
|
func execHIncrByFloat(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) != 3 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'hincrbyfloat' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
field := string(args[1])
|
field := string(args[1])
|
||||||
rawDelta := string(args[2])
|
rawDelta := string(args[2])
|
||||||
@@ -440,3 +404,19 @@ func HIncrByFloat(db *DB, args [][]byte) redis.Reply {
|
|||||||
db.AddAof(makeAofCmd("hincrbyfloat", args))
|
db.AddAof(makeAofCmd("hincrbyfloat", args))
|
||||||
return reply.MakeBulkReply(resultBytes)
|
return reply.MakeBulkReply(resultBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
RegisterCommand("HSet", execHSet, nil, 4)
|
||||||
|
RegisterCommand("HSetNX", execHSetNX, nil, 4)
|
||||||
|
RegisterCommand("HGet", execHGet, nil, 3)
|
||||||
|
RegisterCommand("HExists", execHExists, nil, 3)
|
||||||
|
RegisterCommand("HDel", execHDel, nil, -3)
|
||||||
|
RegisterCommand("HLen", execHLen, nil, 2)
|
||||||
|
RegisterCommand("HMSet", execHMSet, nil, -4)
|
||||||
|
RegisterCommand("HGet", execHGet, nil, -3)
|
||||||
|
RegisterCommand("HKeys", execHKeys, nil, 2)
|
||||||
|
RegisterCommand("HVals", execHVals, nil, 2)
|
||||||
|
RegisterCommand("HGetAll", execHGetAll, nil, 2)
|
||||||
|
RegisterCommand("HIncrBy", execHIncrBy, nil, 4)
|
||||||
|
RegisterCommand("HIncrByFloat", execHIncrByFloat, nil, 4)
|
||||||
|
}
|
||||||
|
50
hash_test.go
50
hash_test.go
@@ -11,7 +11,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestHSet(t *testing.T) {
|
func TestHSet(t *testing.T) {
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
size := 100
|
size := 100
|
||||||
|
|
||||||
// test hset
|
// test hset
|
||||||
@@ -21,7 +21,7 @@ func TestHSet(t *testing.T) {
|
|||||||
value := utils2.RandString(10)
|
value := utils2.RandString(10)
|
||||||
field := strconv.Itoa(i)
|
field := strconv.Itoa(i)
|
||||||
values[field] = []byte(value)
|
values[field] = []byte(value)
|
||||||
result := HSet(testDB, utils2.ToBytesList(key, field, value))
|
result := execHSet(testDB, utils2.ToBytesList(key, field, value))
|
||||||
if intResult, _ := result.(*reply.IntReply); intResult.Code != int64(1) {
|
if intResult, _ := result.(*reply.IntReply); intResult.Code != int64(1) {
|
||||||
t.Error(fmt.Sprintf("expected %d, actually %d", 1, intResult.Code))
|
t.Error(fmt.Sprintf("expected %d, actually %d", 1, intResult.Code))
|
||||||
}
|
}
|
||||||
@@ -29,26 +29,26 @@ func TestHSet(t *testing.T) {
|
|||||||
|
|
||||||
// test hget and hexists
|
// test hget and hexists
|
||||||
for field, v := range values {
|
for field, v := range values {
|
||||||
actual := HGet(testDB, utils2.ToBytesList(key, field))
|
actual := execHGet(testDB, utils2.ToBytesList(key, field))
|
||||||
expected := reply.MakeBulkReply(v)
|
expected := reply.MakeBulkReply(v)
|
||||||
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
|
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
|
||||||
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(actual.ToBytes())))
|
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(actual.ToBytes())))
|
||||||
}
|
}
|
||||||
actual = HExists(testDB, utils2.ToBytesList(key, field))
|
actual = execHExists(testDB, utils2.ToBytesList(key, field))
|
||||||
if intResult, _ := actual.(*reply.IntReply); intResult.Code != int64(1) {
|
if intResult, _ := actual.(*reply.IntReply); intResult.Code != int64(1) {
|
||||||
t.Error(fmt.Sprintf("expected %d, actually %d", 1, intResult.Code))
|
t.Error(fmt.Sprintf("expected %d, actually %d", 1, intResult.Code))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// test hlen
|
// test hlen
|
||||||
actual := HLen(testDB, utils2.ToBytesList(key))
|
actual := execHLen(testDB, utils2.ToBytesList(key))
|
||||||
if intResult, _ := actual.(*reply.IntReply); intResult.Code != int64(len(values)) {
|
if intResult, _ := actual.(*reply.IntReply); intResult.Code != int64(len(values)) {
|
||||||
t.Error(fmt.Sprintf("expected %d, actually %d", len(values), intResult.Code))
|
t.Error(fmt.Sprintf("expected %d, actually %d", len(values), intResult.Code))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHDel(t *testing.T) {
|
func TestHDel(t *testing.T) {
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
size := 100
|
size := 100
|
||||||
|
|
||||||
// set values
|
// set values
|
||||||
@@ -58,25 +58,25 @@ func TestHDel(t *testing.T) {
|
|||||||
value := utils2.RandString(10)
|
value := utils2.RandString(10)
|
||||||
field := strconv.Itoa(i)
|
field := strconv.Itoa(i)
|
||||||
fields[i] = field
|
fields[i] = field
|
||||||
HSet(testDB, utils2.ToBytesList(key, field, value))
|
execHSet(testDB, utils2.ToBytesList(key, field, value))
|
||||||
}
|
}
|
||||||
|
|
||||||
// test HDel
|
// test HDel
|
||||||
args := []string{key}
|
args := []string{key}
|
||||||
args = append(args, fields...)
|
args = append(args, fields...)
|
||||||
actual := HDel(testDB, utils2.ToBytesList(args...))
|
actual := execHDel(testDB, utils2.ToBytesList(args...))
|
||||||
if intResult, _ := actual.(*reply.IntReply); intResult.Code != int64(len(fields)) {
|
if intResult, _ := actual.(*reply.IntReply); intResult.Code != int64(len(fields)) {
|
||||||
t.Error(fmt.Sprintf("expected %d, actually %d", len(fields), intResult.Code))
|
t.Error(fmt.Sprintf("expected %d, actually %d", len(fields), intResult.Code))
|
||||||
}
|
}
|
||||||
|
|
||||||
actual = HLen(testDB, utils2.ToBytesList(key))
|
actual = execHLen(testDB, utils2.ToBytesList(key))
|
||||||
if intResult, _ := actual.(*reply.IntReply); intResult.Code != int64(0) {
|
if intResult, _ := actual.(*reply.IntReply); intResult.Code != int64(0) {
|
||||||
t.Error(fmt.Sprintf("expected %d, actually %d", 0, intResult.Code))
|
t.Error(fmt.Sprintf("expected %d, actually %d", 0, intResult.Code))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHMSet(t *testing.T) {
|
func TestHMSet(t *testing.T) {
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
size := 100
|
size := 100
|
||||||
|
|
||||||
// test hset
|
// test hset
|
||||||
@@ -89,7 +89,7 @@ func TestHMSet(t *testing.T) {
|
|||||||
values[i] = utils2.RandString(10)
|
values[i] = utils2.RandString(10)
|
||||||
setArgs = append(setArgs, fields[i], values[i])
|
setArgs = append(setArgs, fields[i], values[i])
|
||||||
}
|
}
|
||||||
result := HMSet(testDB, utils2.ToBytesList(setArgs...))
|
result := execHMSet(testDB, utils2.ToBytesList(setArgs...))
|
||||||
if _, ok := result.(*reply.OkReply); !ok {
|
if _, ok := result.(*reply.OkReply); !ok {
|
||||||
t.Error(fmt.Sprintf("expected ok, actually %s", string(result.ToBytes())))
|
t.Error(fmt.Sprintf("expected ok, actually %s", string(result.ToBytes())))
|
||||||
}
|
}
|
||||||
@@ -105,7 +105,7 @@ func TestHMSet(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestHGetAll(t *testing.T) {
|
func TestHGetAll(t *testing.T) {
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
size := 100
|
size := 100
|
||||||
key := utils2.RandString(10)
|
key := utils2.RandString(10)
|
||||||
fields := make([]string, size)
|
fields := make([]string, size)
|
||||||
@@ -118,11 +118,11 @@ func TestHGetAll(t *testing.T) {
|
|||||||
all = append(all, fields[i], value)
|
all = append(all, fields[i], value)
|
||||||
valueMap[fields[i]] = value
|
valueMap[fields[i]] = value
|
||||||
valueSet[value] = true
|
valueSet[value] = true
|
||||||
HSet(testDB, utils2.ToBytesList(key, fields[i], value))
|
execHSet(testDB, utils2.ToBytesList(key, fields[i], value))
|
||||||
}
|
}
|
||||||
|
|
||||||
// test HGetAll
|
// test HGetAll
|
||||||
result := HGetAll(testDB, utils2.ToBytesList(key))
|
result := execHGetAll(testDB, utils2.ToBytesList(key))
|
||||||
multiBulk, ok := result.(*reply.MultiBulkReply)
|
multiBulk, ok := result.(*reply.MultiBulkReply)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Error(fmt.Sprintf("expected MultiBulkReply, actually %s", string(result.ToBytes())))
|
t.Error(fmt.Sprintf("expected MultiBulkReply, actually %s", string(result.ToBytes())))
|
||||||
@@ -144,7 +144,7 @@ func TestHGetAll(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// test HKeys
|
// test HKeys
|
||||||
result = HKeys(testDB, utils2.ToBytesList(key))
|
result = execHKeys(testDB, utils2.ToBytesList(key))
|
||||||
multiBulk, ok = result.(*reply.MultiBulkReply)
|
multiBulk, ok = result.(*reply.MultiBulkReply)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Error(fmt.Sprintf("expected MultiBulkReply, actually %s", string(result.ToBytes())))
|
t.Error(fmt.Sprintf("expected MultiBulkReply, actually %s", string(result.ToBytes())))
|
||||||
@@ -160,7 +160,7 @@ func TestHGetAll(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// test HVals
|
// test HVals
|
||||||
result = HVals(testDB, utils2.ToBytesList(key))
|
result = execHVals(testDB, utils2.ToBytesList(key))
|
||||||
multiBulk, ok = result.(*reply.MultiBulkReply)
|
multiBulk, ok = result.(*reply.MultiBulkReply)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Error(fmt.Sprintf("expected MultiBulkReply, actually %s", string(result.ToBytes())))
|
t.Error(fmt.Sprintf("expected MultiBulkReply, actually %s", string(result.ToBytes())))
|
||||||
@@ -178,39 +178,39 @@ func TestHGetAll(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestHIncrBy(t *testing.T) {
|
func TestHIncrBy(t *testing.T) {
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
|
|
||||||
key := utils2.RandString(10)
|
key := utils2.RandString(10)
|
||||||
result := HIncrBy(testDB, utils2.ToBytesList(key, "a", "1"))
|
result := execHIncrBy(testDB, utils2.ToBytesList(key, "a", "1"))
|
||||||
if bulkResult, _ := result.(*reply.BulkReply); string(bulkResult.Arg) != "1" {
|
if bulkResult, _ := result.(*reply.BulkReply); string(bulkResult.Arg) != "1" {
|
||||||
t.Error(fmt.Sprintf("expected %s, actually %s", "1", string(bulkResult.Arg)))
|
t.Error(fmt.Sprintf("expected %s, actually %s", "1", string(bulkResult.Arg)))
|
||||||
}
|
}
|
||||||
result = HIncrBy(testDB, utils2.ToBytesList(key, "a", "1"))
|
result = execHIncrBy(testDB, utils2.ToBytesList(key, "a", "1"))
|
||||||
if bulkResult, _ := result.(*reply.BulkReply); string(bulkResult.Arg) != "2" {
|
if bulkResult, _ := result.(*reply.BulkReply); string(bulkResult.Arg) != "2" {
|
||||||
t.Error(fmt.Sprintf("expected %s, actually %s", "2", string(bulkResult.Arg)))
|
t.Error(fmt.Sprintf("expected %s, actually %s", "2", string(bulkResult.Arg)))
|
||||||
}
|
}
|
||||||
|
|
||||||
result = HIncrByFloat(testDB, utils2.ToBytesList(key, "b", "1.2"))
|
result = execHIncrByFloat(testDB, utils2.ToBytesList(key, "b", "1.2"))
|
||||||
if bulkResult, _ := result.(*reply.BulkReply); string(bulkResult.Arg) != "1.2" {
|
if bulkResult, _ := result.(*reply.BulkReply); string(bulkResult.Arg) != "1.2" {
|
||||||
t.Error(fmt.Sprintf("expected %s, actually %s", "1.2", string(bulkResult.Arg)))
|
t.Error(fmt.Sprintf("expected %s, actually %s", "1.2", string(bulkResult.Arg)))
|
||||||
}
|
}
|
||||||
result = HIncrByFloat(testDB, utils2.ToBytesList(key, "b", "1.2"))
|
result = execHIncrByFloat(testDB, utils2.ToBytesList(key, "b", "1.2"))
|
||||||
if bulkResult, _ := result.(*reply.BulkReply); string(bulkResult.Arg) != "2.4" {
|
if bulkResult, _ := result.(*reply.BulkReply); string(bulkResult.Arg) != "2.4" {
|
||||||
t.Error(fmt.Sprintf("expected %s, actually %s", "2.4", string(bulkResult.Arg)))
|
t.Error(fmt.Sprintf("expected %s, actually %s", "2.4", string(bulkResult.Arg)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHSetNX(t *testing.T) {
|
func TestHSetNX(t *testing.T) {
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
key := utils2.RandString(10)
|
key := utils2.RandString(10)
|
||||||
field := utils2.RandString(10)
|
field := utils2.RandString(10)
|
||||||
value := utils2.RandString(10)
|
value := utils2.RandString(10)
|
||||||
result := HSetNX(testDB, utils2.ToBytesList(key, field, value))
|
result := execHSetNX(testDB, utils2.ToBytesList(key, field, value))
|
||||||
asserts.AssertIntReply(t, result, 1)
|
asserts.AssertIntReply(t, result, 1)
|
||||||
value2 := utils2.RandString(10)
|
value2 := utils2.RandString(10)
|
||||||
result = HSetNX(testDB, utils2.ToBytesList(key, field, value2))
|
result = execHSetNX(testDB, utils2.ToBytesList(key, field, value2))
|
||||||
asserts.AssertIntReply(t, result, 0)
|
asserts.AssertIntReply(t, result, 0)
|
||||||
result = HGet(testDB, utils2.ToBytesList(key, field))
|
result = execHGet(testDB, utils2.ToBytesList(key, field))
|
||||||
asserts.AssertBulkReply(t, result, value)
|
asserts.AssertBulkReply(t, result, value)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
136
keys.go
136
keys.go
@@ -12,11 +12,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Del removes a key from db
|
// execDel removes a key from db
|
||||||
func Del(db *DB, args [][]byte) redis.Reply {
|
func execDel(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) == 0 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'del' command")
|
|
||||||
}
|
|
||||||
keys := make([]string, len(args))
|
keys := make([]string, len(args))
|
||||||
for i, v := range args {
|
for i, v := range args {
|
||||||
keys[i] = string(v)
|
keys[i] = string(v)
|
||||||
@@ -32,44 +29,35 @@ func Del(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeIntReply(int64(deleted))
|
return reply.MakeIntReply(int64(deleted))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exists checks if a is existed in db
|
// execExists checks if a is existed in db
|
||||||
func Exists(db *DB, args [][]byte) redis.Reply {
|
func execExists(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) != 1 {
|
result := int64(0)
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'exists' command")
|
for _, arg := range args {
|
||||||
|
key := string(arg)
|
||||||
|
_, exists := db.GetEntity(key)
|
||||||
|
if exists {
|
||||||
|
result++
|
||||||
|
}
|
||||||
}
|
}
|
||||||
key := string(args[0])
|
return reply.MakeIntReply(result)
|
||||||
_, exists := db.GetEntity(key)
|
|
||||||
if exists {
|
|
||||||
return reply.MakeIntReply(1)
|
|
||||||
}
|
|
||||||
return reply.MakeIntReply(0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FlushDB removes all data in current db
|
// execFlushDB removes all data in current db
|
||||||
func FlushDB(db *DB, args [][]byte) redis.Reply {
|
func execFlushDB(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) != 0 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'flushdb' command")
|
|
||||||
}
|
|
||||||
db.Flush()
|
db.Flush()
|
||||||
db.AddAof(makeAofCmd("flushdb", args))
|
db.AddAof(makeAofCmd("flushdb", args))
|
||||||
return &reply.OkReply{}
|
return &reply.OkReply{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FlushAll removes all data in all db
|
// execFlushAll removes all data in all db
|
||||||
func FlushAll(db *DB, args [][]byte) redis.Reply {
|
func execFlushAll(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) != 0 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'flushall' command")
|
|
||||||
}
|
|
||||||
db.Flush()
|
db.Flush()
|
||||||
db.AddAof(makeAofCmd("flushdb", args))
|
db.AddAof(makeAofCmd("flushdb", args))
|
||||||
return &reply.OkReply{}
|
return &reply.OkReply{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Type returns the type of entity, including: string, list, hash, set and zset
|
// execType returns the type of entity, including: string, list, hash, set and zset
|
||||||
func Type(db *DB, args [][]byte) redis.Reply {
|
func execType(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) != 1 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'type' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
entity, exists := db.GetEntity(key)
|
entity, exists := db.GetEntity(key)
|
||||||
if !exists {
|
if !exists {
|
||||||
@@ -90,8 +78,8 @@ func Type(db *DB, args [][]byte) redis.Reply {
|
|||||||
return &reply.UnknownErrReply{}
|
return &reply.UnknownErrReply{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rename a key
|
// execRename a key
|
||||||
func Rename(db *DB, args [][]byte) redis.Reply {
|
func execRename(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) != 2 {
|
if len(args) != 2 {
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'rename' command")
|
return reply.MakeErrReply("ERR wrong number of arguments for 'rename' command")
|
||||||
}
|
}
|
||||||
@@ -118,11 +106,8 @@ func Rename(db *DB, args [][]byte) redis.Reply {
|
|||||||
return &reply.OkReply{}
|
return &reply.OkReply{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RenameNx a key, only if the new key does not exist
|
// execRenameNx a key, only if the new key does not exist
|
||||||
func RenameNx(db *DB, args [][]byte) redis.Reply {
|
func execRenameNx(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) != 2 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'renamenx' command")
|
|
||||||
}
|
|
||||||
src := string(args[0])
|
src := string(args[0])
|
||||||
dest := string(args[1])
|
dest := string(args[1])
|
||||||
|
|
||||||
@@ -151,11 +136,8 @@ func RenameNx(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeIntReply(1)
|
return reply.MakeIntReply(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expire sets a key's time to live in seconds
|
// execExpire sets a key's time to live in seconds
|
||||||
func Expire(db *DB, args [][]byte) redis.Reply {
|
func execExpire(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) != 2 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'expire' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
|
|
||||||
ttlArg, err := strconv.ParseInt(string(args[1]), 10, 64)
|
ttlArg, err := strconv.ParseInt(string(args[1]), 10, 64)
|
||||||
@@ -175,11 +157,8 @@ func Expire(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeIntReply(1)
|
return reply.MakeIntReply(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExpireAt sets a key's expiration in unix timestamp
|
// execExpireAt sets a key's expiration in unix timestamp
|
||||||
func ExpireAt(db *DB, args [][]byte) redis.Reply {
|
func execExpireAt(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) != 2 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'expireat' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
|
|
||||||
raw, err := strconv.ParseInt(string(args[1]), 10, 64)
|
raw, err := strconv.ParseInt(string(args[1]), 10, 64)
|
||||||
@@ -198,11 +177,8 @@ func ExpireAt(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeIntReply(1)
|
return reply.MakeIntReply(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PExpire sets a key's time to live in milliseconds
|
// execPExpire sets a key's time to live in milliseconds
|
||||||
func PExpire(db *DB, args [][]byte) redis.Reply {
|
func execPExpire(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) != 2 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'pexpire' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
|
|
||||||
ttlArg, err := strconv.ParseInt(string(args[1]), 10, 64)
|
ttlArg, err := strconv.ParseInt(string(args[1]), 10, 64)
|
||||||
@@ -222,11 +198,8 @@ func PExpire(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeIntReply(1)
|
return reply.MakeIntReply(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PExpireAt sets a key's expiration in unix timestamp specified in milliseconds
|
// execPExpireAt sets a key's expiration in unix timestamp specified in milliseconds
|
||||||
func PExpireAt(db *DB, args [][]byte) redis.Reply {
|
func execPExpireAt(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) != 2 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'pexpireat' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
|
|
||||||
raw, err := strconv.ParseInt(string(args[1]), 10, 64)
|
raw, err := strconv.ParseInt(string(args[1]), 10, 64)
|
||||||
@@ -246,11 +219,8 @@ func PExpireAt(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeIntReply(1)
|
return reply.MakeIntReply(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TTL returns a key's time to live in seconds
|
// execTTL returns a key's time to live in seconds
|
||||||
func TTL(db *DB, args [][]byte) redis.Reply {
|
func execTTL(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) != 1 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'ttl' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
_, exists := db.GetEntity(key)
|
_, exists := db.GetEntity(key)
|
||||||
if !exists {
|
if !exists {
|
||||||
@@ -266,11 +236,8 @@ func TTL(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeIntReply(int64(ttl / time.Second))
|
return reply.MakeIntReply(int64(ttl / time.Second))
|
||||||
}
|
}
|
||||||
|
|
||||||
// PTTL returns a key's time to live in milliseconds
|
// execPTTL returns a key's time to live in milliseconds
|
||||||
func PTTL(db *DB, args [][]byte) redis.Reply {
|
func execPTTL(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) != 1 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'pttl' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
_, exists := db.GetEntity(key)
|
_, exists := db.GetEntity(key)
|
||||||
if !exists {
|
if !exists {
|
||||||
@@ -286,11 +253,8 @@ func PTTL(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeIntReply(int64(ttl / time.Millisecond))
|
return reply.MakeIntReply(int64(ttl / time.Millisecond))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Persist removes expiration from a key
|
// execPersist removes expiration from a key
|
||||||
func Persist(db *DB, args [][]byte) redis.Reply {
|
func execPersist(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) != 1 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'persist' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
_, exists := db.GetEntity(key)
|
_, exists := db.GetEntity(key)
|
||||||
if !exists {
|
if !exists {
|
||||||
@@ -309,18 +273,12 @@ func Persist(db *DB, args [][]byte) redis.Reply {
|
|||||||
|
|
||||||
// BGRewriteAOF asynchronously rewrites Append-Only-File
|
// BGRewriteAOF asynchronously rewrites Append-Only-File
|
||||||
func BGRewriteAOF(db *DB, args [][]byte) redis.Reply {
|
func BGRewriteAOF(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) != 0 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'bgrewriteaof' command")
|
|
||||||
}
|
|
||||||
go db.aofRewrite()
|
go db.aofRewrite()
|
||||||
return reply.MakeStatusReply("Background append only file rewriting started")
|
return reply.MakeStatusReply("Background append only file rewriting started")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keys returns all keys matching the given pattern
|
// execKeys returns all keys matching the given pattern
|
||||||
func Keys(db *DB, args [][]byte) redis.Reply {
|
func execKeys(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) != 1 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'keys' command")
|
|
||||||
}
|
|
||||||
pattern := wildcard.CompilePattern(string(args[0]))
|
pattern := wildcard.CompilePattern(string(args[0]))
|
||||||
result := make([][]byte, 0)
|
result := make([][]byte, 0)
|
||||||
db.data.ForEach(func(key string, val interface{}) bool {
|
db.data.ForEach(func(key string, val interface{}) bool {
|
||||||
@@ -331,3 +289,21 @@ func Keys(db *DB, args [][]byte) redis.Reply {
|
|||||||
})
|
})
|
||||||
return reply.MakeMultiBulkReply(result)
|
return reply.MakeMultiBulkReply(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
RegisterCommand("Del", execDel, nil, -2)
|
||||||
|
RegisterCommand("Expire", execExpire, nil, 3)
|
||||||
|
RegisterCommand("ExpireAt", execExpireAt, nil, 3)
|
||||||
|
RegisterCommand("PExpire", execPExpire, nil, 3)
|
||||||
|
RegisterCommand("PExpireAt", execPExpireAt, nil, 3)
|
||||||
|
RegisterCommand("TTL", execTTL, nil, 2)
|
||||||
|
RegisterCommand("PTTL", execPTTL, nil, 2)
|
||||||
|
RegisterCommand("Persist", execPersist, nil, 2)
|
||||||
|
RegisterCommand("Exists", execExists, nil, -2)
|
||||||
|
RegisterCommand("Type", execType, nil, 2)
|
||||||
|
RegisterCommand("Rename", execRename, nil, 3)
|
||||||
|
RegisterCommand("RenameNx", execRenameNx, nil, 3)
|
||||||
|
RegisterCommand("FlushDB", execFlushDB, nil, -1)
|
||||||
|
RegisterCommand("FlushAll", execFlushAll, nil, -1)
|
||||||
|
RegisterCommand("Keys", execKeys, nil, 2)
|
||||||
|
}
|
||||||
|
106
keys_test.go
106
keys_test.go
@@ -11,65 +11,65 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestExists(t *testing.T) {
|
func TestExists(t *testing.T) {
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
key := utils.RandString(10)
|
key := utils.RandString(10)
|
||||||
value := utils.RandString(10)
|
value := utils.RandString(10)
|
||||||
Set(testDB, utils.ToBytesList(key, value))
|
execSet(testDB, utils.ToBytesList(key, value))
|
||||||
result := Exists(testDB, utils.ToBytesList(key))
|
result := execExists(testDB, utils.ToBytesList(key))
|
||||||
asserts.AssertIntReply(t, result, 1)
|
asserts.AssertIntReply(t, result, 1)
|
||||||
key = utils.RandString(10)
|
key = utils.RandString(10)
|
||||||
result = Exists(testDB, utils.ToBytesList(key))
|
result = execExists(testDB, utils.ToBytesList(key))
|
||||||
asserts.AssertIntReply(t, result, 0)
|
asserts.AssertIntReply(t, result, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestType(t *testing.T) {
|
func TestType(t *testing.T) {
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
key := utils.RandString(10)
|
key := utils.RandString(10)
|
||||||
value := utils.RandString(10)
|
value := utils.RandString(10)
|
||||||
Set(testDB, utils.ToBytesList(key, value))
|
execSet(testDB, utils.ToBytesList(key, value))
|
||||||
result := Type(testDB, utils.ToBytesList(key))
|
result := execType(testDB, utils.ToBytesList(key))
|
||||||
asserts.AssertStatusReply(t, result, "string")
|
asserts.AssertStatusReply(t, result, "string")
|
||||||
|
|
||||||
Del(testDB, utils.ToBytesList(key))
|
testDB.Remove(key)
|
||||||
result = Type(testDB, utils.ToBytesList(key))
|
result = execType(testDB, utils.ToBytesList(key))
|
||||||
asserts.AssertStatusReply(t, result, "none")
|
asserts.AssertStatusReply(t, result, "none")
|
||||||
RPush(testDB, utils.ToBytesList(key, value))
|
execRPush(testDB, utils.ToBytesList(key, value))
|
||||||
result = Type(testDB, utils.ToBytesList(key))
|
result = execType(testDB, utils.ToBytesList(key))
|
||||||
asserts.AssertStatusReply(t, result, "list")
|
asserts.AssertStatusReply(t, result, "list")
|
||||||
|
|
||||||
Del(testDB, utils.ToBytesList(key))
|
testDB.Remove(key)
|
||||||
HSet(testDB, utils.ToBytesList(key, key, value))
|
execHSet(testDB, utils.ToBytesList(key, key, value))
|
||||||
result = Type(testDB, utils.ToBytesList(key))
|
result = execType(testDB, utils.ToBytesList(key))
|
||||||
asserts.AssertStatusReply(t, result, "hash")
|
asserts.AssertStatusReply(t, result, "hash")
|
||||||
|
|
||||||
Del(testDB, utils.ToBytesList(key))
|
testDB.Remove(key)
|
||||||
SAdd(testDB, utils.ToBytesList(key, value))
|
execSAdd(testDB, utils.ToBytesList(key, value))
|
||||||
result = Type(testDB, utils.ToBytesList(key))
|
result = execType(testDB, utils.ToBytesList(key))
|
||||||
asserts.AssertStatusReply(t, result, "set")
|
asserts.AssertStatusReply(t, result, "set")
|
||||||
|
|
||||||
Del(testDB, utils.ToBytesList(key))
|
testDB.Remove(key)
|
||||||
ZAdd(testDB, utils.ToBytesList(key, "1", value))
|
execZAdd(testDB, utils.ToBytesList(key, "1", value))
|
||||||
result = Type(testDB, utils.ToBytesList(key))
|
result = execType(testDB, utils.ToBytesList(key))
|
||||||
asserts.AssertStatusReply(t, result, "zset")
|
asserts.AssertStatusReply(t, result, "zset")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRename(t *testing.T) {
|
func TestRename(t *testing.T) {
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
key := utils.RandString(10)
|
key := utils.RandString(10)
|
||||||
value := utils.RandString(10)
|
value := utils.RandString(10)
|
||||||
newKey := key + utils.RandString(2)
|
newKey := key + utils.RandString(2)
|
||||||
Set(testDB, utils.ToBytesList(key, value, "ex", "1000"))
|
execSet(testDB, utils.ToBytesList(key, value, "ex", "1000"))
|
||||||
result := Rename(testDB, utils.ToBytesList(key, newKey))
|
result := execRename(testDB, utils.ToBytesList(key, newKey))
|
||||||
if _, ok := result.(*reply.OkReply); !ok {
|
if _, ok := result.(*reply.OkReply); !ok {
|
||||||
t.Error("expect ok")
|
t.Error("expect ok")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
result = Exists(testDB, utils.ToBytesList(key))
|
result = execExists(testDB, utils.ToBytesList(key))
|
||||||
asserts.AssertIntReply(t, result, 0)
|
asserts.AssertIntReply(t, result, 0)
|
||||||
result = Exists(testDB, utils.ToBytesList(newKey))
|
result = execExists(testDB, utils.ToBytesList(newKey))
|
||||||
asserts.AssertIntReply(t, result, 1)
|
asserts.AssertIntReply(t, result, 1)
|
||||||
// check ttl
|
// check ttl
|
||||||
result = TTL(testDB, utils.ToBytesList(newKey))
|
result = execTTL(testDB, utils.ToBytesList(newKey))
|
||||||
intResult, ok := result.(*reply.IntReply)
|
intResult, ok := result.(*reply.IntReply)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Error(fmt.Sprintf("expected int reply, actually %s", result.ToBytes()))
|
t.Error(fmt.Sprintf("expected int reply, actually %s", result.ToBytes()))
|
||||||
@@ -82,18 +82,18 @@ func TestRename(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestRenameNx(t *testing.T) {
|
func TestRenameNx(t *testing.T) {
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
key := utils.RandString(10)
|
key := utils.RandString(10)
|
||||||
value := utils.RandString(10)
|
value := utils.RandString(10)
|
||||||
newKey := key + utils.RandString(2)
|
newKey := key + utils.RandString(2)
|
||||||
Set(testDB, utils.ToBytesList(key, value, "ex", "1000"))
|
execSet(testDB, utils.ToBytesList(key, value, "ex", "1000"))
|
||||||
result := RenameNx(testDB, utils.ToBytesList(key, newKey))
|
result := execRenameNx(testDB, utils.ToBytesList(key, newKey))
|
||||||
asserts.AssertIntReply(t, result, 1)
|
asserts.AssertIntReply(t, result, 1)
|
||||||
result = Exists(testDB, utils.ToBytesList(key))
|
result = execExists(testDB, utils.ToBytesList(key))
|
||||||
asserts.AssertIntReply(t, result, 0)
|
asserts.AssertIntReply(t, result, 0)
|
||||||
result = Exists(testDB, utils.ToBytesList(newKey))
|
result = execExists(testDB, utils.ToBytesList(newKey))
|
||||||
asserts.AssertIntReply(t, result, 1)
|
asserts.AssertIntReply(t, result, 1)
|
||||||
result = TTL(testDB, utils.ToBytesList(newKey))
|
result = execTTL(testDB, utils.ToBytesList(newKey))
|
||||||
intResult, ok := result.(*reply.IntReply)
|
intResult, ok := result.(*reply.IntReply)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Error(fmt.Sprintf("expected int reply, actually %s", result.ToBytes()))
|
t.Error(fmt.Sprintf("expected int reply, actually %s", result.ToBytes()))
|
||||||
@@ -106,14 +106,14 @@ func TestRenameNx(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestTTL(t *testing.T) {
|
func TestTTL(t *testing.T) {
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
key := utils.RandString(10)
|
key := utils.RandString(10)
|
||||||
value := utils.RandString(10)
|
value := utils.RandString(10)
|
||||||
Set(testDB, utils.ToBytesList(key, value))
|
execSet(testDB, utils.ToBytesList(key, value))
|
||||||
|
|
||||||
result := Expire(testDB, utils.ToBytesList(key, "1000"))
|
result := execExpire(testDB, utils.ToBytesList(key, "1000"))
|
||||||
asserts.AssertIntReply(t, result, 1)
|
asserts.AssertIntReply(t, result, 1)
|
||||||
result = TTL(testDB, utils.ToBytesList(key))
|
result = execTTL(testDB, utils.ToBytesList(key))
|
||||||
intResult, ok := result.(*reply.IntReply)
|
intResult, ok := result.(*reply.IntReply)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Error(fmt.Sprintf("expected int reply, actually %s", result.ToBytes()))
|
t.Error(fmt.Sprintf("expected int reply, actually %s", result.ToBytes()))
|
||||||
@@ -124,14 +124,14 @@ func TestTTL(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
result = Persist(testDB, utils.ToBytesList(key))
|
result = execPersist(testDB, utils.ToBytesList(key))
|
||||||
asserts.AssertIntReply(t, result, 1)
|
asserts.AssertIntReply(t, result, 1)
|
||||||
result = TTL(testDB, utils.ToBytesList(key))
|
result = execTTL(testDB, utils.ToBytesList(key))
|
||||||
asserts.AssertIntReply(t, result, -1)
|
asserts.AssertIntReply(t, result, -1)
|
||||||
|
|
||||||
result = PExpire(testDB, utils.ToBytesList(key, "1000000"))
|
result = execPExpire(testDB, utils.ToBytesList(key, "1000000"))
|
||||||
asserts.AssertIntReply(t, result, 1)
|
asserts.AssertIntReply(t, result, 1)
|
||||||
result = PTTL(testDB, utils.ToBytesList(key))
|
result = execPTTL(testDB, utils.ToBytesList(key))
|
||||||
intResult, ok = result.(*reply.IntReply)
|
intResult, ok = result.(*reply.IntReply)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Error(fmt.Sprintf("expected int reply, actually %s", result.ToBytes()))
|
t.Error(fmt.Sprintf("expected int reply, actually %s", result.ToBytes()))
|
||||||
@@ -144,15 +144,15 @@ func TestTTL(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestExpireAt(t *testing.T) {
|
func TestExpireAt(t *testing.T) {
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
key := utils.RandString(10)
|
key := utils.RandString(10)
|
||||||
value := utils.RandString(10)
|
value := utils.RandString(10)
|
||||||
Set(testDB, utils.ToBytesList(key, value))
|
execSet(testDB, utils.ToBytesList(key, value))
|
||||||
|
|
||||||
expireAt := time.Now().Add(time.Minute).Unix()
|
expireAt := time.Now().Add(time.Minute).Unix()
|
||||||
result := ExpireAt(testDB, utils.ToBytesList(key, strconv.FormatInt(expireAt, 10)))
|
result := execExpireAt(testDB, utils.ToBytesList(key, strconv.FormatInt(expireAt, 10)))
|
||||||
asserts.AssertIntReply(t, result, 1)
|
asserts.AssertIntReply(t, result, 1)
|
||||||
result = TTL(testDB, utils.ToBytesList(key))
|
result = execTTL(testDB, utils.ToBytesList(key))
|
||||||
intResult, ok := result.(*reply.IntReply)
|
intResult, ok := result.(*reply.IntReply)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Error(fmt.Sprintf("expected int reply, actually %s", result.ToBytes()))
|
t.Error(fmt.Sprintf("expected int reply, actually %s", result.ToBytes()))
|
||||||
@@ -164,9 +164,9 @@ func TestExpireAt(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
expireAt = time.Now().Add(time.Minute).Unix()
|
expireAt = time.Now().Add(time.Minute).Unix()
|
||||||
result = PExpireAt(testDB, utils.ToBytesList(key, strconv.FormatInt(expireAt*1000, 10)))
|
result = execPExpireAt(testDB, utils.ToBytesList(key, strconv.FormatInt(expireAt*1000, 10)))
|
||||||
asserts.AssertIntReply(t, result, 1)
|
asserts.AssertIntReply(t, result, 1)
|
||||||
result = TTL(testDB, utils.ToBytesList(key))
|
result = execTTL(testDB, utils.ToBytesList(key))
|
||||||
intResult, ok = result.(*reply.IntReply)
|
intResult, ok = result.(*reply.IntReply)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Error(fmt.Sprintf("expected int reply, actually %s", result.ToBytes()))
|
t.Error(fmt.Sprintf("expected int reply, actually %s", result.ToBytes()))
|
||||||
@@ -179,17 +179,17 @@ func TestExpireAt(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestKeys(t *testing.T) {
|
func TestKeys(t *testing.T) {
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
key := utils.RandString(10)
|
key := utils.RandString(10)
|
||||||
value := utils.RandString(10)
|
value := utils.RandString(10)
|
||||||
Set(testDB, utils.ToBytesList(key, value))
|
execSet(testDB, utils.ToBytesList(key, value))
|
||||||
Set(testDB, utils.ToBytesList("a:"+key, value))
|
execSet(testDB, utils.ToBytesList("a:"+key, value))
|
||||||
Set(testDB, utils.ToBytesList("b:"+key, value))
|
execSet(testDB, utils.ToBytesList("b:"+key, value))
|
||||||
|
|
||||||
result := Keys(testDB, utils.ToBytesList("*"))
|
result := execKeys(testDB, utils.ToBytesList("*"))
|
||||||
asserts.AssertMultiBulkReplySize(t, result, 3)
|
asserts.AssertMultiBulkReplySize(t, result, 3)
|
||||||
result = Keys(testDB, utils.ToBytesList("a:*"))
|
result = execKeys(testDB, utils.ToBytesList("a:*"))
|
||||||
asserts.AssertMultiBulkReplySize(t, result, 1)
|
asserts.AssertMultiBulkReplySize(t, result, 1)
|
||||||
result = Keys(testDB, utils.ToBytesList("?:*"))
|
result = execKeys(testDB, utils.ToBytesList("?:*"))
|
||||||
asserts.AssertMultiBulkReplySize(t, result, 2)
|
asserts.AssertMultiBulkReplySize(t, result, 2)
|
||||||
}
|
}
|
||||||
|
96
list.go
96
list.go
@@ -35,12 +35,9 @@ func (db *DB) getOrInitList(key string) (list *List.LinkedList, isNew bool, errR
|
|||||||
return list, isNew, nil
|
return list, isNew, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// LIndex gets element of list at given list
|
// execLIndex gets element of list at given list
|
||||||
func LIndex(db *DB, args [][]byte) redis.Reply {
|
func execLIndex(db *DB, args [][]byte) redis.Reply {
|
||||||
// parse args
|
// parse args
|
||||||
if len(args) != 2 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'lindex' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
index64, err := strconv.ParseInt(string(args[1]), 10, 64)
|
index64, err := strconv.ParseInt(string(args[1]), 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -73,12 +70,9 @@ func LIndex(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeBulkReply(val)
|
return reply.MakeBulkReply(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LLen gets length of list
|
// execLLen gets length of list
|
||||||
func LLen(db *DB, args [][]byte) redis.Reply {
|
func execLLen(db *DB, args [][]byte) redis.Reply {
|
||||||
// parse args
|
// parse args
|
||||||
if len(args) != 1 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'llen' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
|
|
||||||
db.RLock(key)
|
db.RLock(key)
|
||||||
@@ -96,12 +90,9 @@ func LLen(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeIntReply(size)
|
return reply.MakeIntReply(size)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LPop removes the first element of list, and return it
|
// execLPop removes the first element of list, and return it
|
||||||
func LPop(db *DB, args [][]byte) redis.Reply {
|
func execLPop(db *DB, args [][]byte) redis.Reply {
|
||||||
// parse args
|
// parse args
|
||||||
if len(args) != 1 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'lindex' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
|
|
||||||
// lock
|
// lock
|
||||||
@@ -125,11 +116,8 @@ func LPop(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeBulkReply(val)
|
return reply.MakeBulkReply(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LPush inserts element at head of list
|
// execLPush inserts element at head of list
|
||||||
func LPush(db *DB, args [][]byte) redis.Reply {
|
func execLPush(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) < 2 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'lpush' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
values := args[1:]
|
values := args[1:]
|
||||||
|
|
||||||
@@ -152,11 +140,8 @@ func LPush(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeIntReply(int64(list.Len()))
|
return reply.MakeIntReply(int64(list.Len()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// LPushX inserts element at head of list, only if list exists
|
// execLPushX inserts element at head of list, only if list exists
|
||||||
func LPushX(db *DB, args [][]byte) redis.Reply {
|
func execLPushX(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) < 2 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'lpushx' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
values := args[1:]
|
values := args[1:]
|
||||||
|
|
||||||
@@ -181,12 +166,9 @@ func LPushX(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeIntReply(int64(list.Len()))
|
return reply.MakeIntReply(int64(list.Len()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// LRange gets elements of list in given range
|
// execLRange gets elements of list in given range
|
||||||
func LRange(db *DB, args [][]byte) redis.Reply {
|
func execLRange(db *DB, args [][]byte) redis.Reply {
|
||||||
// parse args
|
// parse args
|
||||||
if len(args) != 3 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'lrange' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
start64, err := strconv.ParseInt(string(args[1]), 10, 64)
|
start64, err := strconv.ParseInt(string(args[1]), 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -244,12 +226,9 @@ func LRange(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeMultiBulkReply(result)
|
return reply.MakeMultiBulkReply(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LRem removes element of list at specified index
|
// execLRem removes element of list at specified index
|
||||||
func LRem(db *DB, args [][]byte) redis.Reply {
|
func execLRem(db *DB, args [][]byte) redis.Reply {
|
||||||
// parse args
|
// parse args
|
||||||
if len(args) != 3 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'lrem' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
count64, err := strconv.ParseInt(string(args[1]), 10, 64)
|
count64, err := strconv.ParseInt(string(args[1]), 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -290,12 +269,9 @@ func LRem(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeIntReply(int64(removed))
|
return reply.MakeIntReply(int64(removed))
|
||||||
}
|
}
|
||||||
|
|
||||||
// LSet puts element at specified index of list
|
// execLSet puts element at specified index of list
|
||||||
func LSet(db *DB, args [][]byte) redis.Reply {
|
func execLSet(db *DB, args [][]byte) redis.Reply {
|
||||||
// parse args
|
// parse args
|
||||||
if len(args) != 3 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'lset' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
index64, err := strconv.ParseInt(string(args[1]), 10, 64)
|
index64, err := strconv.ParseInt(string(args[1]), 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -331,12 +307,9 @@ func LSet(db *DB, args [][]byte) redis.Reply {
|
|||||||
return &reply.OkReply{}
|
return &reply.OkReply{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RPop removes last element of list then return it
|
// execRPop removes last element of list then return it
|
||||||
func RPop(db *DB, args [][]byte) redis.Reply {
|
func execRPop(db *DB, args [][]byte) redis.Reply {
|
||||||
// parse args
|
// parse args
|
||||||
if len(args) != 1 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'rpop' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
|
|
||||||
// lock
|
// lock
|
||||||
@@ -360,11 +333,8 @@ func RPop(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeBulkReply(val)
|
return reply.MakeBulkReply(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RPopLPush pops last element of list-A then insert it to the head of list-B
|
// execRPopLPush pops last element of list-A then insert it to the head of list-B
|
||||||
func RPopLPush(db *DB, args [][]byte) redis.Reply {
|
func execRPopLPush(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) != 2 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'rpoplpush' command")
|
|
||||||
}
|
|
||||||
sourceKey := string(args[0])
|
sourceKey := string(args[0])
|
||||||
destKey := string(args[1])
|
destKey := string(args[1])
|
||||||
|
|
||||||
@@ -399,12 +369,9 @@ func RPopLPush(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeBulkReply(val)
|
return reply.MakeBulkReply(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RPush inserts element at last of list
|
// execRPush inserts element at last of list
|
||||||
func RPush(db *DB, args [][]byte) redis.Reply {
|
func execRPush(db *DB, args [][]byte) redis.Reply {
|
||||||
// parse args
|
// parse args
|
||||||
if len(args) < 2 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'rpush' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
values := args[1:]
|
values := args[1:]
|
||||||
|
|
||||||
@@ -426,8 +393,8 @@ func RPush(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeIntReply(int64(list.Len()))
|
return reply.MakeIntReply(int64(list.Len()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// RPushX inserts element at last of list only if list exists
|
// execRPushX inserts element at last of list only if list exists
|
||||||
func RPushX(db *DB, args [][]byte) redis.Reply {
|
func execRPushX(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) < 2 {
|
if len(args) < 2 {
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'rpush' command")
|
return reply.MakeErrReply("ERR wrong number of arguments for 'rpush' command")
|
||||||
}
|
}
|
||||||
@@ -455,3 +422,18 @@ func RPushX(db *DB, args [][]byte) redis.Reply {
|
|||||||
|
|
||||||
return reply.MakeIntReply(int64(list.Len()))
|
return reply.MakeIntReply(int64(list.Len()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
RegisterCommand("LPush", execLPush, nil, -3)
|
||||||
|
RegisterCommand("LPushX", execLPushX, nil, -3)
|
||||||
|
RegisterCommand("RPush", execRPush, nil, -3)
|
||||||
|
RegisterCommand("RPushX", execRPushX, nil, -3)
|
||||||
|
RegisterCommand("LPop", execLPop, nil, 2)
|
||||||
|
RegisterCommand("RPop", execRPop, nil, 2)
|
||||||
|
RegisterCommand("RPopLPush", execRPopLPush, nil, 4)
|
||||||
|
RegisterCommand("LRem", execLRem, nil, 4)
|
||||||
|
RegisterCommand("LLen", execLLen, nil, 2)
|
||||||
|
RegisterCommand("LIndex", execLIndex, nil, 3)
|
||||||
|
RegisterCommand("LSet", execLSet, nil, 4)
|
||||||
|
RegisterCommand("LRange", execLRange, nil, 4)
|
||||||
|
}
|
||||||
|
130
list_test.go
130
list_test.go
@@ -10,7 +10,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestPush(t *testing.T) {
|
func TestPush(t *testing.T) {
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
size := 100
|
size := 100
|
||||||
|
|
||||||
// rpush single
|
// rpush single
|
||||||
@@ -19,17 +19,17 @@ func TestPush(t *testing.T) {
|
|||||||
for i := 0; i < size; i++ {
|
for i := 0; i < size; i++ {
|
||||||
value := utils2.RandString(10)
|
value := utils2.RandString(10)
|
||||||
values[i] = []byte(value)
|
values[i] = []byte(value)
|
||||||
result := RPush(testDB, utils2.ToBytesList(key, value))
|
result := execRPush(testDB, utils2.ToBytesList(key, value))
|
||||||
if intResult, _ := result.(*reply.IntReply); intResult.Code != int64(i+1) {
|
if intResult, _ := result.(*reply.IntReply); intResult.Code != int64(i+1) {
|
||||||
t.Error(fmt.Sprintf("expected %d, actually %d", i+1, intResult.Code))
|
t.Error(fmt.Sprintf("expected %d, actually %d", i+1, intResult.Code))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
actual := LRange(testDB, utils2.ToBytesList(key, "0", "-1"))
|
actual := execLRange(testDB, utils2.ToBytesList(key, "0", "-1"))
|
||||||
expected := reply.MakeMultiBulkReply(values)
|
expected := reply.MakeMultiBulkReply(values)
|
||||||
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
|
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
|
||||||
t.Error("push error")
|
t.Error("push error")
|
||||||
}
|
}
|
||||||
Del(testDB, utils2.ToBytesList(key))
|
testDB.Remove(key)
|
||||||
|
|
||||||
// rpush multi
|
// rpush multi
|
||||||
key = utils2.RandString(10)
|
key = utils2.RandString(10)
|
||||||
@@ -39,16 +39,16 @@ func TestPush(t *testing.T) {
|
|||||||
value := utils2.RandString(10)
|
value := utils2.RandString(10)
|
||||||
values[i+1] = []byte(value)
|
values[i+1] = []byte(value)
|
||||||
}
|
}
|
||||||
result := RPush(testDB, values)
|
result := execRPush(testDB, values)
|
||||||
if intResult, _ := result.(*reply.IntReply); intResult.Code != int64(size) {
|
if intResult, _ := result.(*reply.IntReply); intResult.Code != int64(size) {
|
||||||
t.Error(fmt.Sprintf("expected %d, actually %d", size, intResult.Code))
|
t.Error(fmt.Sprintf("expected %d, actually %d", size, intResult.Code))
|
||||||
}
|
}
|
||||||
actual = LRange(testDB, utils2.ToBytesList(key, "0", "-1"))
|
actual = execLRange(testDB, utils2.ToBytesList(key, "0", "-1"))
|
||||||
expected = reply.MakeMultiBulkReply(values[1:])
|
expected = reply.MakeMultiBulkReply(values[1:])
|
||||||
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
|
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
|
||||||
t.Error("push error")
|
t.Error("push error")
|
||||||
}
|
}
|
||||||
Del(testDB, utils2.ToBytesList(key))
|
testDB.Remove(key)
|
||||||
|
|
||||||
// left push single
|
// left push single
|
||||||
key = utils2.RandString(10)
|
key = utils2.RandString(10)
|
||||||
@@ -56,17 +56,17 @@ func TestPush(t *testing.T) {
|
|||||||
for i := 0; i < size; i++ {
|
for i := 0; i < size; i++ {
|
||||||
value := utils2.RandString(10)
|
value := utils2.RandString(10)
|
||||||
values[size-i-1] = []byte(value)
|
values[size-i-1] = []byte(value)
|
||||||
result = LPush(testDB, utils2.ToBytesList(key, value))
|
result = execLPush(testDB, utils2.ToBytesList(key, value))
|
||||||
if intResult, _ := result.(*reply.IntReply); intResult.Code != int64(i+1) {
|
if intResult, _ := result.(*reply.IntReply); intResult.Code != int64(i+1) {
|
||||||
t.Error(fmt.Sprintf("expected %d, actually %d", i+1, intResult.Code))
|
t.Error(fmt.Sprintf("expected %d, actually %d", i+1, intResult.Code))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
actual = LRange(testDB, utils2.ToBytesList(key, "0", "-1"))
|
actual = execLRange(testDB, utils2.ToBytesList(key, "0", "-1"))
|
||||||
expected = reply.MakeMultiBulkReply(values)
|
expected = reply.MakeMultiBulkReply(values)
|
||||||
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
|
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
|
||||||
t.Error("push error")
|
t.Error("push error")
|
||||||
}
|
}
|
||||||
Del(testDB, utils2.ToBytesList(key))
|
testDB.Remove(key)
|
||||||
|
|
||||||
// left push multi
|
// left push multi
|
||||||
key = utils2.RandString(10)
|
key = utils2.RandString(10)
|
||||||
@@ -78,33 +78,33 @@ func TestPush(t *testing.T) {
|
|||||||
values[i+1] = []byte(value)
|
values[i+1] = []byte(value)
|
||||||
expectedValues[size-i-1] = []byte(value)
|
expectedValues[size-i-1] = []byte(value)
|
||||||
}
|
}
|
||||||
result = LPush(testDB, values)
|
result = execLPush(testDB, values)
|
||||||
if intResult, _ := result.(*reply.IntReply); intResult.Code != int64(size) {
|
if intResult, _ := result.(*reply.IntReply); intResult.Code != int64(size) {
|
||||||
t.Error(fmt.Sprintf("expected %d, actually %d", size, intResult.Code))
|
t.Error(fmt.Sprintf("expected %d, actually %d", size, intResult.Code))
|
||||||
}
|
}
|
||||||
actual = LRange(testDB, utils2.ToBytesList(key, "0", "-1"))
|
actual = execLRange(testDB, utils2.ToBytesList(key, "0", "-1"))
|
||||||
expected = reply.MakeMultiBulkReply(expectedValues)
|
expected = reply.MakeMultiBulkReply(expectedValues)
|
||||||
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
|
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
|
||||||
t.Error("push error")
|
t.Error("push error")
|
||||||
}
|
}
|
||||||
Del(testDB, utils2.ToBytesList(key))
|
testDB.Remove(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLRange(t *testing.T) {
|
func TestLRange(t *testing.T) {
|
||||||
// prepare list
|
// prepare list
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
size := 100
|
size := 100
|
||||||
key := utils2.RandString(10)
|
key := utils2.RandString(10)
|
||||||
values := make([][]byte, size)
|
values := make([][]byte, size)
|
||||||
for i := 0; i < size; i++ {
|
for i := 0; i < size; i++ {
|
||||||
value := utils2.RandString(10)
|
value := utils2.RandString(10)
|
||||||
RPush(testDB, utils2.ToBytesList(key, value))
|
execRPush(testDB, utils2.ToBytesList(key, value))
|
||||||
values[i] = []byte(value)
|
values[i] = []byte(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
start := "0"
|
start := "0"
|
||||||
end := "9"
|
end := "9"
|
||||||
actual := LRange(testDB, utils2.ToBytesList(key, start, end))
|
actual := execLRange(testDB, utils2.ToBytesList(key, start, end))
|
||||||
expected := reply.MakeMultiBulkReply(values[0:10])
|
expected := reply.MakeMultiBulkReply(values[0:10])
|
||||||
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
|
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
|
||||||
t.Error(fmt.Sprintf("range error [%s, %s]", start, end))
|
t.Error(fmt.Sprintf("range error [%s, %s]", start, end))
|
||||||
@@ -112,7 +112,7 @@ func TestLRange(t *testing.T) {
|
|||||||
|
|
||||||
start = "0"
|
start = "0"
|
||||||
end = "200"
|
end = "200"
|
||||||
actual = LRange(testDB, utils2.ToBytesList(key, start, end))
|
actual = execLRange(testDB, utils2.ToBytesList(key, start, end))
|
||||||
expected = reply.MakeMultiBulkReply(values)
|
expected = reply.MakeMultiBulkReply(values)
|
||||||
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
|
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
|
||||||
t.Error(fmt.Sprintf("range error [%s, %s]", start, end))
|
t.Error(fmt.Sprintf("range error [%s, %s]", start, end))
|
||||||
@@ -120,7 +120,7 @@ func TestLRange(t *testing.T) {
|
|||||||
|
|
||||||
start = "0"
|
start = "0"
|
||||||
end = "-10"
|
end = "-10"
|
||||||
actual = LRange(testDB, utils2.ToBytesList(key, start, end))
|
actual = execLRange(testDB, utils2.ToBytesList(key, start, end))
|
||||||
expected = reply.MakeMultiBulkReply(values[0 : size-10+1])
|
expected = reply.MakeMultiBulkReply(values[0 : size-10+1])
|
||||||
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
|
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
|
||||||
t.Error(fmt.Sprintf("range error [%s, %s]", start, end))
|
t.Error(fmt.Sprintf("range error [%s, %s]", start, end))
|
||||||
@@ -128,7 +128,7 @@ func TestLRange(t *testing.T) {
|
|||||||
|
|
||||||
start = "0"
|
start = "0"
|
||||||
end = "-200"
|
end = "-200"
|
||||||
actual = LRange(testDB, utils2.ToBytesList(key, start, end))
|
actual = execLRange(testDB, utils2.ToBytesList(key, start, end))
|
||||||
expected = reply.MakeMultiBulkReply(values[0:0])
|
expected = reply.MakeMultiBulkReply(values[0:0])
|
||||||
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
|
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
|
||||||
t.Error(fmt.Sprintf("range error [%s, %s]", start, end))
|
t.Error(fmt.Sprintf("range error [%s, %s]", start, end))
|
||||||
@@ -136,7 +136,7 @@ func TestLRange(t *testing.T) {
|
|||||||
|
|
||||||
start = "-10"
|
start = "-10"
|
||||||
end = "-1"
|
end = "-1"
|
||||||
actual = LRange(testDB, utils2.ToBytesList(key, start, end))
|
actual = execLRange(testDB, utils2.ToBytesList(key, start, end))
|
||||||
expected = reply.MakeMultiBulkReply(values[90:])
|
expected = reply.MakeMultiBulkReply(values[90:])
|
||||||
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
|
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
|
||||||
t.Error(fmt.Sprintf("range error [%s, %s]", start, end))
|
t.Error(fmt.Sprintf("range error [%s, %s]", start, end))
|
||||||
@@ -145,23 +145,23 @@ func TestLRange(t *testing.T) {
|
|||||||
|
|
||||||
func TestLIndex(t *testing.T) {
|
func TestLIndex(t *testing.T) {
|
||||||
// prepare list
|
// prepare list
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
size := 100
|
size := 100
|
||||||
key := utils2.RandString(10)
|
key := utils2.RandString(10)
|
||||||
values := make([][]byte, size)
|
values := make([][]byte, size)
|
||||||
for i := 0; i < size; i++ {
|
for i := 0; i < size; i++ {
|
||||||
value := utils2.RandString(10)
|
value := utils2.RandString(10)
|
||||||
RPush(testDB, utils2.ToBytesList(key, value))
|
execRPush(testDB, utils2.ToBytesList(key, value))
|
||||||
values[i] = []byte(value)
|
values[i] = []byte(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
result := LLen(testDB, utils2.ToBytesList(key))
|
result := execLLen(testDB, utils2.ToBytesList(key))
|
||||||
if intResult, _ := result.(*reply.IntReply); intResult.Code != int64(size) {
|
if intResult, _ := result.(*reply.IntReply); intResult.Code != int64(size) {
|
||||||
t.Error(fmt.Sprintf("expected %d, actually %d", size, intResult.Code))
|
t.Error(fmt.Sprintf("expected %d, actually %d", size, intResult.Code))
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < size; i++ {
|
for i := 0; i < size; i++ {
|
||||||
result = LIndex(testDB, utils2.ToBytesList(key, strconv.Itoa(i)))
|
result = execLIndex(testDB, utils2.ToBytesList(key, strconv.Itoa(i)))
|
||||||
expected := reply.MakeBulkReply(values[i])
|
expected := reply.MakeBulkReply(values[i])
|
||||||
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
|
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
|
||||||
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
|
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
|
||||||
@@ -169,7 +169,7 @@ func TestLIndex(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i := 1; i <= size; i++ {
|
for i := 1; i <= size; i++ {
|
||||||
result = LIndex(testDB, utils2.ToBytesList(key, strconv.Itoa(-i)))
|
result = execLIndex(testDB, utils2.ToBytesList(key, strconv.Itoa(-i)))
|
||||||
expected := reply.MakeBulkReply(values[size-i])
|
expected := reply.MakeBulkReply(values[size-i])
|
||||||
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
|
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
|
||||||
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
|
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
|
||||||
@@ -179,55 +179,55 @@ func TestLIndex(t *testing.T) {
|
|||||||
|
|
||||||
func TestLRem(t *testing.T) {
|
func TestLRem(t *testing.T) {
|
||||||
// prepare list
|
// prepare list
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
key := utils2.RandString(10)
|
key := utils2.RandString(10)
|
||||||
values := []string{key, "a", "b", "a", "a", "c", "a", "a"}
|
values := []string{key, "a", "b", "a", "a", "c", "a", "a"}
|
||||||
RPush(testDB, utils2.ToBytesList(values...))
|
execRPush(testDB, utils2.ToBytesList(values...))
|
||||||
|
|
||||||
result := LRem(testDB, utils2.ToBytesList(key, "1", "a"))
|
result := execLRem(testDB, utils2.ToBytesList(key, "1", "a"))
|
||||||
if intResult, _ := result.(*reply.IntReply); intResult.Code != 1 {
|
if intResult, _ := result.(*reply.IntReply); intResult.Code != 1 {
|
||||||
t.Error(fmt.Sprintf("expected %d, actually %d", 1, intResult.Code))
|
t.Error(fmt.Sprintf("expected %d, actually %d", 1, intResult.Code))
|
||||||
}
|
}
|
||||||
result = LLen(testDB, utils2.ToBytesList(key))
|
result = execLLen(testDB, utils2.ToBytesList(key))
|
||||||
if intResult, _ := result.(*reply.IntReply); intResult.Code != 6 {
|
if intResult, _ := result.(*reply.IntReply); intResult.Code != 6 {
|
||||||
t.Error(fmt.Sprintf("expected %d, actually %d", 6, intResult.Code))
|
t.Error(fmt.Sprintf("expected %d, actually %d", 6, intResult.Code))
|
||||||
}
|
}
|
||||||
|
|
||||||
result = LRem(testDB, utils2.ToBytesList(key, "-2", "a"))
|
result = execLRem(testDB, utils2.ToBytesList(key, "-2", "a"))
|
||||||
if intResult, _ := result.(*reply.IntReply); intResult.Code != 2 {
|
if intResult, _ := result.(*reply.IntReply); intResult.Code != 2 {
|
||||||
t.Error(fmt.Sprintf("expected %d, actually %d", 2, intResult.Code))
|
t.Error(fmt.Sprintf("expected %d, actually %d", 2, intResult.Code))
|
||||||
}
|
}
|
||||||
result = LLen(testDB, utils2.ToBytesList(key))
|
result = execLLen(testDB, utils2.ToBytesList(key))
|
||||||
if intResult, _ := result.(*reply.IntReply); intResult.Code != 4 {
|
if intResult, _ := result.(*reply.IntReply); intResult.Code != 4 {
|
||||||
t.Error(fmt.Sprintf("expected %d, actually %d", 4, intResult.Code))
|
t.Error(fmt.Sprintf("expected %d, actually %d", 4, intResult.Code))
|
||||||
}
|
}
|
||||||
|
|
||||||
result = LRem(testDB, utils2.ToBytesList(key, "0", "a"))
|
result = execLRem(testDB, utils2.ToBytesList(key, "0", "a"))
|
||||||
if intResult, _ := result.(*reply.IntReply); intResult.Code != 2 {
|
if intResult, _ := result.(*reply.IntReply); intResult.Code != 2 {
|
||||||
t.Error(fmt.Sprintf("expected %d, actually %d", 2, intResult.Code))
|
t.Error(fmt.Sprintf("expected %d, actually %d", 2, intResult.Code))
|
||||||
}
|
}
|
||||||
result = LLen(testDB, utils2.ToBytesList(key))
|
result = execLLen(testDB, utils2.ToBytesList(key))
|
||||||
if intResult, _ := result.(*reply.IntReply); intResult.Code != 2 {
|
if intResult, _ := result.(*reply.IntReply); intResult.Code != 2 {
|
||||||
t.Error(fmt.Sprintf("expected %d, actually %d", 2, intResult.Code))
|
t.Error(fmt.Sprintf("expected %d, actually %d", 2, intResult.Code))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLSet(t *testing.T) {
|
func TestLSet(t *testing.T) {
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
key := utils2.RandString(10)
|
key := utils2.RandString(10)
|
||||||
values := []string{key, "a", "b", "c", "d", "e", "f"}
|
values := []string{key, "a", "b", "c", "d", "e", "f"}
|
||||||
RPush(testDB, utils2.ToBytesList(values...))
|
execRPush(testDB, utils2.ToBytesList(values...))
|
||||||
|
|
||||||
// test positive index
|
// test positive index
|
||||||
size := len(values) - 1
|
size := len(values) - 1
|
||||||
for i := 0; i < size; i++ {
|
for i := 0; i < size; i++ {
|
||||||
indexStr := strconv.Itoa(i)
|
indexStr := strconv.Itoa(i)
|
||||||
value := utils2.RandString(10)
|
value := utils2.RandString(10)
|
||||||
result := LSet(testDB, utils2.ToBytesList(key, indexStr, value))
|
result := execLSet(testDB, utils2.ToBytesList(key, indexStr, value))
|
||||||
if _, ok := result.(*reply.OkReply); !ok {
|
if _, ok := result.(*reply.OkReply); !ok {
|
||||||
t.Error(fmt.Sprintf("expected OK, actually %s", string(result.ToBytes())))
|
t.Error(fmt.Sprintf("expected OK, actually %s", string(result.ToBytes())))
|
||||||
}
|
}
|
||||||
result = LIndex(testDB, utils2.ToBytesList(key, indexStr))
|
result = execLIndex(testDB, utils2.ToBytesList(key, indexStr))
|
||||||
expected := reply.MakeBulkReply([]byte(value))
|
expected := reply.MakeBulkReply([]byte(value))
|
||||||
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
|
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
|
||||||
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
|
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
|
||||||
@@ -236,11 +236,11 @@ func TestLSet(t *testing.T) {
|
|||||||
// test negative index
|
// test negative index
|
||||||
for i := 1; i <= size; i++ {
|
for i := 1; i <= size; i++ {
|
||||||
value := utils2.RandString(10)
|
value := utils2.RandString(10)
|
||||||
result := LSet(testDB, utils2.ToBytesList(key, strconv.Itoa(-i), value))
|
result := execLSet(testDB, utils2.ToBytesList(key, strconv.Itoa(-i), value))
|
||||||
if _, ok := result.(*reply.OkReply); !ok {
|
if _, ok := result.(*reply.OkReply); !ok {
|
||||||
t.Error(fmt.Sprintf("expected OK, actually %s", string(result.ToBytes())))
|
t.Error(fmt.Sprintf("expected OK, actually %s", string(result.ToBytes())))
|
||||||
}
|
}
|
||||||
result = LIndex(testDB, utils2.ToBytesList(key, strconv.Itoa(len(values)-i-1)))
|
result = execLIndex(testDB, utils2.ToBytesList(key, strconv.Itoa(len(values)-i-1)))
|
||||||
expected := reply.MakeBulkReply([]byte(value))
|
expected := reply.MakeBulkReply([]byte(value))
|
||||||
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
|
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
|
||||||
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
|
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
|
||||||
@@ -249,16 +249,16 @@ func TestLSet(t *testing.T) {
|
|||||||
|
|
||||||
// test illegal index
|
// test illegal index
|
||||||
value := utils2.RandString(10)
|
value := utils2.RandString(10)
|
||||||
result := LSet(testDB, utils2.ToBytesList(key, strconv.Itoa(-len(values)-1), value))
|
result := execLSet(testDB, utils2.ToBytesList(key, strconv.Itoa(-len(values)-1), value))
|
||||||
expected := reply.MakeErrReply("ERR index out of range")
|
expected := reply.MakeErrReply("ERR index out of range")
|
||||||
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
|
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
|
||||||
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
|
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
|
||||||
}
|
}
|
||||||
result = LSet(testDB, utils2.ToBytesList(key, strconv.Itoa(len(values)), value))
|
result = execLSet(testDB, utils2.ToBytesList(key, strconv.Itoa(len(values)), value))
|
||||||
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
|
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
|
||||||
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
|
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
|
||||||
}
|
}
|
||||||
result = LSet(testDB, utils2.ToBytesList(key, "a", value))
|
result = execLSet(testDB, utils2.ToBytesList(key, "a", value))
|
||||||
expected = reply.MakeErrReply("ERR value is not an integer or out of range")
|
expected = reply.MakeErrReply("ERR value is not an integer or out of range")
|
||||||
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
|
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
|
||||||
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
|
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
|
||||||
@@ -266,20 +266,20 @@ func TestLSet(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestLPop(t *testing.T) {
|
func TestLPop(t *testing.T) {
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
key := utils2.RandString(10)
|
key := utils2.RandString(10)
|
||||||
values := []string{key, "a", "b", "c", "d", "e", "f"}
|
values := []string{key, "a", "b", "c", "d", "e", "f"}
|
||||||
RPush(testDB, utils2.ToBytesList(values...))
|
execRPush(testDB, utils2.ToBytesList(values...))
|
||||||
size := len(values) - 1
|
size := len(values) - 1
|
||||||
|
|
||||||
for i := 0; i < size; i++ {
|
for i := 0; i < size; i++ {
|
||||||
result := LPop(testDB, utils2.ToBytesList(key))
|
result := execLPop(testDB, utils2.ToBytesList(key))
|
||||||
expected := reply.MakeBulkReply([]byte(values[i+1]))
|
expected := reply.MakeBulkReply([]byte(values[i+1]))
|
||||||
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
|
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
|
||||||
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
|
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result := RPop(testDB, utils2.ToBytesList(key))
|
result := execRPop(testDB, utils2.ToBytesList(key))
|
||||||
expected := &reply.NullBulkReply{}
|
expected := &reply.NullBulkReply{}
|
||||||
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
|
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
|
||||||
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
|
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
|
||||||
@@ -287,20 +287,20 @@ func TestLPop(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestRPop(t *testing.T) {
|
func TestRPop(t *testing.T) {
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
key := utils2.RandString(10)
|
key := utils2.RandString(10)
|
||||||
values := []string{key, "a", "b", "c", "d", "e", "f"}
|
values := []string{key, "a", "b", "c", "d", "e", "f"}
|
||||||
RPush(testDB, utils2.ToBytesList(values...))
|
execRPush(testDB, utils2.ToBytesList(values...))
|
||||||
size := len(values) - 1
|
size := len(values) - 1
|
||||||
|
|
||||||
for i := 0; i < size; i++ {
|
for i := 0; i < size; i++ {
|
||||||
result := RPop(testDB, utils2.ToBytesList(key))
|
result := execRPop(testDB, utils2.ToBytesList(key))
|
||||||
expected := reply.MakeBulkReply([]byte(values[len(values)-i-1]))
|
expected := reply.MakeBulkReply([]byte(values[len(values)-i-1]))
|
||||||
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
|
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
|
||||||
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
|
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result := RPop(testDB, utils2.ToBytesList(key))
|
result := execRPop(testDB, utils2.ToBytesList(key))
|
||||||
expected := &reply.NullBulkReply{}
|
expected := &reply.NullBulkReply{}
|
||||||
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
|
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
|
||||||
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
|
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
|
||||||
@@ -308,25 +308,25 @@ func TestRPop(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestRPopLPush(t *testing.T) {
|
func TestRPopLPush(t *testing.T) {
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
key1 := utils2.RandString(10)
|
key1 := utils2.RandString(10)
|
||||||
key2 := utils2.RandString(10)
|
key2 := utils2.RandString(10)
|
||||||
values := []string{key1, "a", "b", "c", "d", "e", "f"}
|
values := []string{key1, "a", "b", "c", "d", "e", "f"}
|
||||||
RPush(testDB, utils2.ToBytesList(values...))
|
execRPush(testDB, utils2.ToBytesList(values...))
|
||||||
size := len(values) - 1
|
size := len(values) - 1
|
||||||
|
|
||||||
for i := 0; i < size; i++ {
|
for i := 0; i < size; i++ {
|
||||||
result := RPopLPush(testDB, utils2.ToBytesList(key1, key2))
|
result := execRPopLPush(testDB, utils2.ToBytesList(key1, key2))
|
||||||
expected := reply.MakeBulkReply([]byte(values[len(values)-i-1]))
|
expected := reply.MakeBulkReply([]byte(values[len(values)-i-1]))
|
||||||
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
|
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
|
||||||
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
|
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
|
||||||
}
|
}
|
||||||
result = LIndex(testDB, utils2.ToBytesList(key2, "0"))
|
result = execLIndex(testDB, utils2.ToBytesList(key2, "0"))
|
||||||
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
|
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
|
||||||
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
|
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result := RPop(testDB, utils2.ToBytesList(key1))
|
result := execRPop(testDB, utils2.ToBytesList(key1))
|
||||||
expected := &reply.NullBulkReply{}
|
expected := &reply.NullBulkReply{}
|
||||||
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
|
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
|
||||||
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
|
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
|
||||||
@@ -334,23 +334,23 @@ func TestRPopLPush(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestRPushX(t *testing.T) {
|
func TestRPushX(t *testing.T) {
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
key := utils2.RandString(10)
|
key := utils2.RandString(10)
|
||||||
result := RPushX(testDB, utils2.ToBytesList(key, "1"))
|
result := execRPushX(testDB, utils2.ToBytesList(key, "1"))
|
||||||
expected := reply.MakeIntReply(int64(0))
|
expected := reply.MakeIntReply(int64(0))
|
||||||
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
|
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
|
||||||
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
|
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
|
||||||
}
|
}
|
||||||
|
|
||||||
RPush(testDB, utils2.ToBytesList(key, "1"))
|
execRPush(testDB, utils2.ToBytesList(key, "1"))
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
value := utils2.RandString(10)
|
value := utils2.RandString(10)
|
||||||
result := RPushX(testDB, utils2.ToBytesList(key, value))
|
result := execRPushX(testDB, utils2.ToBytesList(key, value))
|
||||||
expected := reply.MakeIntReply(int64(i + 2))
|
expected := reply.MakeIntReply(int64(i + 2))
|
||||||
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
|
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
|
||||||
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
|
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
|
||||||
}
|
}
|
||||||
result = LIndex(testDB, utils2.ToBytesList(key, "-1"))
|
result = execLIndex(testDB, utils2.ToBytesList(key, "-1"))
|
||||||
expected2 := reply.MakeBulkReply([]byte(value))
|
expected2 := reply.MakeBulkReply([]byte(value))
|
||||||
if !utils.BytesEquals(result.ToBytes(), expected2.ToBytes()) {
|
if !utils.BytesEquals(result.ToBytes(), expected2.ToBytes()) {
|
||||||
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected2.ToBytes()), string(result.ToBytes())))
|
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected2.ToBytes()), string(result.ToBytes())))
|
||||||
@@ -359,23 +359,23 @@ func TestRPushX(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestLPushX(t *testing.T) {
|
func TestLPushX(t *testing.T) {
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
key := utils2.RandString(10)
|
key := utils2.RandString(10)
|
||||||
result := RPushX(testDB, utils2.ToBytesList(key, "1"))
|
result := execRPushX(testDB, utils2.ToBytesList(key, "1"))
|
||||||
expected := reply.MakeIntReply(int64(0))
|
expected := reply.MakeIntReply(int64(0))
|
||||||
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
|
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
|
||||||
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
|
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
|
||||||
}
|
}
|
||||||
|
|
||||||
LPush(testDB, utils2.ToBytesList(key, "1"))
|
execLPush(testDB, utils2.ToBytesList(key, "1"))
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
value := utils2.RandString(10)
|
value := utils2.RandString(10)
|
||||||
result := LPushX(testDB, utils2.ToBytesList(key, value))
|
result := execLPushX(testDB, utils2.ToBytesList(key, value))
|
||||||
expected := reply.MakeIntReply(int64(i + 2))
|
expected := reply.MakeIntReply(int64(i + 2))
|
||||||
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
|
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
|
||||||
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
|
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
|
||||||
}
|
}
|
||||||
result = LIndex(testDB, utils2.ToBytesList(key, "0"))
|
result = execLIndex(testDB, utils2.ToBytesList(key, "0"))
|
||||||
expected2 := reply.MakeBulkReply([]byte(value))
|
expected2 := reply.MakeBulkReply([]byte(value))
|
||||||
if !utils.BytesEquals(result.ToBytes(), expected2.ToBytes()) {
|
if !utils.BytesEquals(result.ToBytes(), expected2.ToBytes()) {
|
||||||
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected2.ToBytes()), string(result.ToBytes())))
|
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected2.ToBytes()), string(result.ToBytes())))
|
||||||
|
5
prepare.go
Normal file
5
prepare.go
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
package godis
|
||||||
|
|
||||||
|
func noPre(args [][]byte) ([]string, [][][]byte) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
@@ -28,10 +28,23 @@ func (r *ArgNumErrReply) Error() string {
|
|||||||
return "ERR wrong number of arguments for '" + r.Cmd + "' command"
|
return "ERR wrong number of arguments for '" + r.Cmd + "' command"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MakeArgNumErrReply represents wrong number of arguments for command
|
||||||
|
func MakeArgNumErrReply(cmd string) *ArgNumErrReply {
|
||||||
|
return &ArgNumErrReply{
|
||||||
|
Cmd: cmd,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// SyntaxErrReply represents meeting unexpected arguments
|
// SyntaxErrReply represents meeting unexpected arguments
|
||||||
type SyntaxErrReply struct{}
|
type SyntaxErrReply struct{}
|
||||||
|
|
||||||
var syntaxErrBytes = []byte("-Err syntax error\r\n")
|
var syntaxErrBytes = []byte("-Err syntax error\r\n")
|
||||||
|
var theSyntaxErrReply = &SyntaxErrReply{}
|
||||||
|
|
||||||
|
// MakeSyntaxErrReply creates syntax error
|
||||||
|
func MakeSyntaxErrReply() *SyntaxErrReply {
|
||||||
|
return theSyntaxErrReply
|
||||||
|
}
|
||||||
|
|
||||||
// ToBytes marshals redis.Reply
|
// ToBytes marshals redis.Reply
|
||||||
func (r *SyntaxErrReply) ToBytes() []byte {
|
func (r *SyntaxErrReply) ToBytes() []byte {
|
||||||
|
115
router.go
115
router.go
@@ -1,102 +1,23 @@
|
|||||||
package godis
|
package godis
|
||||||
|
|
||||||
func makeRouter() map[string]cmdFunc {
|
import "strings"
|
||||||
routerMap := make(map[string]cmdFunc)
|
|
||||||
routerMap["ping"] = Ping
|
|
||||||
|
|
||||||
routerMap["del"] = Del
|
var cmdTable = make(map[string]*command)
|
||||||
routerMap["expire"] = Expire
|
|
||||||
routerMap["expireat"] = ExpireAt
|
|
||||||
routerMap["pexpire"] = PExpire
|
|
||||||
routerMap["pexpireat"] = PExpireAt
|
|
||||||
routerMap["ttl"] = TTL
|
|
||||||
routerMap["pttl"] = PTTL
|
|
||||||
routerMap["persist"] = Persist
|
|
||||||
routerMap["exists"] = Exists
|
|
||||||
routerMap["type"] = Type
|
|
||||||
routerMap["rename"] = Rename
|
|
||||||
routerMap["renamenx"] = RenameNx
|
|
||||||
|
|
||||||
routerMap["set"] = Set
|
type command struct {
|
||||||
routerMap["setnx"] = SetNX
|
executor ExecFunc
|
||||||
routerMap["setex"] = SetEX
|
prepare PreFunc // return related keys and rollback command
|
||||||
routerMap["psetex"] = PSetEX
|
arity int // allow number of args, arity < 0 means len(args) >= -arity
|
||||||
routerMap["mset"] = MSet
|
}
|
||||||
routerMap["mget"] = MGet
|
|
||||||
routerMap["msetnx"] = MSetNX
|
// RegisterCommand registers a new command
|
||||||
routerMap["get"] = Get
|
// arity means allowed number of cmdArgs, arity < 0 means len(args) >= -arity.
|
||||||
routerMap["getset"] = GetSet
|
// for example: the arity of `get` is 2, `mget` is -2
|
||||||
routerMap["incr"] = Incr
|
func RegisterCommand(name string, executor ExecFunc, prepare PreFunc, arity int) {
|
||||||
routerMap["incrby"] = IncrBy
|
name = strings.ToLower(name)
|
||||||
routerMap["incrbyfloat"] = IncrByFloat
|
cmdTable[name] = &command{
|
||||||
routerMap["decr"] = Decr
|
executor: executor,
|
||||||
routerMap["decrby"] = DecrBy
|
prepare: prepare,
|
||||||
|
arity: arity,
|
||||||
routerMap["lpush"] = LPush
|
}
|
||||||
routerMap["lpushx"] = LPushX
|
|
||||||
routerMap["rpush"] = RPush
|
|
||||||
routerMap["rpushx"] = RPushX
|
|
||||||
routerMap["lpop"] = LPop
|
|
||||||
routerMap["rpop"] = RPop
|
|
||||||
routerMap["rpoplpush"] = RPopLPush
|
|
||||||
routerMap["lrem"] = LRem
|
|
||||||
routerMap["llen"] = LLen
|
|
||||||
routerMap["lindex"] = LIndex
|
|
||||||
routerMap["lset"] = LSet
|
|
||||||
routerMap["lrange"] = LRange
|
|
||||||
|
|
||||||
routerMap["hset"] = HSet
|
|
||||||
routerMap["hsetnx"] = HSetNX
|
|
||||||
routerMap["hget"] = HGet
|
|
||||||
routerMap["hexists"] = HExists
|
|
||||||
routerMap["hdel"] = HDel
|
|
||||||
routerMap["hlen"] = HLen
|
|
||||||
routerMap["hmget"] = HMGet
|
|
||||||
routerMap["hmset"] = HMSet
|
|
||||||
routerMap["hkeys"] = HKeys
|
|
||||||
routerMap["hvals"] = HVals
|
|
||||||
routerMap["hgetall"] = HGetAll
|
|
||||||
routerMap["hincrby"] = HIncrBy
|
|
||||||
routerMap["hincrbyfloat"] = HIncrByFloat
|
|
||||||
|
|
||||||
routerMap["sadd"] = SAdd
|
|
||||||
routerMap["sismember"] = SIsMember
|
|
||||||
routerMap["srem"] = SRem
|
|
||||||
routerMap["scard"] = SCard
|
|
||||||
routerMap["smembers"] = SMembers
|
|
||||||
routerMap["sinter"] = SInter
|
|
||||||
routerMap["sinterstore"] = SInterStore
|
|
||||||
routerMap["sunion"] = SUnion
|
|
||||||
routerMap["sunionstore"] = SUnionStore
|
|
||||||
routerMap["sdiff"] = SDiff
|
|
||||||
routerMap["sdiffstore"] = SDiffStore
|
|
||||||
routerMap["srandmember"] = SRandMember
|
|
||||||
|
|
||||||
routerMap["zadd"] = ZAdd
|
|
||||||
routerMap["zscore"] = ZScore
|
|
||||||
routerMap["zincrby"] = ZIncrBy
|
|
||||||
routerMap["zrank"] = ZRank
|
|
||||||
routerMap["zcount"] = ZCount
|
|
||||||
routerMap["zrevrank"] = ZRevRank
|
|
||||||
routerMap["zcard"] = ZCard
|
|
||||||
routerMap["zrange"] = ZRange
|
|
||||||
routerMap["zrevrange"] = ZRevRange
|
|
||||||
routerMap["zrangebyscore"] = ZRangeByScore
|
|
||||||
routerMap["zrevrangebyscore"] = ZRevRangeByScore
|
|
||||||
routerMap["zrem"] = ZRem
|
|
||||||
routerMap["zremrangebyscore"] = ZRemRangeByScore
|
|
||||||
routerMap["zremrangebyrank"] = ZRemRangeByRank
|
|
||||||
|
|
||||||
routerMap["geoadd"] = GeoAdd
|
|
||||||
routerMap["geopos"] = GeoPos
|
|
||||||
routerMap["geodist"] = GeoDist
|
|
||||||
routerMap["geohash"] = GeoHash
|
|
||||||
routerMap["georadius"] = GeoRadius
|
|
||||||
routerMap["georadiusbymember"] = GeoRadiusByMember
|
|
||||||
|
|
||||||
routerMap["flushdb"] = FlushDB
|
|
||||||
routerMap["flushall"] = FlushAll
|
|
||||||
routerMap["keys"] = Keys
|
|
||||||
|
|
||||||
return routerMap
|
|
||||||
}
|
}
|
||||||
|
@@ -39,3 +39,7 @@ func isAuthenticated(c redis.Connection) bool {
|
|||||||
}
|
}
|
||||||
return c.GetPassword() == config.Properties.RequirePass
|
return c.GetPassword() == config.Properties.RequirePass
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
RegisterCommand("ping", Ping, nil, -1)
|
||||||
|
}
|
||||||
|
@@ -21,18 +21,20 @@ func TestPing(t *testing.T) {
|
|||||||
func TestAuth(t *testing.T) {
|
func TestAuth(t *testing.T) {
|
||||||
passwd := utils.RandString(10)
|
passwd := utils.RandString(10)
|
||||||
c := &connection.FakeConn{}
|
c := &connection.FakeConn{}
|
||||||
ret := Auth(testDB, c, utils.ToBytesList())
|
ret := testDB.Exec(c, utils.ToBytesList("AUTH"))
|
||||||
asserts.AssertErrReply(t, ret, "ERR wrong number of arguments for 'auth' command")
|
asserts.AssertErrReply(t, ret, "ERR wrong number of arguments for 'auth' command")
|
||||||
ret = Auth(testDB, c, utils.ToBytesList(passwd))
|
ret = testDB.Exec(c, utils.ToBytesList("AUTH", passwd))
|
||||||
asserts.AssertErrReply(t, ret, "ERR Client sent AUTH, but no password is set")
|
asserts.AssertErrReply(t, ret, "ERR Client sent AUTH, but no password is set")
|
||||||
|
|
||||||
config.Properties.RequirePass = passwd
|
config.Properties.RequirePass = passwd
|
||||||
defer func() {
|
defer func() {
|
||||||
config.Properties.RequirePass = ""
|
config.Properties.RequirePass = ""
|
||||||
}()
|
}()
|
||||||
ret = Auth(testDB, c, utils.ToBytesList(passwd+passwd))
|
ret = testDB.Exec(c, utils.ToBytesList("AUTH", passwd+"wrong"))
|
||||||
asserts.AssertErrReply(t, ret, "ERR invalid password")
|
asserts.AssertErrReply(t, ret, "ERR invalid password")
|
||||||
ret = Auth(testDB, c, utils.ToBytesList(passwd))
|
ret = testDB.Exec(c, utils.ToBytesList("PING"))
|
||||||
|
asserts.AssertErrReply(t, ret, "NOAUTH Authentication required")
|
||||||
|
ret = testDB.Exec(c, utils.ToBytesList("AUTH", passwd))
|
||||||
asserts.AssertStatusReply(t, ret, "OK")
|
asserts.AssertStatusReply(t, ret, "OK")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
96
set.go
96
set.go
@@ -35,11 +35,8 @@ func (db *DB) getOrInitSet(key string) (set *HashSet.Set, inited bool, errReply
|
|||||||
return set, inited, nil
|
return set, inited, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SAdd adds members into set
|
// execSAdd adds members into set
|
||||||
func SAdd(db *DB, args [][]byte) redis.Reply {
|
func execSAdd(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) < 2 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'sadd' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
members := args[1:]
|
members := args[1:]
|
||||||
|
|
||||||
@@ -60,11 +57,8 @@ func SAdd(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeIntReply(int64(counter))
|
return reply.MakeIntReply(int64(counter))
|
||||||
}
|
}
|
||||||
|
|
||||||
// SIsMember checks if the given value is member of set
|
// execSIsMember checks if the given value is member of set
|
||||||
func SIsMember(db *DB, args [][]byte) redis.Reply {
|
func execSIsMember(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) != 2 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'sismember' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
member := string(args[1])
|
member := string(args[1])
|
||||||
|
|
||||||
@@ -87,11 +81,8 @@ func SIsMember(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeIntReply(0)
|
return reply.MakeIntReply(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SRem removes a member from set
|
// execSRem removes a member from set
|
||||||
func SRem(db *DB, args [][]byte) redis.Reply {
|
func execSRem(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) < 2 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'srem' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
members := args[1:]
|
members := args[1:]
|
||||||
|
|
||||||
@@ -119,11 +110,8 @@ func SRem(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeIntReply(int64(counter))
|
return reply.MakeIntReply(int64(counter))
|
||||||
}
|
}
|
||||||
|
|
||||||
// SCard gets the number of members in a set
|
// execSCard gets the number of members in a set
|
||||||
func SCard(db *DB, args [][]byte) redis.Reply {
|
func execSCard(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) != 1 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'scard' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
|
|
||||||
db.RLock(key)
|
db.RLock(key)
|
||||||
@@ -140,11 +128,8 @@ func SCard(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeIntReply(int64(set.Len()))
|
return reply.MakeIntReply(int64(set.Len()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// SMembers gets all members in a set
|
// execSMembers gets all members in a set
|
||||||
func SMembers(db *DB, args [][]byte) redis.Reply {
|
func execSMembers(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) != 1 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'smembers' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
|
|
||||||
// lock
|
// lock
|
||||||
@@ -170,11 +155,8 @@ func SMembers(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeMultiBulkReply(arr)
|
return reply.MakeMultiBulkReply(arr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SInter intersect multiple sets
|
// execSInter intersect multiple sets
|
||||||
func SInter(db *DB, args [][]byte) redis.Reply {
|
func execSInter(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) < 1 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'sinter' command")
|
|
||||||
}
|
|
||||||
keys := make([]string, len(args))
|
keys := make([]string, len(args))
|
||||||
for i, arg := range args {
|
for i, arg := range args {
|
||||||
keys[i] = string(arg)
|
keys[i] = string(arg)
|
||||||
@@ -216,11 +198,8 @@ func SInter(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeMultiBulkReply(arr)
|
return reply.MakeMultiBulkReply(arr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SInterStore intersects multiple sets and store the result in a key
|
// execSInterStore intersects multiple sets and store the result in a key
|
||||||
func SInterStore(db *DB, args [][]byte) redis.Reply {
|
func execSInterStore(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) < 2 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'sinterstore' command")
|
|
||||||
}
|
|
||||||
dest := string(args[0])
|
dest := string(args[0])
|
||||||
keys := make([]string, len(args)-1)
|
keys := make([]string, len(args)-1)
|
||||||
keyArgs := args[1:]
|
keyArgs := args[1:]
|
||||||
@@ -267,11 +246,8 @@ func SInterStore(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeIntReply(int64(set.Len()))
|
return reply.MakeIntReply(int64(set.Len()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// SUnion adds multiple sets
|
// execSUnion adds multiple sets
|
||||||
func SUnion(db *DB, args [][]byte) redis.Reply {
|
func execSUnion(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) < 1 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'sunion' command")
|
|
||||||
}
|
|
||||||
keys := make([]string, len(args))
|
keys := make([]string, len(args))
|
||||||
for i, arg := range args {
|
for i, arg := range args {
|
||||||
keys[i] = string(arg)
|
keys[i] = string(arg)
|
||||||
@@ -313,11 +289,8 @@ func SUnion(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeMultiBulkReply(arr)
|
return reply.MakeMultiBulkReply(arr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SUnionStore adds multiple sets and store the result in a key
|
// execSUnionStore adds multiple sets and store the result in a key
|
||||||
func SUnionStore(db *DB, args [][]byte) redis.Reply {
|
func execSUnionStore(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) < 2 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'sunionstore' command")
|
|
||||||
}
|
|
||||||
dest := string(args[0])
|
dest := string(args[0])
|
||||||
keys := make([]string, len(args)-1)
|
keys := make([]string, len(args)-1)
|
||||||
keyArgs := args[1:]
|
keyArgs := args[1:]
|
||||||
@@ -364,11 +337,8 @@ func SUnionStore(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeIntReply(int64(set.Len()))
|
return reply.MakeIntReply(int64(set.Len()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// SDiff subtracts multiple sets
|
// execSDiff subtracts multiple sets
|
||||||
func SDiff(db *DB, args [][]byte) redis.Reply {
|
func execSDiff(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) < 1 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'sdiff' command")
|
|
||||||
}
|
|
||||||
keys := make([]string, len(args))
|
keys := make([]string, len(args))
|
||||||
for i, arg := range args {
|
for i, arg := range args {
|
||||||
keys[i] = string(arg)
|
keys[i] = string(arg)
|
||||||
@@ -417,11 +387,8 @@ func SDiff(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeMultiBulkReply(arr)
|
return reply.MakeMultiBulkReply(arr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SDiffStore subtracts multiple sets and store the result in a key
|
// execSDiffStore subtracts multiple sets and store the result in a key
|
||||||
func SDiffStore(db *DB, args [][]byte) redis.Reply {
|
func execSDiffStore(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) < 2 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'sdiffstore' command")
|
|
||||||
}
|
|
||||||
dest := string(args[0])
|
dest := string(args[0])
|
||||||
keys := make([]string, len(args)-1)
|
keys := make([]string, len(args)-1)
|
||||||
keyArgs := args[1:]
|
keyArgs := args[1:]
|
||||||
@@ -477,8 +444,8 @@ func SDiffStore(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeIntReply(int64(set.Len()))
|
return reply.MakeIntReply(int64(set.Len()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// SRandMember gets random members from set
|
// execSRandMember gets random members from set
|
||||||
func SRandMember(db *DB, args [][]byte) redis.Reply {
|
func execSRandMember(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) != 1 && len(args) != 2 {
|
if len(args) != 1 && len(args) != 2 {
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'srandmember' command")
|
return reply.MakeErrReply("ERR wrong number of arguments for 'srandmember' command")
|
||||||
}
|
}
|
||||||
@@ -522,3 +489,18 @@ func SRandMember(db *DB, args [][]byte) redis.Reply {
|
|||||||
}
|
}
|
||||||
return &reply.EmptyMultiBulkReply{}
|
return &reply.EmptyMultiBulkReply{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
RegisterCommand("SAdd", execSAdd, nil, -3)
|
||||||
|
RegisterCommand("SIsMember", execSIsMember, nil, 3)
|
||||||
|
RegisterCommand("SRem", execSRem, nil, -3)
|
||||||
|
RegisterCommand("SCard", execSCard, nil, 2)
|
||||||
|
RegisterCommand("SMembers", execSMembers, nil, 2)
|
||||||
|
RegisterCommand("SInter", execSInter, nil, -2)
|
||||||
|
RegisterCommand("SInterStore", execSInterStore, nil, -3)
|
||||||
|
RegisterCommand("SUnion", execSUnion, nil, -2)
|
||||||
|
RegisterCommand("SUnionStore", execSUnionStore, nil, -3)
|
||||||
|
RegisterCommand("SDiff", execSDiff, nil, -2)
|
||||||
|
RegisterCommand("SDiffStore", execSDiffStore, nil, -3)
|
||||||
|
RegisterCommand("SRandMember", execSRandMember, nil, -2)
|
||||||
|
}
|
||||||
|
88
set_test.go
88
set_test.go
@@ -11,29 +11,29 @@ import (
|
|||||||
|
|
||||||
// basic add get and remove
|
// basic add get and remove
|
||||||
func TestSAdd(t *testing.T) {
|
func TestSAdd(t *testing.T) {
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
size := 100
|
size := 100
|
||||||
|
|
||||||
// test sadd
|
// test sadd
|
||||||
key := utils.RandString(10)
|
key := utils.RandString(10)
|
||||||
for i := 0; i < size; i++ {
|
for i := 0; i < size; i++ {
|
||||||
member := strconv.Itoa(i)
|
member := strconv.Itoa(i)
|
||||||
result := SAdd(testDB, utils.ToBytesList(key, member))
|
result := execSAdd(testDB, utils.ToBytesList(key, member))
|
||||||
asserts.AssertIntReply(t, result, 1)
|
asserts.AssertIntReply(t, result, 1)
|
||||||
}
|
}
|
||||||
// test scard
|
// test scard
|
||||||
result := SCard(testDB, utils.ToBytesList(key))
|
result := execSCard(testDB, utils.ToBytesList(key))
|
||||||
asserts.AssertIntReply(t, result, size)
|
asserts.AssertIntReply(t, result, size)
|
||||||
|
|
||||||
// test is member
|
// test is member
|
||||||
for i := 0; i < size; i++ {
|
for i := 0; i < size; i++ {
|
||||||
member := strconv.Itoa(i)
|
member := strconv.Itoa(i)
|
||||||
result := SIsMember(testDB, utils.ToBytesList(key, member))
|
result := execSIsMember(testDB, utils.ToBytesList(key, member))
|
||||||
asserts.AssertIntReply(t, result, 1)
|
asserts.AssertIntReply(t, result, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// test members
|
// test members
|
||||||
result = SMembers(testDB, utils.ToBytesList(key))
|
result = execSMembers(testDB, utils.ToBytesList(key))
|
||||||
multiBulk, ok := result.(*reply.MultiBulkReply)
|
multiBulk, ok := result.(*reply.MultiBulkReply)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Error(fmt.Sprintf("expected bulk reply, actually %s", result.ToBytes()))
|
t.Error(fmt.Sprintf("expected bulk reply, actually %s", result.ToBytes()))
|
||||||
@@ -46,25 +46,25 @@ func TestSAdd(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestSRem(t *testing.T) {
|
func TestSRem(t *testing.T) {
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
size := 100
|
size := 100
|
||||||
|
|
||||||
// mock data
|
// mock data
|
||||||
key := utils.RandString(10)
|
key := utils.RandString(10)
|
||||||
for i := 0; i < size; i++ {
|
for i := 0; i < size; i++ {
|
||||||
member := strconv.Itoa(i)
|
member := strconv.Itoa(i)
|
||||||
SAdd(testDB, utils.ToBytesList(key, member))
|
execSAdd(testDB, utils.ToBytesList(key, member))
|
||||||
}
|
}
|
||||||
for i := 0; i < size; i++ {
|
for i := 0; i < size; i++ {
|
||||||
member := strconv.Itoa(i)
|
member := strconv.Itoa(i)
|
||||||
SRem(testDB, utils.ToBytesList(key, member))
|
execSRem(testDB, utils.ToBytesList(key, member))
|
||||||
result := SIsMember(testDB, utils.ToBytesList(key, member))
|
result := execSIsMember(testDB, utils.ToBytesList(key, member))
|
||||||
asserts.AssertIntReply(t, result, 0)
|
asserts.AssertIntReply(t, result, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSInter(t *testing.T) {
|
func TestSInter(t *testing.T) {
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
size := 100
|
size := 100
|
||||||
step := 10
|
step := 10
|
||||||
|
|
||||||
@@ -75,39 +75,39 @@ func TestSInter(t *testing.T) {
|
|||||||
keys = append(keys, key)
|
keys = append(keys, key)
|
||||||
for j := start; j < size+start; j++ {
|
for j := start; j < size+start; j++ {
|
||||||
member := strconv.Itoa(j)
|
member := strconv.Itoa(j)
|
||||||
SAdd(testDB, utils.ToBytesList(key, member))
|
execSAdd(testDB, utils.ToBytesList(key, member))
|
||||||
}
|
}
|
||||||
start += step
|
start += step
|
||||||
}
|
}
|
||||||
result := SInter(testDB, utils.ToBytesList(keys...))
|
result := execSInter(testDB, utils.ToBytesList(keys...))
|
||||||
asserts.AssertMultiBulkReplySize(t, result, 70)
|
asserts.AssertMultiBulkReplySize(t, result, 70)
|
||||||
|
|
||||||
destKey := utils.RandString(10)
|
destKey := utils.RandString(10)
|
||||||
keysWithDest := []string{destKey}
|
keysWithDest := []string{destKey}
|
||||||
keysWithDest = append(keysWithDest, keys...)
|
keysWithDest = append(keysWithDest, keys...)
|
||||||
result = SInterStore(testDB, utils.ToBytesList(keysWithDest...))
|
result = execSInterStore(testDB, utils.ToBytesList(keysWithDest...))
|
||||||
asserts.AssertIntReply(t, result, 70)
|
asserts.AssertIntReply(t, result, 70)
|
||||||
|
|
||||||
// test empty set
|
// test empty set
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
key0 := utils.RandString(10)
|
key0 := utils.RandString(10)
|
||||||
Del(testDB, utils.ToBytesList(key0))
|
testDB.Remove(key0)
|
||||||
key1 := utils.RandString(10)
|
key1 := utils.RandString(10)
|
||||||
SAdd(testDB, utils.ToBytesList(key1, "a", "b"))
|
execSAdd(testDB, utils.ToBytesList(key1, "a", "b"))
|
||||||
key2 := utils.RandString(10)
|
key2 := utils.RandString(10)
|
||||||
SAdd(testDB, utils.ToBytesList(key2, "1", "2"))
|
execSAdd(testDB, utils.ToBytesList(key2, "1", "2"))
|
||||||
result = SInter(testDB, utils.ToBytesList(key0, key1, key2))
|
result = execSInter(testDB, utils.ToBytesList(key0, key1, key2))
|
||||||
asserts.AssertMultiBulkReplySize(t, result, 0)
|
asserts.AssertMultiBulkReplySize(t, result, 0)
|
||||||
result = SInter(testDB, utils.ToBytesList(key1, key2))
|
result = execSInter(testDB, utils.ToBytesList(key1, key2))
|
||||||
asserts.AssertMultiBulkReplySize(t, result, 0)
|
asserts.AssertMultiBulkReplySize(t, result, 0)
|
||||||
result = SInterStore(testDB, utils.ToBytesList(utils.RandString(10), key0, key1, key2))
|
result = execSInterStore(testDB, utils.ToBytesList(utils.RandString(10), key0, key1, key2))
|
||||||
asserts.AssertIntReply(t, result, 0)
|
asserts.AssertIntReply(t, result, 0)
|
||||||
result = SInterStore(testDB, utils.ToBytesList(utils.RandString(10), key1, key2))
|
result = execSInterStore(testDB, utils.ToBytesList(utils.RandString(10), key1, key2))
|
||||||
asserts.AssertIntReply(t, result, 0)
|
asserts.AssertIntReply(t, result, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSUnion(t *testing.T) {
|
func TestSUnion(t *testing.T) {
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
size := 100
|
size := 100
|
||||||
step := 10
|
step := 10
|
||||||
|
|
||||||
@@ -118,22 +118,22 @@ func TestSUnion(t *testing.T) {
|
|||||||
keys = append(keys, key)
|
keys = append(keys, key)
|
||||||
for j := start; j < size+start; j++ {
|
for j := start; j < size+start; j++ {
|
||||||
member := strconv.Itoa(j)
|
member := strconv.Itoa(j)
|
||||||
SAdd(testDB, utils.ToBytesList(key, member))
|
execSAdd(testDB, utils.ToBytesList(key, member))
|
||||||
}
|
}
|
||||||
start += step
|
start += step
|
||||||
}
|
}
|
||||||
result := SUnion(testDB, utils.ToBytesList(keys...))
|
result := execSUnion(testDB, utils.ToBytesList(keys...))
|
||||||
asserts.AssertMultiBulkReplySize(t, result, 130)
|
asserts.AssertMultiBulkReplySize(t, result, 130)
|
||||||
|
|
||||||
destKey := utils.RandString(10)
|
destKey := utils.RandString(10)
|
||||||
keysWithDest := []string{destKey}
|
keysWithDest := []string{destKey}
|
||||||
keysWithDest = append(keysWithDest, keys...)
|
keysWithDest = append(keysWithDest, keys...)
|
||||||
result = SUnionStore(testDB, utils.ToBytesList(keysWithDest...))
|
result = execSUnionStore(testDB, utils.ToBytesList(keysWithDest...))
|
||||||
asserts.AssertIntReply(t, result, 130)
|
asserts.AssertIntReply(t, result, 130)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSDiff(t *testing.T) {
|
func TestSDiff(t *testing.T) {
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
size := 100
|
size := 100
|
||||||
step := 20
|
step := 20
|
||||||
|
|
||||||
@@ -144,52 +144,52 @@ func TestSDiff(t *testing.T) {
|
|||||||
keys = append(keys, key)
|
keys = append(keys, key)
|
||||||
for j := start; j < size+start; j++ {
|
for j := start; j < size+start; j++ {
|
||||||
member := strconv.Itoa(j)
|
member := strconv.Itoa(j)
|
||||||
SAdd(testDB, utils.ToBytesList(key, member))
|
execSAdd(testDB, utils.ToBytesList(key, member))
|
||||||
}
|
}
|
||||||
start += step
|
start += step
|
||||||
}
|
}
|
||||||
result := SDiff(testDB, utils.ToBytesList(keys...))
|
result := execSDiff(testDB, utils.ToBytesList(keys...))
|
||||||
asserts.AssertMultiBulkReplySize(t, result, step)
|
asserts.AssertMultiBulkReplySize(t, result, step)
|
||||||
|
|
||||||
destKey := utils.RandString(10)
|
destKey := utils.RandString(10)
|
||||||
keysWithDest := []string{destKey}
|
keysWithDest := []string{destKey}
|
||||||
keysWithDest = append(keysWithDest, keys...)
|
keysWithDest = append(keysWithDest, keys...)
|
||||||
result = SDiffStore(testDB, utils.ToBytesList(keysWithDest...))
|
result = execSDiffStore(testDB, utils.ToBytesList(keysWithDest...))
|
||||||
asserts.AssertIntReply(t, result, step)
|
asserts.AssertIntReply(t, result, step)
|
||||||
|
|
||||||
// test empty set
|
// test empty set
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
key0 := utils.RandString(10)
|
key0 := utils.RandString(10)
|
||||||
Del(testDB, utils.ToBytesList(key0))
|
testDB.Remove(key0)
|
||||||
key1 := utils.RandString(10)
|
key1 := utils.RandString(10)
|
||||||
SAdd(testDB, utils.ToBytesList(key1, "a", "b"))
|
execSAdd(testDB, utils.ToBytesList(key1, "a", "b"))
|
||||||
key2 := utils.RandString(10)
|
key2 := utils.RandString(10)
|
||||||
SAdd(testDB, utils.ToBytesList(key2, "a", "b"))
|
execSAdd(testDB, utils.ToBytesList(key2, "a", "b"))
|
||||||
result = SDiff(testDB, utils.ToBytesList(key0, key1, key2))
|
result = execSDiff(testDB, utils.ToBytesList(key0, key1, key2))
|
||||||
asserts.AssertMultiBulkReplySize(t, result, 0)
|
asserts.AssertMultiBulkReplySize(t, result, 0)
|
||||||
result = SDiff(testDB, utils.ToBytesList(key1, key2))
|
result = execSDiff(testDB, utils.ToBytesList(key1, key2))
|
||||||
asserts.AssertMultiBulkReplySize(t, result, 0)
|
asserts.AssertMultiBulkReplySize(t, result, 0)
|
||||||
result = SDiffStore(testDB, utils.ToBytesList(utils.RandString(10), key0, key1, key2))
|
result = execSDiffStore(testDB, utils.ToBytesList(utils.RandString(10), key0, key1, key2))
|
||||||
asserts.AssertIntReply(t, result, 0)
|
asserts.AssertIntReply(t, result, 0)
|
||||||
result = SDiffStore(testDB, utils.ToBytesList(utils.RandString(10), key1, key2))
|
result = execSDiffStore(testDB, utils.ToBytesList(utils.RandString(10), key1, key2))
|
||||||
asserts.AssertIntReply(t, result, 0)
|
asserts.AssertIntReply(t, result, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSRandMember(t *testing.T) {
|
func TestSRandMember(t *testing.T) {
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
key := utils.RandString(10)
|
key := utils.RandString(10)
|
||||||
for j := 0; j < 100; j++ {
|
for j := 0; j < 100; j++ {
|
||||||
member := strconv.Itoa(j)
|
member := strconv.Itoa(j)
|
||||||
SAdd(testDB, utils.ToBytesList(key, member))
|
execSAdd(testDB, utils.ToBytesList(key, member))
|
||||||
}
|
}
|
||||||
result := SRandMember(testDB, utils.ToBytesList(key))
|
result := execSRandMember(testDB, utils.ToBytesList(key))
|
||||||
br, ok := result.(*reply.BulkReply)
|
br, ok := result.(*reply.BulkReply)
|
||||||
if !ok && len(br.Arg) > 0 {
|
if !ok && len(br.Arg) > 0 {
|
||||||
t.Error(fmt.Sprintf("expected bulk reply, actually %s", result.ToBytes()))
|
t.Error(fmt.Sprintf("expected bulk reply, actually %s", result.ToBytes()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
result = SRandMember(testDB, utils.ToBytesList(key, "10"))
|
result = execSRandMember(testDB, utils.ToBytesList(key, "10"))
|
||||||
asserts.AssertMultiBulkReplySize(t, result, 10)
|
asserts.AssertMultiBulkReplySize(t, result, 10)
|
||||||
multiBulk, ok := result.(*reply.MultiBulkReply)
|
multiBulk, ok := result.(*reply.MultiBulkReply)
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -205,12 +205,12 @@ func TestSRandMember(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
result = SRandMember(testDB, utils.ToBytesList(key, "110"))
|
result = execSRandMember(testDB, utils.ToBytesList(key, "110"))
|
||||||
asserts.AssertMultiBulkReplySize(t, result, 100)
|
asserts.AssertMultiBulkReplySize(t, result, 100)
|
||||||
|
|
||||||
result = SRandMember(testDB, utils.ToBytesList(key, "-10"))
|
result = execSRandMember(testDB, utils.ToBytesList(key, "-10"))
|
||||||
asserts.AssertMultiBulkReplySize(t, result, 10)
|
asserts.AssertMultiBulkReplySize(t, result, 10)
|
||||||
|
|
||||||
result = SRandMember(testDB, utils.ToBytesList(key, "-110"))
|
result = execSRandMember(testDB, utils.ToBytesList(key, "-110"))
|
||||||
asserts.AssertMultiBulkReplySize(t, result, 110)
|
asserts.AssertMultiBulkReplySize(t, result, 110)
|
||||||
}
|
}
|
||||||
|
101
sortedset.go
101
sortedset.go
@@ -36,10 +36,10 @@ func (db *DB) getOrInitSortedSet(key string) (sortedSet *SortedSet.SortedSet, in
|
|||||||
return sortedSet, inited, nil
|
return sortedSet, inited, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ZAdd adds member into sorted set
|
// execZAdd adds member into sorted set
|
||||||
func ZAdd(db *DB, args [][]byte) redis.Reply {
|
func execZAdd(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) < 3 || len(args)%2 != 1 {
|
if len(args)%2 != 1 {
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'zadd' command")
|
return reply.MakeSyntaxErrReply()
|
||||||
}
|
}
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
size := (len(args) - 1) / 2
|
size := (len(args) - 1) / 2
|
||||||
@@ -79,12 +79,9 @@ func ZAdd(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeIntReply(int64(i))
|
return reply.MakeIntReply(int64(i))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ZScore gets score of a member in sortedset
|
// execZScore gets score of a member in sortedset
|
||||||
func ZScore(db *DB, args [][]byte) redis.Reply {
|
func execZScore(db *DB, args [][]byte) redis.Reply {
|
||||||
// parse args
|
// parse args
|
||||||
if len(args) != 2 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'zscore' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
member := string(args[1])
|
member := string(args[1])
|
||||||
|
|
||||||
@@ -106,12 +103,9 @@ func ZScore(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeBulkReply([]byte(value))
|
return reply.MakeBulkReply([]byte(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ZRank gets index of a member in sortedset, ascending order, start from 0
|
// execZRank gets index of a member in sortedset, ascending order, start from 0
|
||||||
func ZRank(db *DB, args [][]byte) redis.Reply {
|
func execZRank(db *DB, args [][]byte) redis.Reply {
|
||||||
// parse args
|
// parse args
|
||||||
if len(args) != 2 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'zrank' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
member := string(args[1])
|
member := string(args[1])
|
||||||
|
|
||||||
@@ -133,12 +127,9 @@ func ZRank(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeIntReply(rank)
|
return reply.MakeIntReply(rank)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ZRevRank gets index of a member in sortedset, descending order, start from 0
|
// execZRevRank gets index of a member in sortedset, descending order, start from 0
|
||||||
func ZRevRank(db *DB, args [][]byte) redis.Reply {
|
func execZRevRank(db *DB, args [][]byte) redis.Reply {
|
||||||
// parse args
|
// parse args
|
||||||
if len(args) != 2 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'zrevrank' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
member := string(args[1])
|
member := string(args[1])
|
||||||
|
|
||||||
@@ -160,12 +151,9 @@ func ZRevRank(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeIntReply(rank)
|
return reply.MakeIntReply(rank)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ZCard gets number of members in sortedset
|
// execZCard gets number of members in sortedset
|
||||||
func ZCard(db *DB, args [][]byte) redis.Reply {
|
func execZCard(db *DB, args [][]byte) redis.Reply {
|
||||||
// parse args
|
// parse args
|
||||||
if len(args) != 1 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'zcard' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
|
|
||||||
// get entity
|
// get entity
|
||||||
@@ -182,8 +170,8 @@ func ZCard(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeIntReply(sortedSet.Len())
|
return reply.MakeIntReply(sortedSet.Len())
|
||||||
}
|
}
|
||||||
|
|
||||||
// ZRange gets members in range, sort by score in ascending order
|
// execZRange gets members in range, sort by score in ascending order
|
||||||
func ZRange(db *DB, args [][]byte) redis.Reply {
|
func execZRange(db *DB, args [][]byte) redis.Reply {
|
||||||
// parse args
|
// parse args
|
||||||
if len(args) != 3 && len(args) != 4 {
|
if len(args) != 3 && len(args) != 4 {
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'zrange' command")
|
return reply.MakeErrReply("ERR wrong number of arguments for 'zrange' command")
|
||||||
@@ -207,8 +195,8 @@ func ZRange(db *DB, args [][]byte) redis.Reply {
|
|||||||
return range0(db, key, start, stop, withScores, false)
|
return range0(db, key, start, stop, withScores, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ZRevRange gets members in range, sort by score in descending order
|
// execZRevRange gets members in range, sort by score in descending order
|
||||||
func ZRevRange(db *DB, args [][]byte) redis.Reply {
|
func execZRevRange(db *DB, args [][]byte) redis.Reply {
|
||||||
// parse args
|
// parse args
|
||||||
if len(args) != 3 && len(args) != 4 {
|
if len(args) != 3 && len(args) != 4 {
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'zrevrange' command")
|
return reply.MakeErrReply("ERR wrong number of arguments for 'zrevrange' command")
|
||||||
@@ -291,11 +279,8 @@ func range0(db *DB, key string, start int64, stop int64, withScores bool, desc b
|
|||||||
return reply.MakeMultiBulkReply(result)
|
return reply.MakeMultiBulkReply(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ZCount gets number of members which score within given range
|
// execZCount gets number of members which score within given range
|
||||||
func ZCount(db *DB, args [][]byte) redis.Reply {
|
func execZCount(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) != 3 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'zcount' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
|
|
||||||
min, err := SortedSet.ParseScoreBorder(string(args[1]))
|
min, err := SortedSet.ParseScoreBorder(string(args[1]))
|
||||||
@@ -362,8 +347,8 @@ func rangeByScore0(db *DB, key string, min *SortedSet.ScoreBorder, max *SortedSe
|
|||||||
return reply.MakeMultiBulkReply(result)
|
return reply.MakeMultiBulkReply(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ZRangeByScore gets members which score within given range, in ascending order
|
// execZRangeByScore gets members which score within given range, in ascending order
|
||||||
func ZRangeByScore(db *DB, args [][]byte) redis.Reply {
|
func execZRangeByScore(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) < 3 {
|
if len(args) < 3 {
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'zrangebyscore' command")
|
return reply.MakeErrReply("ERR wrong number of arguments for 'zrangebyscore' command")
|
||||||
}
|
}
|
||||||
@@ -409,8 +394,8 @@ func ZRangeByScore(db *DB, args [][]byte) redis.Reply {
|
|||||||
return rangeByScore0(db, key, min, max, offset, limit, withScores, false)
|
return rangeByScore0(db, key, min, max, offset, limit, withScores, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ZRevRangeByScore gets number of members which score within given range, in descending order
|
// execZRevRangeByScore gets number of members which score within given range, in descending order
|
||||||
func ZRevRangeByScore(db *DB, args [][]byte) redis.Reply {
|
func execZRevRangeByScore(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) < 3 {
|
if len(args) < 3 {
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'zrangebyscore' command")
|
return reply.MakeErrReply("ERR wrong number of arguments for 'zrangebyscore' command")
|
||||||
}
|
}
|
||||||
@@ -456,8 +441,8 @@ func ZRevRangeByScore(db *DB, args [][]byte) redis.Reply {
|
|||||||
return rangeByScore0(db, key, min, max, offset, limit, withScores, true)
|
return rangeByScore0(db, key, min, max, offset, limit, withScores, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ZRemRangeByScore removes members which score within given range
|
// execZRemRangeByScore removes members which score within given range
|
||||||
func ZRemRangeByScore(db *DB, args [][]byte) redis.Reply {
|
func execZRemRangeByScore(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) != 3 {
|
if len(args) != 3 {
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'zremrangebyscore' command")
|
return reply.MakeErrReply("ERR wrong number of arguments for 'zremrangebyscore' command")
|
||||||
}
|
}
|
||||||
@@ -492,11 +477,8 @@ func ZRemRangeByScore(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeIntReply(removed)
|
return reply.MakeIntReply(removed)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ZRemRangeByRank removes members within given indexes
|
// execZRemRangeByRank removes members within given indexes
|
||||||
func ZRemRangeByRank(db *DB, args [][]byte) redis.Reply {
|
func execZRemRangeByRank(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) != 3 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'zremrangebyrank' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
start, err := strconv.ParseInt(string(args[1]), 10, 64)
|
start, err := strconv.ParseInt(string(args[1]), 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -549,12 +531,9 @@ func ZRemRangeByRank(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeIntReply(removed)
|
return reply.MakeIntReply(removed)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ZRem removes given members
|
// execZRem removes given members
|
||||||
func ZRem(db *DB, args [][]byte) redis.Reply {
|
func execZRem(db *DB, args [][]byte) redis.Reply {
|
||||||
// parse args
|
// parse args
|
||||||
if len(args) < 2 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'zrem' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
fields := make([]string, len(args)-1)
|
fields := make([]string, len(args)-1)
|
||||||
fieldArgs := args[1:]
|
fieldArgs := args[1:]
|
||||||
@@ -586,11 +565,8 @@ func ZRem(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeIntReply(deleted)
|
return reply.MakeIntReply(deleted)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ZIncrBy increments the score of a member
|
// execZIncrBy increments the score of a member
|
||||||
func ZIncrBy(db *DB, args [][]byte) redis.Reply {
|
func execZIncrBy(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) != 3 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'zincrby' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
rawDelta := string(args[1])
|
rawDelta := string(args[1])
|
||||||
field := string(args[2])
|
field := string(args[2])
|
||||||
@@ -620,3 +596,20 @@ func ZIncrBy(db *DB, args [][]byte) redis.Reply {
|
|||||||
db.AddAof(makeAofCmd("zincrby", args))
|
db.AddAof(makeAofCmd("zincrby", args))
|
||||||
return reply.MakeBulkReply(bytes)
|
return reply.MakeBulkReply(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
RegisterCommand("ZAdd", execZAdd, nil, -4)
|
||||||
|
RegisterCommand("ZScore", execZScore, nil, 3)
|
||||||
|
RegisterCommand("ZIncrBy", execZIncrBy, nil, 4)
|
||||||
|
RegisterCommand("ZRank", execZRank, nil, 3)
|
||||||
|
RegisterCommand("ZCount", execZCount, nil, 4)
|
||||||
|
RegisterCommand("ZRevRank", execZRevRank, nil, 3)
|
||||||
|
RegisterCommand("ZCard", execZCard, nil, 2)
|
||||||
|
RegisterCommand("ZRange", execZRange, nil, -4)
|
||||||
|
RegisterCommand("ZRangeByScore", execZRangeByScore, nil, -4)
|
||||||
|
RegisterCommand("ZRange", execZRevRange, nil, -4)
|
||||||
|
RegisterCommand("ZRangeByScore", execZRevRangeByScore, nil, -4)
|
||||||
|
RegisterCommand("ZRem", execZRem, nil, -3)
|
||||||
|
RegisterCommand("ZRemRangeByScore", execZRemRangeByScore, nil, 4)
|
||||||
|
RegisterCommand("ZRemRangeByRank", execZRemRangeByRank, nil, 4)
|
||||||
|
}
|
||||||
|
@@ -9,7 +9,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestZAdd(t *testing.T) {
|
func TestZAdd(t *testing.T) {
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
size := 100
|
size := 100
|
||||||
|
|
||||||
// add new members
|
// add new members
|
||||||
@@ -22,18 +22,18 @@ func TestZAdd(t *testing.T) {
|
|||||||
scores[i] = rand.Float64()
|
scores[i] = rand.Float64()
|
||||||
setArgs = append(setArgs, strconv.FormatFloat(scores[i], 'f', -1, 64), members[i])
|
setArgs = append(setArgs, strconv.FormatFloat(scores[i], 'f', -1, 64), members[i])
|
||||||
}
|
}
|
||||||
result := ZAdd(testDB, utils.ToBytesList(setArgs...))
|
result := execZAdd(testDB, utils.ToBytesList(setArgs...))
|
||||||
asserts.AssertIntReply(t, result, size)
|
asserts.AssertIntReply(t, result, size)
|
||||||
|
|
||||||
// test zscore and zrank
|
// test zscore and zrank
|
||||||
for i, member := range members {
|
for i, member := range members {
|
||||||
result := ZScore(testDB, utils.ToBytesList(key, member))
|
result := execZScore(testDB, utils.ToBytesList(key, member))
|
||||||
score := strconv.FormatFloat(scores[i], 'f', -1, 64)
|
score := strconv.FormatFloat(scores[i], 'f', -1, 64)
|
||||||
asserts.AssertBulkReply(t, result, score)
|
asserts.AssertBulkReply(t, result, score)
|
||||||
}
|
}
|
||||||
|
|
||||||
// test zcard
|
// test zcard
|
||||||
result = ZCard(testDB, utils.ToBytesList(key))
|
result = execZCard(testDB, utils.ToBytesList(key))
|
||||||
asserts.AssertIntReply(t, result, size)
|
asserts.AssertIntReply(t, result, size)
|
||||||
|
|
||||||
// update members
|
// update members
|
||||||
@@ -42,19 +42,19 @@ func TestZAdd(t *testing.T) {
|
|||||||
scores[i] = rand.Float64() + 100
|
scores[i] = rand.Float64() + 100
|
||||||
setArgs = append(setArgs, strconv.FormatFloat(scores[i], 'f', -1, 64), members[i])
|
setArgs = append(setArgs, strconv.FormatFloat(scores[i], 'f', -1, 64), members[i])
|
||||||
}
|
}
|
||||||
result = ZAdd(testDB, utils.ToBytesList(setArgs...))
|
result = execZAdd(testDB, utils.ToBytesList(setArgs...))
|
||||||
asserts.AssertIntReply(t, result, 0) // return number of new members
|
asserts.AssertIntReply(t, result, 0) // return number of new members
|
||||||
|
|
||||||
// test updated score
|
// test updated score
|
||||||
for i, member := range members {
|
for i, member := range members {
|
||||||
result := ZScore(testDB, utils.ToBytesList(key, member))
|
result := execZScore(testDB, utils.ToBytesList(key, member))
|
||||||
score := strconv.FormatFloat(scores[i], 'f', -1, 64)
|
score := strconv.FormatFloat(scores[i], 'f', -1, 64)
|
||||||
asserts.AssertBulkReply(t, result, score)
|
asserts.AssertBulkReply(t, result, score)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestZRank(t *testing.T) {
|
func TestZRank(t *testing.T) {
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
size := 100
|
size := 100
|
||||||
key := utils.RandString(10)
|
key := utils.RandString(10)
|
||||||
members := make([]string, size)
|
members := make([]string, size)
|
||||||
@@ -65,21 +65,21 @@ func TestZRank(t *testing.T) {
|
|||||||
scores[i] = i
|
scores[i] = i
|
||||||
setArgs = append(setArgs, strconv.FormatInt(int64(scores[i]), 10), members[i])
|
setArgs = append(setArgs, strconv.FormatInt(int64(scores[i]), 10), members[i])
|
||||||
}
|
}
|
||||||
ZAdd(testDB, utils.ToBytesList(setArgs...))
|
execZAdd(testDB, utils.ToBytesList(setArgs...))
|
||||||
|
|
||||||
// test zrank
|
// test zrank
|
||||||
for i, member := range members {
|
for i, member := range members {
|
||||||
result := ZRank(testDB, utils.ToBytesList(key, member))
|
result := execZRank(testDB, utils.ToBytesList(key, member))
|
||||||
asserts.AssertIntReply(t, result, i)
|
asserts.AssertIntReply(t, result, i)
|
||||||
|
|
||||||
result = ZRevRank(testDB, utils.ToBytesList(key, member))
|
result = execZRevRank(testDB, utils.ToBytesList(key, member))
|
||||||
asserts.AssertIntReply(t, result, size-i-1)
|
asserts.AssertIntReply(t, result, size-i-1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestZRange(t *testing.T) {
|
func TestZRange(t *testing.T) {
|
||||||
// prepare
|
// prepare
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
size := 100
|
size := 100
|
||||||
key := utils.RandString(10)
|
key := utils.RandString(10)
|
||||||
members := make([]string, size)
|
members := make([]string, size)
|
||||||
@@ -90,7 +90,7 @@ func TestZRange(t *testing.T) {
|
|||||||
scores[i] = i
|
scores[i] = i
|
||||||
setArgs = append(setArgs, strconv.FormatInt(int64(scores[i]), 10), members[i])
|
setArgs = append(setArgs, strconv.FormatInt(int64(scores[i]), 10), members[i])
|
||||||
}
|
}
|
||||||
ZAdd(testDB, utils.ToBytesList(setArgs...))
|
execZAdd(testDB, utils.ToBytesList(setArgs...))
|
||||||
reverseMembers := make([]string, size)
|
reverseMembers := make([]string, size)
|
||||||
for i, v := range members {
|
for i, v := range members {
|
||||||
reverseMembers[size-i-1] = v
|
reverseMembers[size-i-1] = v
|
||||||
@@ -98,39 +98,39 @@ func TestZRange(t *testing.T) {
|
|||||||
|
|
||||||
start := "0"
|
start := "0"
|
||||||
end := "9"
|
end := "9"
|
||||||
result := ZRange(testDB, utils.ToBytesList(key, start, end))
|
result := execZRange(testDB, utils.ToBytesList(key, start, end))
|
||||||
asserts.AssertMultiBulkReply(t, result, members[0:10])
|
asserts.AssertMultiBulkReply(t, result, members[0:10])
|
||||||
result = ZRange(testDB, utils.ToBytesList(key, start, end, "WITHSCORES"))
|
result = execZRange(testDB, utils.ToBytesList(key, start, end, "WITHSCORES"))
|
||||||
asserts.AssertMultiBulkReplySize(t, result, 20)
|
asserts.AssertMultiBulkReplySize(t, result, 20)
|
||||||
result = ZRevRange(testDB, utils.ToBytesList(key, start, end))
|
result = execZRevRange(testDB, utils.ToBytesList(key, start, end))
|
||||||
asserts.AssertMultiBulkReply(t, result, reverseMembers[0:10])
|
asserts.AssertMultiBulkReply(t, result, reverseMembers[0:10])
|
||||||
|
|
||||||
start = "0"
|
start = "0"
|
||||||
end = "200"
|
end = "200"
|
||||||
result = ZRange(testDB, utils.ToBytesList(key, start, end))
|
result = execZRange(testDB, utils.ToBytesList(key, start, end))
|
||||||
asserts.AssertMultiBulkReply(t, result, members)
|
asserts.AssertMultiBulkReply(t, result, members)
|
||||||
result = ZRevRange(testDB, utils.ToBytesList(key, start, end))
|
result = execZRevRange(testDB, utils.ToBytesList(key, start, end))
|
||||||
asserts.AssertMultiBulkReply(t, result, reverseMembers)
|
asserts.AssertMultiBulkReply(t, result, reverseMembers)
|
||||||
|
|
||||||
start = "0"
|
start = "0"
|
||||||
end = "-10"
|
end = "-10"
|
||||||
result = ZRange(testDB, utils.ToBytesList(key, start, end))
|
result = execZRange(testDB, utils.ToBytesList(key, start, end))
|
||||||
asserts.AssertMultiBulkReply(t, result, members[0:size-10+1])
|
asserts.AssertMultiBulkReply(t, result, members[0:size-10+1])
|
||||||
result = ZRevRange(testDB, utils.ToBytesList(key, start, end))
|
result = execZRevRange(testDB, utils.ToBytesList(key, start, end))
|
||||||
asserts.AssertMultiBulkReply(t, result, reverseMembers[0:size-10+1])
|
asserts.AssertMultiBulkReply(t, result, reverseMembers[0:size-10+1])
|
||||||
|
|
||||||
start = "0"
|
start = "0"
|
||||||
end = "-200"
|
end = "-200"
|
||||||
result = ZRange(testDB, utils.ToBytesList(key, start, end))
|
result = execZRange(testDB, utils.ToBytesList(key, start, end))
|
||||||
asserts.AssertMultiBulkReply(t, result, members[0:0])
|
asserts.AssertMultiBulkReply(t, result, members[0:0])
|
||||||
result = ZRevRange(testDB, utils.ToBytesList(key, start, end))
|
result = execZRevRange(testDB, utils.ToBytesList(key, start, end))
|
||||||
asserts.AssertMultiBulkReply(t, result, reverseMembers[0:0])
|
asserts.AssertMultiBulkReply(t, result, reverseMembers[0:0])
|
||||||
|
|
||||||
start = "-10"
|
start = "-10"
|
||||||
end = "-1"
|
end = "-1"
|
||||||
result = ZRange(testDB, utils.ToBytesList(key, start, end))
|
result = execZRange(testDB, utils.ToBytesList(key, start, end))
|
||||||
asserts.AssertMultiBulkReply(t, result, members[90:])
|
asserts.AssertMultiBulkReply(t, result, members[90:])
|
||||||
result = ZRevRange(testDB, utils.ToBytesList(key, start, end))
|
result = execZRevRange(testDB, utils.ToBytesList(key, start, end))
|
||||||
asserts.AssertMultiBulkReply(t, result, reverseMembers[90:])
|
asserts.AssertMultiBulkReply(t, result, reverseMembers[90:])
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,7 +144,7 @@ func reverse(src []string) []string {
|
|||||||
|
|
||||||
func TestZRangeByScore(t *testing.T) {
|
func TestZRangeByScore(t *testing.T) {
|
||||||
// prepare
|
// prepare
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
size := 100
|
size := 100
|
||||||
key := utils.RandString(10)
|
key := utils.RandString(10)
|
||||||
members := make([]string, size)
|
members := make([]string, size)
|
||||||
@@ -155,49 +155,49 @@ func TestZRangeByScore(t *testing.T) {
|
|||||||
scores[i] = i
|
scores[i] = i
|
||||||
setArgs = append(setArgs, strconv.FormatInt(int64(scores[i]), 10), members[i])
|
setArgs = append(setArgs, strconv.FormatInt(int64(scores[i]), 10), members[i])
|
||||||
}
|
}
|
||||||
result := ZAdd(testDB, utils.ToBytesList(setArgs...))
|
result := execZAdd(testDB, utils.ToBytesList(setArgs...))
|
||||||
asserts.AssertIntReply(t, result, size)
|
asserts.AssertIntReply(t, result, size)
|
||||||
|
|
||||||
min := "20"
|
min := "20"
|
||||||
max := "30"
|
max := "30"
|
||||||
result = ZRangeByScore(testDB, utils.ToBytesList(key, min, max))
|
result = execZRangeByScore(testDB, utils.ToBytesList(key, min, max))
|
||||||
asserts.AssertMultiBulkReply(t, result, members[20:31])
|
asserts.AssertMultiBulkReply(t, result, members[20:31])
|
||||||
result = ZRangeByScore(testDB, utils.ToBytesList(key, min, max, "WITHSCORES"))
|
result = execZRangeByScore(testDB, utils.ToBytesList(key, min, max, "WITHSCORES"))
|
||||||
asserts.AssertMultiBulkReplySize(t, result, 22)
|
asserts.AssertMultiBulkReplySize(t, result, 22)
|
||||||
result = ZRevRangeByScore(testDB, utils.ToBytesList(key, max, min))
|
result = execZRevRangeByScore(testDB, utils.ToBytesList(key, max, min))
|
||||||
asserts.AssertMultiBulkReply(t, result, reverse(members[20:31]))
|
asserts.AssertMultiBulkReply(t, result, reverse(members[20:31]))
|
||||||
|
|
||||||
min = "-10"
|
min = "-10"
|
||||||
max = "10"
|
max = "10"
|
||||||
result = ZRangeByScore(testDB, utils.ToBytesList(key, min, max))
|
result = execZRangeByScore(testDB, utils.ToBytesList(key, min, max))
|
||||||
asserts.AssertMultiBulkReply(t, result, members[0:11])
|
asserts.AssertMultiBulkReply(t, result, members[0:11])
|
||||||
result = ZRevRangeByScore(testDB, utils.ToBytesList(key, max, min))
|
result = execZRevRangeByScore(testDB, utils.ToBytesList(key, max, min))
|
||||||
asserts.AssertMultiBulkReply(t, result, reverse(members[0:11]))
|
asserts.AssertMultiBulkReply(t, result, reverse(members[0:11]))
|
||||||
|
|
||||||
min = "90"
|
min = "90"
|
||||||
max = "110"
|
max = "110"
|
||||||
result = ZRangeByScore(testDB, utils.ToBytesList(key, min, max))
|
result = execZRangeByScore(testDB, utils.ToBytesList(key, min, max))
|
||||||
asserts.AssertMultiBulkReply(t, result, members[90:])
|
asserts.AssertMultiBulkReply(t, result, members[90:])
|
||||||
result = ZRevRangeByScore(testDB, utils.ToBytesList(key, max, min))
|
result = execZRevRangeByScore(testDB, utils.ToBytesList(key, max, min))
|
||||||
asserts.AssertMultiBulkReply(t, result, reverse(members[90:]))
|
asserts.AssertMultiBulkReply(t, result, reverse(members[90:]))
|
||||||
|
|
||||||
min = "(20"
|
min = "(20"
|
||||||
max = "(30"
|
max = "(30"
|
||||||
result = ZRangeByScore(testDB, utils.ToBytesList(key, min, max))
|
result = execZRangeByScore(testDB, utils.ToBytesList(key, min, max))
|
||||||
asserts.AssertMultiBulkReply(t, result, members[21:30])
|
asserts.AssertMultiBulkReply(t, result, members[21:30])
|
||||||
result = ZRevRangeByScore(testDB, utils.ToBytesList(key, max, min))
|
result = execZRevRangeByScore(testDB, utils.ToBytesList(key, max, min))
|
||||||
asserts.AssertMultiBulkReply(t, result, reverse(members[21:30]))
|
asserts.AssertMultiBulkReply(t, result, reverse(members[21:30]))
|
||||||
|
|
||||||
min = "20"
|
min = "20"
|
||||||
max = "40"
|
max = "40"
|
||||||
result = ZRangeByScore(testDB, utils.ToBytesList(key, min, max, "LIMIT", "5", "5"))
|
result = execZRangeByScore(testDB, utils.ToBytesList(key, min, max, "LIMIT", "5", "5"))
|
||||||
asserts.AssertMultiBulkReply(t, result, members[25:30])
|
asserts.AssertMultiBulkReply(t, result, members[25:30])
|
||||||
result = ZRevRangeByScore(testDB, utils.ToBytesList(key, max, min, "LIMIT", "5", "5"))
|
result = execZRevRangeByScore(testDB, utils.ToBytesList(key, max, min, "LIMIT", "5", "5"))
|
||||||
asserts.AssertMultiBulkReply(t, result, reverse(members[31:36]))
|
asserts.AssertMultiBulkReply(t, result, reverse(members[31:36]))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestZRem(t *testing.T) {
|
func TestZRem(t *testing.T) {
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
size := 100
|
size := 100
|
||||||
key := utils.RandString(10)
|
key := utils.RandString(10)
|
||||||
members := make([]string, size)
|
members := make([]string, size)
|
||||||
@@ -208,17 +208,17 @@ func TestZRem(t *testing.T) {
|
|||||||
scores[i] = i
|
scores[i] = i
|
||||||
setArgs = append(setArgs, strconv.FormatInt(int64(scores[i]), 10), members[i])
|
setArgs = append(setArgs, strconv.FormatInt(int64(scores[i]), 10), members[i])
|
||||||
}
|
}
|
||||||
ZAdd(testDB, utils.ToBytesList(setArgs...))
|
execZAdd(testDB, utils.ToBytesList(setArgs...))
|
||||||
|
|
||||||
args := []string{key}
|
args := []string{key}
|
||||||
args = append(args, members[0:10]...)
|
args = append(args, members[0:10]...)
|
||||||
result := ZRem(testDB, utils.ToBytesList(args...))
|
result := execZRem(testDB, utils.ToBytesList(args...))
|
||||||
asserts.AssertIntReply(t, result, 10)
|
asserts.AssertIntReply(t, result, 10)
|
||||||
result = ZCard(testDB, utils.ToBytesList(key))
|
result = execZCard(testDB, utils.ToBytesList(key))
|
||||||
asserts.AssertIntReply(t, result, size-10)
|
asserts.AssertIntReply(t, result, size-10)
|
||||||
|
|
||||||
// test ZRemRangeByRank
|
// test ZRemRangeByRank
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
size = 100
|
size = 100
|
||||||
key = utils.RandString(10)
|
key = utils.RandString(10)
|
||||||
members = make([]string, size)
|
members = make([]string, size)
|
||||||
@@ -229,15 +229,15 @@ func TestZRem(t *testing.T) {
|
|||||||
scores[i] = i
|
scores[i] = i
|
||||||
setArgs = append(setArgs, strconv.FormatInt(int64(scores[i]), 10), members[i])
|
setArgs = append(setArgs, strconv.FormatInt(int64(scores[i]), 10), members[i])
|
||||||
}
|
}
|
||||||
ZAdd(testDB, utils.ToBytesList(setArgs...))
|
execZAdd(testDB, utils.ToBytesList(setArgs...))
|
||||||
|
|
||||||
result = ZRemRangeByRank(testDB, utils.ToBytesList(key, "0", "9"))
|
result = execZRemRangeByRank(testDB, utils.ToBytesList(key, "0", "9"))
|
||||||
asserts.AssertIntReply(t, result, 10)
|
asserts.AssertIntReply(t, result, 10)
|
||||||
result = ZCard(testDB, utils.ToBytesList(key))
|
result = execZCard(testDB, utils.ToBytesList(key))
|
||||||
asserts.AssertIntReply(t, result, size-10)
|
asserts.AssertIntReply(t, result, size-10)
|
||||||
|
|
||||||
// test ZRemRangeByScore
|
// test ZRemRangeByScore
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
size = 100
|
size = 100
|
||||||
key = utils.RandString(10)
|
key = utils.RandString(10)
|
||||||
members = make([]string, size)
|
members = make([]string, size)
|
||||||
@@ -248,17 +248,17 @@ func TestZRem(t *testing.T) {
|
|||||||
scores[i] = i
|
scores[i] = i
|
||||||
setArgs = append(setArgs, strconv.FormatInt(int64(scores[i]), 10), members[i])
|
setArgs = append(setArgs, strconv.FormatInt(int64(scores[i]), 10), members[i])
|
||||||
}
|
}
|
||||||
ZAdd(testDB, utils.ToBytesList(setArgs...))
|
execZAdd(testDB, utils.ToBytesList(setArgs...))
|
||||||
|
|
||||||
result = ZRemRangeByScore(testDB, utils.ToBytesList(key, "0", "9"))
|
result = execZRemRangeByScore(testDB, utils.ToBytesList(key, "0", "9"))
|
||||||
asserts.AssertIntReply(t, result, 10)
|
asserts.AssertIntReply(t, result, 10)
|
||||||
result = ZCard(testDB, utils.ToBytesList(key))
|
result = execZCard(testDB, utils.ToBytesList(key))
|
||||||
asserts.AssertIntReply(t, result, size-10)
|
asserts.AssertIntReply(t, result, size-10)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestZCount(t *testing.T) {
|
func TestZCount(t *testing.T) {
|
||||||
// prepare
|
// prepare
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
size := 100
|
size := 100
|
||||||
key := utils.RandString(10)
|
key := utils.RandString(10)
|
||||||
members := make([]string, size)
|
members := make([]string, size)
|
||||||
@@ -269,37 +269,37 @@ func TestZCount(t *testing.T) {
|
|||||||
scores[i] = i
|
scores[i] = i
|
||||||
setArgs = append(setArgs, strconv.FormatInt(int64(scores[i]), 10), members[i])
|
setArgs = append(setArgs, strconv.FormatInt(int64(scores[i]), 10), members[i])
|
||||||
}
|
}
|
||||||
ZAdd(testDB, utils.ToBytesList(setArgs...))
|
execZAdd(testDB, utils.ToBytesList(setArgs...))
|
||||||
|
|
||||||
min := "20"
|
min := "20"
|
||||||
max := "30"
|
max := "30"
|
||||||
result := ZCount(testDB, utils.ToBytesList(key, min, max))
|
result := execZCount(testDB, utils.ToBytesList(key, min, max))
|
||||||
asserts.AssertIntReply(t, result, 11)
|
asserts.AssertIntReply(t, result, 11)
|
||||||
|
|
||||||
min = "-10"
|
min = "-10"
|
||||||
max = "10"
|
max = "10"
|
||||||
result = ZCount(testDB, utils.ToBytesList(key, min, max))
|
result = execZCount(testDB, utils.ToBytesList(key, min, max))
|
||||||
asserts.AssertIntReply(t, result, 11)
|
asserts.AssertIntReply(t, result, 11)
|
||||||
|
|
||||||
min = "90"
|
min = "90"
|
||||||
max = "110"
|
max = "110"
|
||||||
result = ZCount(testDB, utils.ToBytesList(key, min, max))
|
result = execZCount(testDB, utils.ToBytesList(key, min, max))
|
||||||
asserts.AssertIntReply(t, result, 10)
|
asserts.AssertIntReply(t, result, 10)
|
||||||
|
|
||||||
min = "(20"
|
min = "(20"
|
||||||
max = "(30"
|
max = "(30"
|
||||||
result = ZCount(testDB, utils.ToBytesList(key, min, max))
|
result = execZCount(testDB, utils.ToBytesList(key, min, max))
|
||||||
asserts.AssertIntReply(t, result, 9)
|
asserts.AssertIntReply(t, result, 9)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestZIncrBy(t *testing.T) {
|
func TestZIncrBy(t *testing.T) {
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
key := utils.RandString(10)
|
key := utils.RandString(10)
|
||||||
result := ZIncrBy(testDB, utils.ToBytesList(key, "10", "a"))
|
result := execZIncrBy(testDB, utils.ToBytesList(key, "10", "a"))
|
||||||
asserts.AssertBulkReply(t, result, "10")
|
asserts.AssertBulkReply(t, result, "10")
|
||||||
result = ZIncrBy(testDB, utils.ToBytesList(key, "10", "a"))
|
result = execZIncrBy(testDB, utils.ToBytesList(key, "10", "a"))
|
||||||
asserts.AssertBulkReply(t, result, "20")
|
asserts.AssertBulkReply(t, result, "20")
|
||||||
|
|
||||||
result = ZScore(testDB, utils.ToBytesList(key, "a"))
|
result = execZScore(testDB, utils.ToBytesList(key, "a"))
|
||||||
asserts.AssertBulkReply(t, result, "20")
|
asserts.AssertBulkReply(t, result, "20")
|
||||||
}
|
}
|
||||||
|
119
string.go
119
string.go
@@ -21,11 +21,8 @@ func (db *DB) getAsString(key string) ([]byte, reply.ErrorReply) {
|
|||||||
return bytes, nil
|
return bytes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get returns string value bound to the given key
|
// execGet returns string value bound to the given key
|
||||||
func Get(db *DB, args [][]byte) redis.Reply {
|
func execGet(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) != 1 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'get' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
bytes, err := db.getAsString(key)
|
bytes, err := db.getAsString(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -45,11 +42,8 @@ const (
|
|||||||
|
|
||||||
const unlimitedTTL int64 = 0
|
const unlimitedTTL int64 = 0
|
||||||
|
|
||||||
// Set sets string value and time to live to the given key
|
// execSet sets string value and time to live to the given key
|
||||||
func Set(db *DB, args [][]byte) redis.Reply {
|
func execSet(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) < 2 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'set' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
value := args[1]
|
value := args[1]
|
||||||
policy := upsertPolicy
|
policy := upsertPolicy
|
||||||
@@ -149,11 +143,8 @@ func Set(db *DB, args [][]byte) redis.Reply {
|
|||||||
return &reply.NullBulkReply{}
|
return &reply.NullBulkReply{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetNX sets string if not exists
|
// execSetNX sets string if not exists
|
||||||
func SetNX(db *DB, args [][]byte) redis.Reply {
|
func execSetNX(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) != 2 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'setnx' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
value := args[1]
|
value := args[1]
|
||||||
entity := &DataEntity{
|
entity := &DataEntity{
|
||||||
@@ -164,11 +155,8 @@ func SetNX(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeIntReply(int64(result))
|
return reply.MakeIntReply(int64(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetEX sets string and its ttl
|
// execSetEX sets string and its ttl
|
||||||
func SetEX(db *DB, args [][]byte) redis.Reply {
|
func execSetEX(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) != 3 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'setex' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
value := args[2]
|
value := args[2]
|
||||||
|
|
||||||
@@ -196,11 +184,8 @@ func SetEX(db *DB, args [][]byte) redis.Reply {
|
|||||||
return &reply.OkReply{}
|
return &reply.OkReply{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// PSetEX set a key's time to live in milliseconds
|
// execPSetEX set a key's time to live in milliseconds
|
||||||
func PSetEX(db *DB, args [][]byte) redis.Reply {
|
func execPSetEX(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) != 3 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'setex' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
value := args[2]
|
value := args[2]
|
||||||
|
|
||||||
@@ -228,10 +213,10 @@ func PSetEX(db *DB, args [][]byte) redis.Reply {
|
|||||||
return &reply.OkReply{}
|
return &reply.OkReply{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MSet sets multi key-value in database
|
// execMSet sets multi key-value in database
|
||||||
func MSet(db *DB, args [][]byte) redis.Reply {
|
func execMSet(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args)%2 != 0 || len(args) == 0 {
|
if len(args)%2 != 0 {
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'mset' command")
|
return reply.MakeSyntaxErrReply()
|
||||||
}
|
}
|
||||||
|
|
||||||
size := len(args) / 2
|
size := len(args) / 2
|
||||||
@@ -253,11 +238,8 @@ func MSet(db *DB, args [][]byte) redis.Reply {
|
|||||||
return &reply.OkReply{}
|
return &reply.OkReply{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MGet get multi key-value from database
|
// execMGet get multi key-value from database
|
||||||
func MGet(db *DB, args [][]byte) redis.Reply {
|
func execMGet(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) == 0 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'mget' command")
|
|
||||||
}
|
|
||||||
keys := make([]string, len(args))
|
keys := make([]string, len(args))
|
||||||
for i, v := range args {
|
for i, v := range args {
|
||||||
keys[i] = string(v)
|
keys[i] = string(v)
|
||||||
@@ -281,11 +263,11 @@ func MGet(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeMultiBulkReply(result)
|
return reply.MakeMultiBulkReply(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MSetNX sets multi key-value in database, only if none of the given keys exist
|
// execMSetNX sets multi key-value in database, only if none of the given keys exist
|
||||||
func MSetNX(db *DB, args [][]byte) redis.Reply {
|
func execMSetNX(db *DB, args [][]byte) redis.Reply {
|
||||||
// parse args
|
// parse args
|
||||||
if len(args)%2 != 0 || len(args) == 0 {
|
if len(args)%2 != 0 {
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'msetnx' command")
|
return reply.MakeSyntaxErrReply()
|
||||||
}
|
}
|
||||||
size := len(args) / 2
|
size := len(args) / 2
|
||||||
values := make([][]byte, size)
|
values := make([][]byte, size)
|
||||||
@@ -314,11 +296,8 @@ func MSetNX(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeIntReply(1)
|
return reply.MakeIntReply(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSet sets value of a string-type key and returns its old value
|
// execGetSet sets value of a string-type key and returns its old value
|
||||||
func GetSet(db *DB, args [][]byte) redis.Reply {
|
func execGetSet(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) != 2 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'getset' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
value := args[1]
|
value := args[1]
|
||||||
|
|
||||||
@@ -336,11 +315,8 @@ func GetSet(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeBulkReply(old)
|
return reply.MakeBulkReply(old)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Incr increments the integer value of a key by one
|
// execIncr increments the integer value of a key by one
|
||||||
func Incr(db *DB, args [][]byte) redis.Reply {
|
func execIncr(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) != 1 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'incr' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
|
|
||||||
db.Lock(key)
|
db.Lock(key)
|
||||||
@@ -368,11 +344,8 @@ func Incr(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeIntReply(1)
|
return reply.MakeIntReply(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IncrBy increments the integer value of a key by given value
|
// execIncrBy increments the integer value of a key by given value
|
||||||
func IncrBy(db *DB, args [][]byte) redis.Reply {
|
func execIncrBy(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) != 2 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'incrby' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
rawDelta := string(args[1])
|
rawDelta := string(args[1])
|
||||||
delta, err := strconv.ParseInt(rawDelta, 10, 64)
|
delta, err := strconv.ParseInt(rawDelta, 10, 64)
|
||||||
@@ -406,11 +379,8 @@ func IncrBy(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeIntReply(delta)
|
return reply.MakeIntReply(delta)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IncrByFloat increments the float value of a key by given value
|
// execIncrByFloat increments the float value of a key by given value
|
||||||
func IncrByFloat(db *DB, args [][]byte) redis.Reply {
|
func execIncrByFloat(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) != 2 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'incrbyfloat' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
rawDelta := string(args[1])
|
rawDelta := string(args[1])
|
||||||
delta, err := decimal.NewFromString(rawDelta)
|
delta, err := decimal.NewFromString(rawDelta)
|
||||||
@@ -444,11 +414,8 @@ func IncrByFloat(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeBulkReply(args[1])
|
return reply.MakeBulkReply(args[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decr decrements the integer value of a key by one
|
// execDecr decrements the integer value of a key by one
|
||||||
func Decr(db *DB, args [][]byte) redis.Reply {
|
func execDecr(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) != 1 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'decr' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
|
|
||||||
db.Lock(key)
|
db.Lock(key)
|
||||||
@@ -477,11 +444,8 @@ func Decr(db *DB, args [][]byte) redis.Reply {
|
|||||||
return reply.MakeIntReply(-1)
|
return reply.MakeIntReply(-1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecrBy decrements the integer value of a key by onedecrement
|
// execDecrBy decrements the integer value of a key by onedecrement
|
||||||
func DecrBy(db *DB, args [][]byte) redis.Reply {
|
func execDecrBy(db *DB, args [][]byte) redis.Reply {
|
||||||
if len(args) != 2 {
|
|
||||||
return reply.MakeErrReply("ERR wrong number of arguments for 'decrby' command")
|
|
||||||
}
|
|
||||||
key := string(args[0])
|
key := string(args[0])
|
||||||
rawDelta := string(args[1])
|
rawDelta := string(args[1])
|
||||||
delta, err := strconv.ParseInt(rawDelta, 10, 64)
|
delta, err := strconv.ParseInt(rawDelta, 10, 64)
|
||||||
@@ -514,3 +478,22 @@ func DecrBy(db *DB, args [][]byte) redis.Reply {
|
|||||||
db.AddAof(makeAofCmd("decrby", args))
|
db.AddAof(makeAofCmd("decrby", args))
|
||||||
return reply.MakeIntReply(-delta)
|
return reply.MakeIntReply(-delta)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
RegisterCommand("Set", execSet, nil, -3)
|
||||||
|
RegisterCommand("SetNx", execSetNX, nil, 3)
|
||||||
|
RegisterCommand("SetEX", execSetEX, nil, 4)
|
||||||
|
RegisterCommand("PSetEX", execPSetEX, nil, 4)
|
||||||
|
RegisterCommand("MSet", execMSet, nil, -3)
|
||||||
|
RegisterCommand("MGet", execMGet, nil, -2)
|
||||||
|
RegisterCommand("MSetNX", execMSetNX, nil, -3)
|
||||||
|
RegisterCommand("Get", execGet, nil, 2)
|
||||||
|
RegisterCommand("MSet", execMSet, nil, -3)
|
||||||
|
RegisterCommand("GetSet", execGetSet, nil, 3)
|
||||||
|
RegisterCommand("MSet", execMSet, nil, -3)
|
||||||
|
RegisterCommand("Incr", execIncr, nil, 2)
|
||||||
|
RegisterCommand("IncrBy", execIncrBy, nil, 3)
|
||||||
|
RegisterCommand("IncrByFloat", execIncrByFloat, nil, 3)
|
||||||
|
RegisterCommand("Decr", execDecr, nil, 2)
|
||||||
|
RegisterCommand("DecrBy", execDecrBy, nil, 3)
|
||||||
|
}
|
||||||
|
118
string_test.go
118
string_test.go
@@ -13,55 +13,55 @@ import (
|
|||||||
var testDB = makeTestDB()
|
var testDB = makeTestDB()
|
||||||
|
|
||||||
func TestSet(t *testing.T) {
|
func TestSet(t *testing.T) {
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
key := utils2.RandString(10)
|
key := utils2.RandString(10)
|
||||||
value := utils2.RandString(10)
|
value := utils2.RandString(10)
|
||||||
|
|
||||||
// normal set
|
// normal set
|
||||||
Set(testDB, utils2.ToBytesList(key, value))
|
execSet(testDB, utils2.ToBytesList(key, value))
|
||||||
actual := Get(testDB, utils2.ToBytesList(key))
|
actual := execGet(testDB, utils2.ToBytesList(key))
|
||||||
expected := reply.MakeBulkReply([]byte(value))
|
expected := reply.MakeBulkReply([]byte(value))
|
||||||
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
|
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
|
||||||
t.Error("expected: " + string(expected.ToBytes()) + ", actual: " + string(actual.ToBytes()))
|
t.Error("expected: " + string(expected.ToBytes()) + ", actual: " + string(actual.ToBytes()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// set nx
|
// set nx
|
||||||
actual = Set(testDB, utils2.ToBytesList(key, value, "NX"))
|
actual = execSet(testDB, utils2.ToBytesList(key, value, "NX"))
|
||||||
if _, ok := actual.(*reply.NullBulkReply); !ok {
|
if _, ok := actual.(*reply.NullBulkReply); !ok {
|
||||||
t.Error("expected true actual false")
|
t.Error("expected true actual false")
|
||||||
}
|
}
|
||||||
|
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
key = utils2.RandString(10)
|
key = utils2.RandString(10)
|
||||||
value = utils2.RandString(10)
|
value = utils2.RandString(10)
|
||||||
Set(testDB, utils2.ToBytesList(key, value, "NX"))
|
execSet(testDB, utils2.ToBytesList(key, value, "NX"))
|
||||||
actual = Get(testDB, utils2.ToBytesList(key))
|
actual = execGet(testDB, utils2.ToBytesList(key))
|
||||||
expected = reply.MakeBulkReply([]byte(value))
|
expected = reply.MakeBulkReply([]byte(value))
|
||||||
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
|
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
|
||||||
t.Error("expected: " + string(expected.ToBytes()) + ", actual: " + string(actual.ToBytes()))
|
t.Error("expected: " + string(expected.ToBytes()) + ", actual: " + string(actual.ToBytes()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// set xx
|
// set xx
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
key = utils2.RandString(10)
|
key = utils2.RandString(10)
|
||||||
value = utils2.RandString(10)
|
value = utils2.RandString(10)
|
||||||
actual = Set(testDB, utils2.ToBytesList(key, value, "XX"))
|
actual = execSet(testDB, utils2.ToBytesList(key, value, "XX"))
|
||||||
if _, ok := actual.(*reply.NullBulkReply); !ok {
|
if _, ok := actual.(*reply.NullBulkReply); !ok {
|
||||||
t.Error("expected true actually false ")
|
t.Error("expected true actually false ")
|
||||||
}
|
}
|
||||||
|
|
||||||
Set(testDB, utils2.ToBytesList(key, value))
|
execSet(testDB, utils2.ToBytesList(key, value))
|
||||||
Set(testDB, utils2.ToBytesList(key, value, "XX"))
|
execSet(testDB, utils2.ToBytesList(key, value, "XX"))
|
||||||
actual = Get(testDB, utils2.ToBytesList(key))
|
actual = execGet(testDB, utils2.ToBytesList(key))
|
||||||
asserts.AssertBulkReply(t, actual, value)
|
asserts.AssertBulkReply(t, actual, value)
|
||||||
|
|
||||||
// set ex
|
// set ex
|
||||||
Del(testDB, utils2.ToBytesList(key))
|
testDB.Remove(key)
|
||||||
ttl := "1000"
|
ttl := "1000"
|
||||||
Set(testDB, utils2.ToBytesList(key, value, "EX", ttl))
|
execSet(testDB, utils2.ToBytesList(key, value, "EX", ttl))
|
||||||
actual = Get(testDB, utils2.ToBytesList(key))
|
actual = execGet(testDB, utils2.ToBytesList(key))
|
||||||
asserts.AssertBulkReply(t, actual, value)
|
asserts.AssertBulkReply(t, actual, value)
|
||||||
actual = TTL(testDB, utils2.ToBytesList(key))
|
actual = execTTL(testDB, utils2.ToBytesList(key))
|
||||||
intResult, ok := actual.(*reply.IntReply)
|
intResult, ok := actual.(*reply.IntReply)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Error(fmt.Sprintf("expected int reply, actually %s", actual.ToBytes()))
|
t.Error(fmt.Sprintf("expected int reply, actually %s", actual.ToBytes()))
|
||||||
@@ -73,12 +73,12 @@ func TestSet(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// set px
|
// set px
|
||||||
Del(testDB, utils2.ToBytesList(key))
|
testDB.Remove(key)
|
||||||
ttlPx := "1000000"
|
ttlPx := "1000000"
|
||||||
Set(testDB, utils2.ToBytesList(key, value, "PX", ttlPx))
|
execSet(testDB, utils2.ToBytesList(key, value, "PX", ttlPx))
|
||||||
actual = Get(testDB, utils2.ToBytesList(key))
|
actual = execGet(testDB, utils2.ToBytesList(key))
|
||||||
asserts.AssertBulkReply(t, actual, value)
|
asserts.AssertBulkReply(t, actual, value)
|
||||||
actual = TTL(testDB, utils2.ToBytesList(key))
|
actual = execTTL(testDB, utils2.ToBytesList(key))
|
||||||
intResult, ok = actual.(*reply.IntReply)
|
intResult, ok = actual.(*reply.IntReply)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Error(fmt.Sprintf("expected int reply, actually %s", actual.ToBytes()))
|
t.Error(fmt.Sprintf("expected int reply, actually %s", actual.ToBytes()))
|
||||||
@@ -91,17 +91,17 @@ func TestSet(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestSetNX(t *testing.T) {
|
func TestSetNX(t *testing.T) {
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
key := utils2.RandString(10)
|
key := utils2.RandString(10)
|
||||||
value := utils2.RandString(10)
|
value := utils2.RandString(10)
|
||||||
SetNX(testDB, utils2.ToBytesList(key, value))
|
execSetNX(testDB, utils2.ToBytesList(key, value))
|
||||||
actual := Get(testDB, utils2.ToBytesList(key))
|
actual := execGet(testDB, utils2.ToBytesList(key))
|
||||||
expected := reply.MakeBulkReply([]byte(value))
|
expected := reply.MakeBulkReply([]byte(value))
|
||||||
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
|
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
|
||||||
t.Error("expected: " + string(expected.ToBytes()) + ", actual: " + string(actual.ToBytes()))
|
t.Error("expected: " + string(expected.ToBytes()) + ", actual: " + string(actual.ToBytes()))
|
||||||
}
|
}
|
||||||
|
|
||||||
actual = SetNX(testDB, utils2.ToBytesList(key, value))
|
actual = execSetNX(testDB, utils2.ToBytesList(key, value))
|
||||||
expected2 := reply.MakeIntReply(int64(0))
|
expected2 := reply.MakeIntReply(int64(0))
|
||||||
if !utils.BytesEquals(actual.ToBytes(), expected2.ToBytes()) {
|
if !utils.BytesEquals(actual.ToBytes(), expected2.ToBytes()) {
|
||||||
t.Error("expected: " + string(expected2.ToBytes()) + ", actual: " + string(actual.ToBytes()))
|
t.Error("expected: " + string(expected2.ToBytes()) + ", actual: " + string(actual.ToBytes()))
|
||||||
@@ -109,15 +109,15 @@ func TestSetNX(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestSetEX(t *testing.T) {
|
func TestSetEX(t *testing.T) {
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
key := utils2.RandString(10)
|
key := utils2.RandString(10)
|
||||||
value := utils2.RandString(10)
|
value := utils2.RandString(10)
|
||||||
ttl := "1000"
|
ttl := "1000"
|
||||||
|
|
||||||
SetEX(testDB, utils2.ToBytesList(key, ttl, value))
|
execSetEX(testDB, utils2.ToBytesList(key, ttl, value))
|
||||||
actual := Get(testDB, utils2.ToBytesList(key))
|
actual := execGet(testDB, utils2.ToBytesList(key))
|
||||||
asserts.AssertBulkReply(t, actual, value)
|
asserts.AssertBulkReply(t, actual, value)
|
||||||
actual = TTL(testDB, utils2.ToBytesList(key))
|
actual = execTTL(testDB, utils2.ToBytesList(key))
|
||||||
intResult, ok := actual.(*reply.IntReply)
|
intResult, ok := actual.(*reply.IntReply)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Error(fmt.Sprintf("expected int reply, actually %s", actual.ToBytes()))
|
t.Error(fmt.Sprintf("expected int reply, actually %s", actual.ToBytes()))
|
||||||
@@ -130,15 +130,15 @@ func TestSetEX(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPSetEX(t *testing.T) {
|
func TestPSetEX(t *testing.T) {
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
key := utils2.RandString(10)
|
key := utils2.RandString(10)
|
||||||
value := utils2.RandString(10)
|
value := utils2.RandString(10)
|
||||||
ttl := "1000000"
|
ttl := "1000000"
|
||||||
|
|
||||||
PSetEX(testDB, utils2.ToBytesList(key, ttl, value))
|
execPSetEX(testDB, utils2.ToBytesList(key, ttl, value))
|
||||||
actual := Get(testDB, utils2.ToBytesList(key))
|
actual := execGet(testDB, utils2.ToBytesList(key))
|
||||||
asserts.AssertBulkReply(t, actual, value)
|
asserts.AssertBulkReply(t, actual, value)
|
||||||
actual = PTTL(testDB, utils2.ToBytesList(key))
|
actual = execPTTL(testDB, utils2.ToBytesList(key))
|
||||||
intResult, ok := actual.(*reply.IntReply)
|
intResult, ok := actual.(*reply.IntReply)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Error(fmt.Sprintf("expected int reply, actually %s", actual.ToBytes()))
|
t.Error(fmt.Sprintf("expected int reply, actually %s", actual.ToBytes()))
|
||||||
@@ -151,7 +151,7 @@ func TestPSetEX(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMSet(t *testing.T) {
|
func TestMSet(t *testing.T) {
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
size := 10
|
size := 10
|
||||||
keys := make([]string, size)
|
keys := make([]string, size)
|
||||||
values := make([][]byte, size)
|
values := make([][]byte, size)
|
||||||
@@ -162,8 +162,8 @@ func TestMSet(t *testing.T) {
|
|||||||
values[i] = []byte(value)
|
values[i] = []byte(value)
|
||||||
args = append(args, keys[i], value)
|
args = append(args, keys[i], value)
|
||||||
}
|
}
|
||||||
MSet(testDB, utils2.ToBytesList(args...))
|
execMSet(testDB, utils2.ToBytesList(args...))
|
||||||
actual := MGet(testDB, utils2.ToBytesList(keys...))
|
actual := execMGet(testDB, utils2.ToBytesList(keys...))
|
||||||
expected := reply.MakeMultiBulkReply(values)
|
expected := reply.MakeMultiBulkReply(values)
|
||||||
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
|
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
|
||||||
t.Error("expected: " + string(expected.ToBytes()) + ", actual: " + string(actual.ToBytes()))
|
t.Error("expected: " + string(expected.ToBytes()) + ", actual: " + string(actual.ToBytes()))
|
||||||
@@ -171,40 +171,40 @@ func TestMSet(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestIncr(t *testing.T) {
|
func TestIncr(t *testing.T) {
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
size := 10
|
size := 10
|
||||||
key := utils2.RandString(10)
|
key := utils2.RandString(10)
|
||||||
for i := 0; i < size; i++ {
|
for i := 0; i < size; i++ {
|
||||||
Incr(testDB, utils2.ToBytesList(key))
|
execIncr(testDB, utils2.ToBytesList(key))
|
||||||
actual := Get(testDB, utils2.ToBytesList(key))
|
actual := execGet(testDB, utils2.ToBytesList(key))
|
||||||
expected := reply.MakeBulkReply([]byte(strconv.FormatInt(int64(i+1), 10)))
|
expected := reply.MakeBulkReply([]byte(strconv.FormatInt(int64(i+1), 10)))
|
||||||
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
|
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
|
||||||
t.Error("expected: " + string(expected.ToBytes()) + ", actual: " + string(actual.ToBytes()))
|
t.Error("expected: " + string(expected.ToBytes()) + ", actual: " + string(actual.ToBytes()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i := 0; i < size; i++ {
|
for i := 0; i < size; i++ {
|
||||||
IncrBy(testDB, utils2.ToBytesList(key, "-1"))
|
execIncrBy(testDB, utils2.ToBytesList(key, "-1"))
|
||||||
actual := Get(testDB, utils2.ToBytesList(key))
|
actual := execGet(testDB, utils2.ToBytesList(key))
|
||||||
expected := reply.MakeBulkReply([]byte(strconv.FormatInt(int64(size-i-1), 10)))
|
expected := reply.MakeBulkReply([]byte(strconv.FormatInt(int64(size-i-1), 10)))
|
||||||
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
|
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
|
||||||
t.Error("expected: " + string(expected.ToBytes()) + ", actual: " + string(actual.ToBytes()))
|
t.Error("expected: " + string(expected.ToBytes()) + ", actual: " + string(actual.ToBytes()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
key = utils2.RandString(10)
|
key = utils2.RandString(10)
|
||||||
for i := 0; i < size; i++ {
|
for i := 0; i < size; i++ {
|
||||||
IncrBy(testDB, utils2.ToBytesList(key, "1"))
|
execIncrBy(testDB, utils2.ToBytesList(key, "1"))
|
||||||
actual := Get(testDB, utils2.ToBytesList(key))
|
actual := execGet(testDB, utils2.ToBytesList(key))
|
||||||
expected := reply.MakeBulkReply([]byte(strconv.FormatInt(int64(i+1), 10)))
|
expected := reply.MakeBulkReply([]byte(strconv.FormatInt(int64(i+1), 10)))
|
||||||
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
|
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
|
||||||
t.Error("expected: " + string(expected.ToBytes()) + ", actual: " + string(actual.ToBytes()))
|
t.Error("expected: " + string(expected.ToBytes()) + ", actual: " + string(actual.ToBytes()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Del(testDB, utils2.ToBytesList(key))
|
testDB.Remove(key)
|
||||||
for i := 0; i < size; i++ {
|
for i := 0; i < size; i++ {
|
||||||
IncrByFloat(testDB, utils2.ToBytesList(key, "-1.0"))
|
execIncrByFloat(testDB, utils2.ToBytesList(key, "-1.0"))
|
||||||
actual := Get(testDB, utils2.ToBytesList(key))
|
actual := execGet(testDB, utils2.ToBytesList(key))
|
||||||
expected := -i - 1
|
expected := -i - 1
|
||||||
bulk, ok := actual.(*reply.BulkReply)
|
bulk, ok := actual.(*reply.BulkReply)
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -224,18 +224,18 @@ func TestIncr(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDecr(t *testing.T) {
|
func TestDecr(t *testing.T) {
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
size := 10
|
size := 10
|
||||||
key := utils2.RandString(10)
|
key := utils2.RandString(10)
|
||||||
for i := 0; i < size; i++ {
|
for i := 0; i < size; i++ {
|
||||||
Decr(testDB, utils2.ToBytesList(key))
|
execDecr(testDB, utils2.ToBytesList(key))
|
||||||
actual := Get(testDB, utils2.ToBytesList(key))
|
actual := execGet(testDB, utils2.ToBytesList(key))
|
||||||
asserts.AssertBulkReply(t, actual, strconv.Itoa(-i-1))
|
asserts.AssertBulkReply(t, actual, strconv.Itoa(-i-1))
|
||||||
}
|
}
|
||||||
Del(testDB, utils2.ToBytesList(key))
|
testDB.Remove(key)
|
||||||
for i := 0; i < size; i++ {
|
for i := 0; i < size; i++ {
|
||||||
DecrBy(testDB, utils2.ToBytesList(key, "1"))
|
execDecrBy(testDB, utils2.ToBytesList(key, "1"))
|
||||||
actual := Get(testDB, utils2.ToBytesList(key))
|
actual := execGet(testDB, utils2.ToBytesList(key))
|
||||||
expected := -i - 1
|
expected := -i - 1
|
||||||
bulk, ok := actual.(*reply.BulkReply)
|
bulk, ok := actual.(*reply.BulkReply)
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -255,11 +255,11 @@ func TestDecr(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestGetSet(t *testing.T) {
|
func TestGetSet(t *testing.T) {
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
key := utils2.RandString(10)
|
key := utils2.RandString(10)
|
||||||
value := utils2.RandString(10)
|
value := utils2.RandString(10)
|
||||||
|
|
||||||
result := GetSet(testDB, utils2.ToBytesList(key, value))
|
result := execGetSet(testDB, utils2.ToBytesList(key, value))
|
||||||
_, ok := result.(*reply.NullBulkReply)
|
_, ok := result.(*reply.NullBulkReply)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Errorf("expect null bulk reply, get: %s", string(result.ToBytes()))
|
t.Errorf("expect null bulk reply, get: %s", string(result.ToBytes()))
|
||||||
@@ -267,23 +267,23 @@ func TestGetSet(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
value2 := utils2.RandString(10)
|
value2 := utils2.RandString(10)
|
||||||
result = GetSet(testDB, utils2.ToBytesList(key, value2))
|
result = execGetSet(testDB, utils2.ToBytesList(key, value2))
|
||||||
asserts.AssertBulkReply(t, result, value)
|
asserts.AssertBulkReply(t, result, value)
|
||||||
result = Get(testDB, utils2.ToBytesList(key))
|
result = execGet(testDB, utils2.ToBytesList(key))
|
||||||
asserts.AssertBulkReply(t, result, value2)
|
asserts.AssertBulkReply(t, result, value2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMSetNX(t *testing.T) {
|
func TestMSetNX(t *testing.T) {
|
||||||
FlushAll(testDB, [][]byte{})
|
execFlushAll(testDB, [][]byte{})
|
||||||
size := 10
|
size := 10
|
||||||
args := make([]string, 0, size*2)
|
args := make([]string, 0, size*2)
|
||||||
for i := 0; i < size; i++ {
|
for i := 0; i < size; i++ {
|
||||||
str := utils2.RandString(10)
|
str := utils2.RandString(10)
|
||||||
args = append(args, str, str)
|
args = append(args, str, str)
|
||||||
}
|
}
|
||||||
result := MSetNX(testDB, utils2.ToBytesList(args...))
|
result := execMSetNX(testDB, utils2.ToBytesList(args...))
|
||||||
asserts.AssertIntReply(t, result, 1)
|
asserts.AssertIntReply(t, result, 1)
|
||||||
|
|
||||||
result = MSetNX(testDB, utils2.ToBytesList(args[0:4]...))
|
result = execMSetNX(testDB, utils2.ToBytesList(args[0:4]...))
|
||||||
asserts.AssertIntReply(t, result, 0)
|
asserts.AssertIntReply(t, result, 0)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user