diff --git a/aof.go b/aof.go index 93ec7c5..7b1b338 100644 --- a/aof.go +++ b/aof.go @@ -19,11 +19,11 @@ import ( "time" ) -var pExpireAtCmd = []byte("PEXPIREAT") +var pExpireAtBytes = []byte("PEXPIREAT") func makeExpireCmd(key string, expireAt time.Time) *reply.MultiBulkReply { args := make([][]byte, 3) - args[0] = pExpireAtCmd + args[0] = pExpireAtBytes args[1] = []byte(key) args[2] = []byte(strconv.FormatInt(expireAt.UnixNano()/1e6, 10)) return reply.MakeMultiBulkReply(args) @@ -101,9 +101,10 @@ func (db *DB) loadAof(maxBytes int) { continue } cmd := strings.ToLower(string(r.Args[0])) - cmdFunc, ok := router[cmd] + command, ok := cmdTable[cmd] if ok { - cmdFunc(db, r.Args[1:]) + handler := command.executor + handler(db, r.Args[1:]) } } } diff --git a/aof_test.go b/aof_test.go index ee90ea1..84eefb7 100644 --- a/aof_test.go +++ b/aof_test.go @@ -34,31 +34,31 @@ func TestAof(t *testing.T) { for i := 0; i < size; i++ { key := strconv.Itoa(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) } for i := 0; i < size; i++ { key := strconv.Itoa(cursor) cursor++ - RPush(aofWriteDB, utils2.ToBytesList(key, utils2.RandString(8))) + execRPush(aofWriteDB, utils2.ToBytesList(key, utils2.RandString(8))) keys = append(keys, key) } for i := 0; i < size; i++ { key := strconv.Itoa(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) } for i := 0; i < size; i++ { key := strconv.Itoa(cursor) cursor++ - SAdd(aofWriteDB, utils2.ToBytesList(key, utils2.RandString(8))) + execSAdd(aofWriteDB, utils2.ToBytesList(key, utils2.RandString(8))) keys = append(keys, key) } for i := 0; i < size; i++ { key := strconv.Itoa(cursor) cursor++ - ZAdd(aofWriteDB, utils2.ToBytesList(key, "10", utils2.RandString(8))) + execZAdd(aofWriteDB, utils2.ToBytesList(key, "10", utils2.RandString(8))) keys = append(keys, key) } aofWriteDB.Close() // wait for aof finished @@ -105,44 +105,44 @@ func TestRewriteAOF(t *testing.T) { for i := 0; i < size; i++ { key := "str" + strconv.Itoa(cursor) cursor++ - Set(aofWriteDB, utils2.ToBytesList(key, utils2.RandString(8))) - Set(aofWriteDB, utils2.ToBytesList(key, utils2.RandString(8))) + execSet(aofWriteDB, utils2.ToBytesList(key, utils2.RandString(8))) + execSet(aofWriteDB, utils2.ToBytesList(key, utils2.RandString(8))) keys = append(keys, key) } // test ttl for i := 0; i < size; i++ { key := "str" + strconv.Itoa(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) } for i := 0; i < size; i++ { key := "list" + strconv.Itoa(cursor) cursor++ - RPush(aofWriteDB, utils2.ToBytesList(key, utils2.RandString(8))) - RPush(aofWriteDB, utils2.ToBytesList(key, utils2.RandString(8))) + execRPush(aofWriteDB, utils2.ToBytesList(key, utils2.RandString(8))) + execRPush(aofWriteDB, utils2.ToBytesList(key, utils2.RandString(8))) keys = append(keys, key) } for i := 0; i < size; i++ { key := "hash" + strconv.Itoa(cursor) cursor++ field := utils2.RandString(8) - HSet(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))) + execHSet(aofWriteDB, utils2.ToBytesList(key, field, utils2.RandString(8))) keys = append(keys, key) } for i := 0; i < size; i++ { key := "set" + strconv.Itoa(cursor) cursor++ member := utils2.RandString(8) - SAdd(aofWriteDB, utils2.ToBytesList(key, member)) - SAdd(aofWriteDB, utils2.ToBytesList(key, member)) + execSAdd(aofWriteDB, utils2.ToBytesList(key, member)) + execSAdd(aofWriteDB, utils2.ToBytesList(key, member)) keys = append(keys, key) } for i := 0; i < size; i++ { key := "zset" + strconv.Itoa(cursor) cursor++ - ZAdd(aofWriteDB, utils2.ToBytesList(key, "10", utils2.RandString(8))) + execZAdd(aofWriteDB, utils2.ToBytesList(key, "10", utils2.RandString(8))) keys = append(keys, key) } time.Sleep(time.Second) // wait for async goroutine finish its job @@ -167,7 +167,7 @@ func TestRewriteAOF(t *testing.T) { } } for _, key := range ttlKeys { - ret := TTL(aofReadDB, utils2.ToBytesList(key)) + ret := execTTL(aofReadDB, utils2.ToBytesList(key)) intResult, ok := ret.(*reply.IntReply) if !ok { t.Errorf("expected int reply, actually %s", ret.ToBytes()) diff --git a/cluster/rename_test.go b/cluster/rename_test.go index 03f7678..5c1fcc8 100644 --- a/cluster/rename_test.go +++ b/cluster/rename_test.go @@ -2,7 +2,6 @@ package cluster import ( "fmt" - "github.com/hdt3213/godis" "github.com/hdt3213/godis/lib/utils" "github.com/hdt3213/godis/redis/reply" "github.com/hdt3213/godis/redis/reply/asserts" @@ -11,22 +10,22 @@ import ( func TestRename(t *testing.T) { testDB := testCluster.db - godis.FlushAll(testDB, [][]byte{}) + testDB.Exec(nil, utils.ToBytesList("FlushALL")) key := utils.RandString(10) value := utils.RandString(10) 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)) if _, ok := result.(*reply.OkReply); !ok { t.Error("expect ok") return } - result = godis.Exists(testDB, utils.ToBytesList(key)) + result = testDB.Exec(nil, utils.ToBytesList("EXISTS", key)) 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) // check ttl - result = godis.TTL(testDB, utils.ToBytesList(newKey)) + result = testDB.Exec(nil, utils.ToBytesList("TTL", newKey)) intResult, ok := result.(*reply.IntReply) if !ok { 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) { testDB := testCluster.db - godis.FlushAll(testDB, [][]byte{}) + testDB.Exec(nil, utils.ToBytesList("FlushALL")) key := utils.RandString(10) value := utils.RandString(10) 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)) 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) - result = godis.Exists(testDB, utils.ToBytesList(newKey)) + result = testDB.Exec(nil, utils.ToBytesList("EXISTS", newKey)) + 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) if !ok { t.Error(fmt.Sprintf("expected int reply, actually %s", result.ToBytes())) diff --git a/db.go b/db.go index 32d48ff..1fb1183 100644 --- a/db.go +++ b/db.go @@ -2,7 +2,6 @@ package godis import ( - "fmt" "github.com/hdt3213/godis/config" "github.com/hdt3213/godis/datastruct/dict" "github.com/hdt3213/godis/datastruct/lock" @@ -12,17 +11,10 @@ import ( "github.com/hdt3213/godis/pubsub" "github.com/hdt3213/godis/redis/reply" "os" - "runtime/debug" - "strings" "sync" "time" ) -// DataEntity stores data bound to a key, including a string, list, hash, set and so on -type DataEntity struct { - Data interface{} -} - const ( dataDictSize = 1 << 16 ttlDictSize = 1 << 10 @@ -30,9 +22,6 @@ const ( 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 type DB struct { // key -> DataEntity @@ -43,7 +32,7 @@ type DB struct { // dict.Dict will ensure concurrent-safety of its method // use this mutex for complicated command only, eg. rpush, incr ... locker *lock.Locks - // stop all data access for FlushDB + // stop all data access for execFlushDB stopWorld sync.WaitGroup // handle publish/subscribe hub *pubsub.Hub @@ -60,7 +49,18 @@ type DB struct { 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 func MakeDB() *DB { @@ -102,49 +102,12 @@ func (db *DB) Close() { } } -// 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{} - } - }() - - cmd := strings.ToLower(string(cmdArgs[0])) - if cmd == "auth" { - return Auth(db, c, cmdArgs[1:]) +func validateArity(arity int, cmdArgs [][]byte) bool { + argNum := len(cmdArgs) + if arity >= 0 { + return argNum == arity } - if !isAuthenticated(c) { - 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 + return argNum >= -arity } /* ---- Data Access ----- */ @@ -263,7 +226,7 @@ func genExpireTask(key string) string { return "expire:" + key } -// Expire sets TTL of key +// Expire sets ttlCmd of key func (db *DB) Expire(key string, expireTime time.Time) { db.stopWorld.Wait() 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) { db.stopWorld.Wait() db.ttlMap.Remove(key) diff --git a/exec.go b/exec.go new file mode 100644 index 0000000..6fa0a10 --- /dev/null +++ b/exec.go @@ -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 +} diff --git a/geo.go b/geo.go index dd08d14..e062eb8 100644 --- a/geo.go +++ b/geo.go @@ -10,8 +10,8 @@ import ( "strings" ) -// GeoAdd add a location into SortedSet -func GeoAdd(db *DB, args [][]byte) redis.Reply { +// execGeoAdd add a location into SortedSet +func execGeoAdd(db *DB, args [][]byte) redis.Reply { if len(args) < 4 || len(args)%3 != 1 { 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)) } -// GeoPos returns location of a member -func GeoPos(db *DB, args [][]byte) redis.Reply { +// execGeoPos returns location of a member +func execGeoPos(db *DB, args [][]byte) redis.Reply { // parse args if len(args) < 1 { 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) } -// GeoDist returns the distance between two locations -func GeoDist(db *DB, args [][]byte) redis.Reply { +// execGeoDist returns the distance between two locations +func execGeoDist(db *DB, args [][]byte) redis.Reply { // parse args if len(args) != 3 && len(args) != 4 { 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") } -// GeoHash return geo-hash-code of given position -func GeoHash(db *DB, args [][]byte) redis.Reply { +// execGeoHash return geo-hash-code of given position +func execGeoHash(db *DB, args [][]byte) redis.Reply { // parse args if len(args) < 1 { 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) } -// GeoRadius returns members within max distance of given point -func GeoRadius(db *DB, args [][]byte) redis.Reply { +// execGeoRadius returns members within max distance of given point +func execGeoRadius(db *DB, args [][]byte) redis.Reply { // parse args if len(args) < 5 { 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) } -// GeoRadiusByMember returns members within max distance of given member's location -func GeoRadiusByMember(db *DB, args [][]byte) redis.Reply { +// execGeoRadiusByMember returns members within max distance of given member's location +func execGeoRadiusByMember(db *DB, args [][]byte) redis.Reply { // parse args if len(args) < 3 { 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) } + +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) +} diff --git a/geo_test.go b/geo_test.go index c5ec96c..1e73abf 100644 --- a/geo_test.go +++ b/geo_test.go @@ -10,52 +10,52 @@ import ( ) func TestGeoHash(t *testing.T) { - FlushDB(testDB, utils.ToBytesList()) + execFlushDB(testDB, utils.ToBytesList()) key := 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) - result = GeoHash(testDB, utils.ToBytesList(key, pos)) + result = execGeoHash(testDB, utils.ToBytesList(key, pos)) asserts.AssertMultiBulkReply(t, result, []string{"sqc8b49rnys00"}) } func TestGeoRadius(t *testing.T) { - FlushDB(testDB, utils.ToBytesList()) + execFlushDB(testDB, utils.ToBytesList()) key := utils.RandString(10) pos1 := utils.RandString(10) pos2 := utils.RandString(10) - GeoAdd(testDB, utils.ToBytesList(key, + execGeoAdd(testDB, utils.ToBytesList(key, "13.361389", "38.115556", pos1, "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) } func TestGeoRadiusByMember(t *testing.T) { - FlushDB(testDB, utils.ToBytesList()) + execFlushDB(testDB, utils.ToBytesList()) key := utils.RandString(10) pos1 := utils.RandString(10) pos2 := utils.RandString(10) pivot := utils.RandString(10) - GeoAdd(testDB, utils.ToBytesList(key, + execGeoAdd(testDB, utils.ToBytesList(key, "13.361389", "38.115556", pos1, "17.087269", "38.502669", pos2, "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) } func TestGeoPos(t *testing.T) { - FlushDB(testDB, utils.ToBytesList()) + execFlushDB(testDB, utils.ToBytesList()) key := utils.RandString(10) pos1 := utils.RandString(10) pos2 := utils.RandString(10) - GeoAdd(testDB, utils.ToBytesList(key, + execGeoAdd(testDB, utils.ToBytesList(key, "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" if string(result.ToBytes()) != expected { t.Error("test failed") @@ -63,15 +63,15 @@ func TestGeoPos(t *testing.T) { } func TestGeoDist(t *testing.T) { - FlushDB(testDB, utils.ToBytesList()) + execFlushDB(testDB, utils.ToBytesList()) key := utils.RandString(10) pos1 := utils.RandString(10) pos2 := utils.RandString(10) - GeoAdd(testDB, utils.ToBytesList(key, + execGeoAdd(testDB, utils.ToBytesList(key, "13.361389", "38.115556", pos1, "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) if !ok { 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) } - result = GeoDist(testDB, utils.ToBytesList(key, pos1, pos2, "m")) + result = execGeoDist(testDB, utils.ToBytesList(key, pos1, pos2, "m")) bulkReply, ok = result.(*reply.BulkReply) if !ok { t.Error(fmt.Sprintf("expected bulk reply, actually %s", result.ToBytes())) diff --git a/hash.go b/hash.go index cdd99c9..bf4a03c 100644 --- a/hash.go +++ b/hash.go @@ -36,12 +36,9 @@ func (db *DB) getOrInitDict(key string) (dict Dict.Dict, inited bool, errReply r return dict, inited, nil } -// HSet sets field in hash table -func HSet(db *DB, args [][]byte) redis.Reply { +// execHSet sets field in hash table +func execHSet(db *DB, args [][]byte) redis.Reply { // parse args - if len(args) != 3 { - return reply.MakeErrReply("ERR wrong number of arguments for 'hset' command") - } key := string(args[0]) field := string(args[1]) value := args[2] @@ -61,12 +58,9 @@ func HSet(db *DB, args [][]byte) redis.Reply { return reply.MakeIntReply(int64(result)) } -// HSetNX sets field in hash table only if field not exists -func HSetNX(db *DB, args [][]byte) redis.Reply { +// execHSetNX sets field in hash table only if field not exists +func execHSetNX(db *DB, args [][]byte) redis.Reply { // parse args - if len(args) != 3 { - return reply.MakeErrReply("ERR wrong number of arguments for 'hsetnx' command") - } key := string(args[0]) field := string(args[1]) value := args[2] @@ -87,12 +81,9 @@ func HSetNX(db *DB, args [][]byte) redis.Reply { return reply.MakeIntReply(int64(result)) } -// HGet gets field value of hash table -func HGet(db *DB, args [][]byte) redis.Reply { +// execHGet gets field value of hash table +func execHGet(db *DB, args [][]byte) redis.Reply { // parse args - if len(args) != 2 { - return reply.MakeErrReply("ERR wrong number of arguments for 'hget' command") - } key := string(args[0]) field := string(args[1]) @@ -116,12 +107,9 @@ func HGet(db *DB, args [][]byte) redis.Reply { return reply.MakeBulkReply(value) } -// HExists checks if a hash field exists -func HExists(db *DB, args [][]byte) redis.Reply { +// execHExists checks if a hash field exists +func execHExists(db *DB, args [][]byte) redis.Reply { // parse args - if len(args) != 2 { - return reply.MakeErrReply("ERR wrong number of arguments for 'hexists' command") - } key := string(args[0]) field := string(args[1]) @@ -144,12 +132,9 @@ func HExists(db *DB, args [][]byte) redis.Reply { return reply.MakeIntReply(0) } -// HDel deletes a hash field -func HDel(db *DB, args [][]byte) redis.Reply { +// execHDel deletes a hash field +func execHDel(db *DB, args [][]byte) redis.Reply { // parse args - if len(args) < 2 { - return reply.MakeErrReply("ERR wrong number of arguments for 'hdel' command") - } key := string(args[0]) fields := make([]string, len(args)-1) fieldArgs := args[1:] @@ -184,12 +169,9 @@ func HDel(db *DB, args [][]byte) redis.Reply { return reply.MakeIntReply(int64(deleted)) } -// HLen gets number of fields in hash table -func HLen(db *DB, args [][]byte) redis.Reply { +// execHLen gets number of fields in hash table +func execHLen(db *DB, args [][]byte) redis.Reply { // parse args - if len(args) != 1 { - return reply.MakeErrReply("ERR wrong number of arguments for 'hlen' command") - } key := string(args[0]) db.RLock(key) @@ -205,11 +187,11 @@ func HLen(db *DB, args [][]byte) redis.Reply { return reply.MakeIntReply(int64(dict.Len())) } -// HMSet sets multi fields in hash table -func HMSet(db *DB, args [][]byte) redis.Reply { +// execHMSet sets multi fields in hash table +func execHMSet(db *DB, args [][]byte) redis.Reply { // parse args - if len(args) < 3 || len(args)%2 != 1 { - return reply.MakeErrReply("ERR wrong number of arguments for 'hmset' command") + if len(args)%2 != 1 { + return reply.MakeSyntaxErrReply() } key := string(args[0]) size := (len(args) - 1) / 2 @@ -241,9 +223,6 @@ func HMSet(db *DB, args [][]byte) redis.Reply { // HMGet gets multi fields in hash table 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]) size := len(args) - 1 fields := make([]string, size) @@ -276,11 +255,8 @@ func HMGet(db *DB, args [][]byte) redis.Reply { return reply.MakeMultiBulkReply(result) } -// HKeys gets all field names in hash table -func HKeys(db *DB, args [][]byte) redis.Reply { - if len(args) != 1 { - return reply.MakeErrReply("ERR wrong number of arguments for 'hkeys' command") - } +// execHKeys gets all field names in hash table +func execHKeys(db *DB, args [][]byte) redis.Reply { key := string(args[0]) db.RLock(key) @@ -304,11 +280,8 @@ func HKeys(db *DB, args [][]byte) redis.Reply { return reply.MakeMultiBulkReply(fields[:i]) } -// HVals gets all field value in hash table -func HVals(db *DB, args [][]byte) redis.Reply { - if len(args) != 1 { - return reply.MakeErrReply("ERR wrong number of arguments for 'hvals' command") - } +// execHVals gets all field value in hash table +func execHVals(db *DB, args [][]byte) redis.Reply { key := string(args[0]) db.RLock(key) @@ -333,11 +306,8 @@ func HVals(db *DB, args [][]byte) redis.Reply { return reply.MakeMultiBulkReply(values[:i]) } -// HGetAll gets all key-value entries in hash table -func HGetAll(db *DB, args [][]byte) redis.Reply { - if len(args) != 1 { - return reply.MakeErrReply("ERR wrong number of arguments for 'hgetAll' command") - } +// execHGetAll gets all key-value entries in hash table +func execHGetAll(db *DB, args [][]byte) redis.Reply { key := string(args[0]) db.RLock(key) @@ -365,11 +335,8 @@ func HGetAll(db *DB, args [][]byte) redis.Reply { return reply.MakeMultiBulkReply(result[:i]) } -// HIncrBy increments the integer value of a hash field by the given number -func HIncrBy(db *DB, args [][]byte) redis.Reply { - if len(args) != 3 { - return reply.MakeErrReply("ERR wrong number of arguments for 'hincrby' command") - } +// execHIncrBy increments the integer value of a hash field by the given number +func execHIncrBy(db *DB, args [][]byte) redis.Reply { key := string(args[0]) field := string(args[1]) rawDelta := string(args[2]) @@ -403,11 +370,8 @@ func HIncrBy(db *DB, args [][]byte) redis.Reply { return reply.MakeBulkReply(bytes) } -// HIncrByFloat increments the float value of a hash field by the given number -func HIncrByFloat(db *DB, args [][]byte) redis.Reply { - if len(args) != 3 { - return reply.MakeErrReply("ERR wrong number of arguments for 'hincrbyfloat' command") - } +// execHIncrByFloat increments the float value of a hash field by the given number +func execHIncrByFloat(db *DB, args [][]byte) redis.Reply { key := string(args[0]) field := string(args[1]) rawDelta := string(args[2]) @@ -440,3 +404,19 @@ func HIncrByFloat(db *DB, args [][]byte) redis.Reply { db.AddAof(makeAofCmd("hincrbyfloat", args)) 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) +} diff --git a/hash_test.go b/hash_test.go index 71bc543..ed2ec12 100644 --- a/hash_test.go +++ b/hash_test.go @@ -11,7 +11,7 @@ import ( ) func TestHSet(t *testing.T) { - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) size := 100 // test hset @@ -21,7 +21,7 @@ func TestHSet(t *testing.T) { value := utils2.RandString(10) field := strconv.Itoa(i) 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) { t.Error(fmt.Sprintf("expected %d, actually %d", 1, intResult.Code)) } @@ -29,26 +29,26 @@ func TestHSet(t *testing.T) { // test hget and hexists for field, v := range values { - actual := HGet(testDB, utils2.ToBytesList(key, field)) + actual := execHGet(testDB, utils2.ToBytesList(key, field)) expected := reply.MakeBulkReply(v) if !utils.BytesEquals(actual.ToBytes(), expected.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) { t.Error(fmt.Sprintf("expected %d, actually %d", 1, intResult.Code)) } } // test hlen - actual := HLen(testDB, utils2.ToBytesList(key)) + actual := execHLen(testDB, utils2.ToBytesList(key)) if intResult, _ := actual.(*reply.IntReply); intResult.Code != int64(len(values)) { t.Error(fmt.Sprintf("expected %d, actually %d", len(values), intResult.Code)) } } func TestHDel(t *testing.T) { - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) size := 100 // set values @@ -58,25 +58,25 @@ func TestHDel(t *testing.T) { value := utils2.RandString(10) field := strconv.Itoa(i) fields[i] = field - HSet(testDB, utils2.ToBytesList(key, field, value)) + execHSet(testDB, utils2.ToBytesList(key, field, value)) } // test HDel args := []string{key} 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)) { 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) { t.Error(fmt.Sprintf("expected %d, actually %d", 0, intResult.Code)) } } func TestHMSet(t *testing.T) { - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) size := 100 // test hset @@ -89,7 +89,7 @@ func TestHMSet(t *testing.T) { values[i] = utils2.RandString(10) 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 { 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) { - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) size := 100 key := utils2.RandString(10) fields := make([]string, size) @@ -118,11 +118,11 @@ func TestHGetAll(t *testing.T) { all = append(all, fields[i], value) valueMap[fields[i]] = value valueSet[value] = true - HSet(testDB, utils2.ToBytesList(key, fields[i], value)) + execHSet(testDB, utils2.ToBytesList(key, fields[i], value)) } // test HGetAll - result := HGetAll(testDB, utils2.ToBytesList(key)) + result := execHGetAll(testDB, utils2.ToBytesList(key)) multiBulk, ok := result.(*reply.MultiBulkReply) if !ok { t.Error(fmt.Sprintf("expected MultiBulkReply, actually %s", string(result.ToBytes()))) @@ -144,7 +144,7 @@ func TestHGetAll(t *testing.T) { } // test HKeys - result = HKeys(testDB, utils2.ToBytesList(key)) + result = execHKeys(testDB, utils2.ToBytesList(key)) multiBulk, ok = result.(*reply.MultiBulkReply) if !ok { t.Error(fmt.Sprintf("expected MultiBulkReply, actually %s", string(result.ToBytes()))) @@ -160,7 +160,7 @@ func TestHGetAll(t *testing.T) { } // test HVals - result = HVals(testDB, utils2.ToBytesList(key)) + result = execHVals(testDB, utils2.ToBytesList(key)) multiBulk, ok = result.(*reply.MultiBulkReply) if !ok { 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) { - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) 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" { 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" { 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" { 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" { t.Error(fmt.Sprintf("expected %s, actually %s", "2.4", string(bulkResult.Arg))) } } func TestHSetNX(t *testing.T) { - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) key := utils2.RandString(10) field := 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) 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) - result = HGet(testDB, utils2.ToBytesList(key, field)) + result = execHGet(testDB, utils2.ToBytesList(key, field)) asserts.AssertBulkReply(t, result, value) } diff --git a/keys.go b/keys.go index a226150..d5be7e2 100644 --- a/keys.go +++ b/keys.go @@ -12,11 +12,8 @@ import ( "time" ) -// Del removes a key from db -func Del(db *DB, args [][]byte) redis.Reply { - if len(args) == 0 { - return reply.MakeErrReply("ERR wrong number of arguments for 'del' command") - } +// execDel removes a key from db +func execDel(db *DB, args [][]byte) redis.Reply { keys := make([]string, len(args)) for i, v := range args { keys[i] = string(v) @@ -32,44 +29,35 @@ func Del(db *DB, args [][]byte) redis.Reply { return reply.MakeIntReply(int64(deleted)) } -// Exists checks if a is existed in db -func Exists(db *DB, args [][]byte) redis.Reply { - if len(args) != 1 { - return reply.MakeErrReply("ERR wrong number of arguments for 'exists' command") +// execExists checks if a is existed in db +func execExists(db *DB, args [][]byte) redis.Reply { + result := int64(0) + for _, arg := range args { + key := string(arg) + _, exists := db.GetEntity(key) + if exists { + result++ + } } - key := string(args[0]) - _, exists := db.GetEntity(key) - if exists { - return reply.MakeIntReply(1) - } - return reply.MakeIntReply(0) + return reply.MakeIntReply(result) } -// FlushDB removes all data in current db -func FlushDB(db *DB, args [][]byte) redis.Reply { - if len(args) != 0 { - return reply.MakeErrReply("ERR wrong number of arguments for 'flushdb' command") - } +// execFlushDB removes all data in current db +func execFlushDB(db *DB, args [][]byte) redis.Reply { db.Flush() db.AddAof(makeAofCmd("flushdb", args)) return &reply.OkReply{} } -// FlushAll removes all data in all db -func FlushAll(db *DB, args [][]byte) redis.Reply { - if len(args) != 0 { - return reply.MakeErrReply("ERR wrong number of arguments for 'flushall' command") - } +// execFlushAll removes all data in all db +func execFlushAll(db *DB, args [][]byte) redis.Reply { db.Flush() db.AddAof(makeAofCmd("flushdb", args)) return &reply.OkReply{} } -// Type returns the type of entity, including: string, list, hash, set and zset -func Type(db *DB, args [][]byte) redis.Reply { - if len(args) != 1 { - return reply.MakeErrReply("ERR wrong number of arguments for 'type' command") - } +// execType returns the type of entity, including: string, list, hash, set and zset +func execType(db *DB, args [][]byte) redis.Reply { key := string(args[0]) entity, exists := db.GetEntity(key) if !exists { @@ -90,8 +78,8 @@ func Type(db *DB, args [][]byte) redis.Reply { return &reply.UnknownErrReply{} } -// Rename a key -func Rename(db *DB, args [][]byte) redis.Reply { +// execRename a key +func execRename(db *DB, args [][]byte) redis.Reply { if len(args) != 2 { 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{} } -// RenameNx a key, only if the new key does not exist -func RenameNx(db *DB, args [][]byte) redis.Reply { - if len(args) != 2 { - return reply.MakeErrReply("ERR wrong number of arguments for 'renamenx' command") - } +// execRenameNx a key, only if the new key does not exist +func execRenameNx(db *DB, args [][]byte) redis.Reply { src := string(args[0]) dest := string(args[1]) @@ -151,11 +136,8 @@ func RenameNx(db *DB, args [][]byte) redis.Reply { return reply.MakeIntReply(1) } -// Expire sets a key's time to live in seconds -func Expire(db *DB, args [][]byte) redis.Reply { - if len(args) != 2 { - return reply.MakeErrReply("ERR wrong number of arguments for 'expire' command") - } +// execExpire sets a key's time to live in seconds +func execExpire(db *DB, args [][]byte) redis.Reply { key := string(args[0]) 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) } -// ExpireAt sets a key's expiration in unix timestamp -func ExpireAt(db *DB, args [][]byte) redis.Reply { - if len(args) != 2 { - return reply.MakeErrReply("ERR wrong number of arguments for 'expireat' command") - } +// execExpireAt sets a key's expiration in unix timestamp +func execExpireAt(db *DB, args [][]byte) redis.Reply { key := string(args[0]) 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) } -// PExpire sets a key's time to live in milliseconds -func PExpire(db *DB, args [][]byte) redis.Reply { - if len(args) != 2 { - return reply.MakeErrReply("ERR wrong number of arguments for 'pexpire' command") - } +// execPExpire sets a key's time to live in milliseconds +func execPExpire(db *DB, args [][]byte) redis.Reply { key := string(args[0]) 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) } -// PExpireAt sets a key's expiration in unix timestamp specified in milliseconds -func PExpireAt(db *DB, args [][]byte) redis.Reply { - if len(args) != 2 { - return reply.MakeErrReply("ERR wrong number of arguments for 'pexpireat' command") - } +// execPExpireAt sets a key's expiration in unix timestamp specified in milliseconds +func execPExpireAt(db *DB, args [][]byte) redis.Reply { key := string(args[0]) 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) } -// TTL returns a key's time to live in seconds -func TTL(db *DB, args [][]byte) redis.Reply { - if len(args) != 1 { - return reply.MakeErrReply("ERR wrong number of arguments for 'ttl' command") - } +// execTTL returns a key's time to live in seconds +func execTTL(db *DB, args [][]byte) redis.Reply { key := string(args[0]) _, exists := db.GetEntity(key) if !exists { @@ -266,11 +236,8 @@ func TTL(db *DB, args [][]byte) redis.Reply { return reply.MakeIntReply(int64(ttl / time.Second)) } -// PTTL returns a key's time to live in milliseconds -func PTTL(db *DB, args [][]byte) redis.Reply { - if len(args) != 1 { - return reply.MakeErrReply("ERR wrong number of arguments for 'pttl' command") - } +// execPTTL returns a key's time to live in milliseconds +func execPTTL(db *DB, args [][]byte) redis.Reply { key := string(args[0]) _, exists := db.GetEntity(key) if !exists { @@ -286,11 +253,8 @@ func PTTL(db *DB, args [][]byte) redis.Reply { return reply.MakeIntReply(int64(ttl / time.Millisecond)) } -// Persist removes expiration from a key -func Persist(db *DB, args [][]byte) redis.Reply { - if len(args) != 1 { - return reply.MakeErrReply("ERR wrong number of arguments for 'persist' command") - } +// execPersist removes expiration from a key +func execPersist(db *DB, args [][]byte) redis.Reply { key := string(args[0]) _, exists := db.GetEntity(key) if !exists { @@ -309,18 +273,12 @@ func Persist(db *DB, args [][]byte) redis.Reply { // BGRewriteAOF asynchronously rewrites Append-Only-File 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() return reply.MakeStatusReply("Background append only file rewriting started") } -// Keys returns all keys matching the given pattern -func Keys(db *DB, args [][]byte) redis.Reply { - if len(args) != 1 { - return reply.MakeErrReply("ERR wrong number of arguments for 'keys' command") - } +// execKeys returns all keys matching the given pattern +func execKeys(db *DB, args [][]byte) redis.Reply { pattern := wildcard.CompilePattern(string(args[0])) result := make([][]byte, 0) 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) } + +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) +} diff --git a/keys_test.go b/keys_test.go index 37b3560..16a1e26 100644 --- a/keys_test.go +++ b/keys_test.go @@ -11,65 +11,65 @@ import ( ) func TestExists(t *testing.T) { - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) key := utils.RandString(10) value := utils.RandString(10) - Set(testDB, utils.ToBytesList(key, value)) - result := Exists(testDB, utils.ToBytesList(key)) + execSet(testDB, utils.ToBytesList(key, value)) + result := execExists(testDB, utils.ToBytesList(key)) asserts.AssertIntReply(t, result, 1) key = utils.RandString(10) - result = Exists(testDB, utils.ToBytesList(key)) + result = execExists(testDB, utils.ToBytesList(key)) asserts.AssertIntReply(t, result, 0) } func TestType(t *testing.T) { - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) key := utils.RandString(10) value := utils.RandString(10) - Set(testDB, utils.ToBytesList(key, value)) - result := Type(testDB, utils.ToBytesList(key)) + execSet(testDB, utils.ToBytesList(key, value)) + result := execType(testDB, utils.ToBytesList(key)) asserts.AssertStatusReply(t, result, "string") - Del(testDB, utils.ToBytesList(key)) - result = Type(testDB, utils.ToBytesList(key)) + testDB.Remove(key) + result = execType(testDB, utils.ToBytesList(key)) asserts.AssertStatusReply(t, result, "none") - RPush(testDB, utils.ToBytesList(key, value)) - result = Type(testDB, utils.ToBytesList(key)) + execRPush(testDB, utils.ToBytesList(key, value)) + result = execType(testDB, utils.ToBytesList(key)) asserts.AssertStatusReply(t, result, "list") - Del(testDB, utils.ToBytesList(key)) - HSet(testDB, utils.ToBytesList(key, key, value)) - result = Type(testDB, utils.ToBytesList(key)) + testDB.Remove(key) + execHSet(testDB, utils.ToBytesList(key, key, value)) + result = execType(testDB, utils.ToBytesList(key)) asserts.AssertStatusReply(t, result, "hash") - Del(testDB, utils.ToBytesList(key)) - SAdd(testDB, utils.ToBytesList(key, value)) - result = Type(testDB, utils.ToBytesList(key)) + testDB.Remove(key) + execSAdd(testDB, utils.ToBytesList(key, value)) + result = execType(testDB, utils.ToBytesList(key)) asserts.AssertStatusReply(t, result, "set") - Del(testDB, utils.ToBytesList(key)) - ZAdd(testDB, utils.ToBytesList(key, "1", value)) - result = Type(testDB, utils.ToBytesList(key)) + testDB.Remove(key) + execZAdd(testDB, utils.ToBytesList(key, "1", value)) + result = execType(testDB, utils.ToBytesList(key)) asserts.AssertStatusReply(t, result, "zset") } func TestRename(t *testing.T) { - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) key := utils.RandString(10) value := utils.RandString(10) newKey := key + utils.RandString(2) - Set(testDB, utils.ToBytesList(key, value, "ex", "1000")) - result := Rename(testDB, utils.ToBytesList(key, newKey)) + execSet(testDB, utils.ToBytesList(key, value, "ex", "1000")) + result := execRename(testDB, utils.ToBytesList(key, newKey)) if _, ok := result.(*reply.OkReply); !ok { t.Error("expect ok") return } - result = Exists(testDB, utils.ToBytesList(key)) + result = execExists(testDB, utils.ToBytesList(key)) asserts.AssertIntReply(t, result, 0) - result = Exists(testDB, utils.ToBytesList(newKey)) + result = execExists(testDB, utils.ToBytesList(newKey)) asserts.AssertIntReply(t, result, 1) // check ttl - result = TTL(testDB, utils.ToBytesList(newKey)) + result = execTTL(testDB, utils.ToBytesList(newKey)) intResult, ok := result.(*reply.IntReply) if !ok { 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) { - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) key := utils.RandString(10) value := utils.RandString(10) newKey := key + utils.RandString(2) - Set(testDB, utils.ToBytesList(key, value, "ex", "1000")) - result := RenameNx(testDB, utils.ToBytesList(key, newKey)) + execSet(testDB, utils.ToBytesList(key, value, "ex", "1000")) + result := execRenameNx(testDB, utils.ToBytesList(key, newKey)) asserts.AssertIntReply(t, result, 1) - result = Exists(testDB, utils.ToBytesList(key)) + result = execExists(testDB, utils.ToBytesList(key)) asserts.AssertIntReply(t, result, 0) - result = Exists(testDB, utils.ToBytesList(newKey)) + result = execExists(testDB, utils.ToBytesList(newKey)) asserts.AssertIntReply(t, result, 1) - result = TTL(testDB, utils.ToBytesList(newKey)) + result = execTTL(testDB, utils.ToBytesList(newKey)) intResult, ok := result.(*reply.IntReply) if !ok { 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) { - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) key := 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) - result = TTL(testDB, utils.ToBytesList(key)) + result = execTTL(testDB, utils.ToBytesList(key)) intResult, ok := result.(*reply.IntReply) if !ok { t.Error(fmt.Sprintf("expected int reply, actually %s", result.ToBytes())) @@ -124,14 +124,14 @@ func TestTTL(t *testing.T) { return } - result = Persist(testDB, utils.ToBytesList(key)) + result = execPersist(testDB, utils.ToBytesList(key)) asserts.AssertIntReply(t, result, 1) - result = TTL(testDB, utils.ToBytesList(key)) + result = execTTL(testDB, utils.ToBytesList(key)) asserts.AssertIntReply(t, result, -1) - result = PExpire(testDB, utils.ToBytesList(key, "1000000")) + result = execPExpire(testDB, utils.ToBytesList(key, "1000000")) asserts.AssertIntReply(t, result, 1) - result = PTTL(testDB, utils.ToBytesList(key)) + result = execPTTL(testDB, utils.ToBytesList(key)) intResult, ok = result.(*reply.IntReply) if !ok { 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) { - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) key := 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() - 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) - result = TTL(testDB, utils.ToBytesList(key)) + result = execTTL(testDB, utils.ToBytesList(key)) intResult, ok := result.(*reply.IntReply) if !ok { 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() - 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) - result = TTL(testDB, utils.ToBytesList(key)) + result = execTTL(testDB, utils.ToBytesList(key)) intResult, ok = result.(*reply.IntReply) if !ok { 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) { - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) key := utils.RandString(10) value := utils.RandString(10) - Set(testDB, utils.ToBytesList(key, value)) - Set(testDB, utils.ToBytesList("a:"+key, value)) - Set(testDB, utils.ToBytesList("b:"+key, value)) + execSet(testDB, utils.ToBytesList(key, value)) + execSet(testDB, utils.ToBytesList("a:"+key, value)) + execSet(testDB, utils.ToBytesList("b:"+key, value)) - result := Keys(testDB, utils.ToBytesList("*")) + result := execKeys(testDB, utils.ToBytesList("*")) asserts.AssertMultiBulkReplySize(t, result, 3) - result = Keys(testDB, utils.ToBytesList("a:*")) + result = execKeys(testDB, utils.ToBytesList("a:*")) asserts.AssertMultiBulkReplySize(t, result, 1) - result = Keys(testDB, utils.ToBytesList("?:*")) + result = execKeys(testDB, utils.ToBytesList("?:*")) asserts.AssertMultiBulkReplySize(t, result, 2) } diff --git a/list.go b/list.go index 72e1a29..1b27ada 100644 --- a/list.go +++ b/list.go @@ -35,12 +35,9 @@ func (db *DB) getOrInitList(key string) (list *List.LinkedList, isNew bool, errR return list, isNew, nil } -// LIndex gets element of list at given list -func LIndex(db *DB, args [][]byte) redis.Reply { +// execLIndex gets element of list at given list +func execLIndex(db *DB, args [][]byte) redis.Reply { // parse args - if len(args) != 2 { - return reply.MakeErrReply("ERR wrong number of arguments for 'lindex' command") - } key := string(args[0]) index64, err := strconv.ParseInt(string(args[1]), 10, 64) if err != nil { @@ -73,12 +70,9 @@ func LIndex(db *DB, args [][]byte) redis.Reply { return reply.MakeBulkReply(val) } -// LLen gets length of list -func LLen(db *DB, args [][]byte) redis.Reply { +// execLLen gets length of list +func execLLen(db *DB, args [][]byte) redis.Reply { // parse args - if len(args) != 1 { - return reply.MakeErrReply("ERR wrong number of arguments for 'llen' command") - } key := string(args[0]) db.RLock(key) @@ -96,12 +90,9 @@ func LLen(db *DB, args [][]byte) redis.Reply { return reply.MakeIntReply(size) } -// LPop removes the first element of list, and return it -func LPop(db *DB, args [][]byte) redis.Reply { +// execLPop removes the first element of list, and return it +func execLPop(db *DB, args [][]byte) redis.Reply { // parse args - if len(args) != 1 { - return reply.MakeErrReply("ERR wrong number of arguments for 'lindex' command") - } key := string(args[0]) // lock @@ -125,11 +116,8 @@ func LPop(db *DB, args [][]byte) redis.Reply { return reply.MakeBulkReply(val) } -// LPush inserts element at head of list -func LPush(db *DB, args [][]byte) redis.Reply { - if len(args) < 2 { - return reply.MakeErrReply("ERR wrong number of arguments for 'lpush' command") - } +// execLPush inserts element at head of list +func execLPush(db *DB, args [][]byte) redis.Reply { key := string(args[0]) values := args[1:] @@ -152,11 +140,8 @@ func LPush(db *DB, args [][]byte) redis.Reply { return reply.MakeIntReply(int64(list.Len())) } -// LPushX inserts element at head of list, only if list exists -func LPushX(db *DB, args [][]byte) redis.Reply { - if len(args) < 2 { - return reply.MakeErrReply("ERR wrong number of arguments for 'lpushx' command") - } +// execLPushX inserts element at head of list, only if list exists +func execLPushX(db *DB, args [][]byte) redis.Reply { key := string(args[0]) values := args[1:] @@ -181,12 +166,9 @@ func LPushX(db *DB, args [][]byte) redis.Reply { return reply.MakeIntReply(int64(list.Len())) } -// LRange gets elements of list in given range -func LRange(db *DB, args [][]byte) redis.Reply { +// execLRange gets elements of list in given range +func execLRange(db *DB, args [][]byte) redis.Reply { // parse args - if len(args) != 3 { - return reply.MakeErrReply("ERR wrong number of arguments for 'lrange' command") - } key := string(args[0]) start64, err := strconv.ParseInt(string(args[1]), 10, 64) if err != nil { @@ -244,12 +226,9 @@ func LRange(db *DB, args [][]byte) redis.Reply { return reply.MakeMultiBulkReply(result) } -// LRem removes element of list at specified index -func LRem(db *DB, args [][]byte) redis.Reply { +// execLRem removes element of list at specified index +func execLRem(db *DB, args [][]byte) redis.Reply { // parse args - if len(args) != 3 { - return reply.MakeErrReply("ERR wrong number of arguments for 'lrem' command") - } key := string(args[0]) count64, err := strconv.ParseInt(string(args[1]), 10, 64) if err != nil { @@ -290,12 +269,9 @@ func LRem(db *DB, args [][]byte) redis.Reply { return reply.MakeIntReply(int64(removed)) } -// LSet puts element at specified index of list -func LSet(db *DB, args [][]byte) redis.Reply { +// execLSet puts element at specified index of list +func execLSet(db *DB, args [][]byte) redis.Reply { // parse args - if len(args) != 3 { - return reply.MakeErrReply("ERR wrong number of arguments for 'lset' command") - } key := string(args[0]) index64, err := strconv.ParseInt(string(args[1]), 10, 64) if err != nil { @@ -331,12 +307,9 @@ func LSet(db *DB, args [][]byte) redis.Reply { return &reply.OkReply{} } -// RPop removes last element of list then return it -func RPop(db *DB, args [][]byte) redis.Reply { +// execRPop removes last element of list then return it +func execRPop(db *DB, args [][]byte) redis.Reply { // parse args - if len(args) != 1 { - return reply.MakeErrReply("ERR wrong number of arguments for 'rpop' command") - } key := string(args[0]) // lock @@ -360,11 +333,8 @@ func RPop(db *DB, args [][]byte) redis.Reply { return reply.MakeBulkReply(val) } -// RPopLPush pops last element of list-A then insert it to the head of list-B -func RPopLPush(db *DB, args [][]byte) redis.Reply { - if len(args) != 2 { - return reply.MakeErrReply("ERR wrong number of arguments for 'rpoplpush' command") - } +// execRPopLPush pops last element of list-A then insert it to the head of list-B +func execRPopLPush(db *DB, args [][]byte) redis.Reply { sourceKey := string(args[0]) destKey := string(args[1]) @@ -399,12 +369,9 @@ func RPopLPush(db *DB, args [][]byte) redis.Reply { return reply.MakeBulkReply(val) } -// RPush inserts element at last of list -func RPush(db *DB, args [][]byte) redis.Reply { +// execRPush inserts element at last of list +func execRPush(db *DB, args [][]byte) redis.Reply { // parse args - if len(args) < 2 { - return reply.MakeErrReply("ERR wrong number of arguments for 'rpush' command") - } key := string(args[0]) values := args[1:] @@ -426,8 +393,8 @@ func RPush(db *DB, args [][]byte) redis.Reply { return reply.MakeIntReply(int64(list.Len())) } -// RPushX inserts element at last of list only if list exists -func RPushX(db *DB, args [][]byte) redis.Reply { +// execRPushX inserts element at last of list only if list exists +func execRPushX(db *DB, args [][]byte) redis.Reply { if len(args) < 2 { 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())) } + +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) +} diff --git a/list_test.go b/list_test.go index 4259719..0e6eaba 100644 --- a/list_test.go +++ b/list_test.go @@ -10,7 +10,7 @@ import ( ) func TestPush(t *testing.T) { - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) size := 100 // rpush single @@ -19,17 +19,17 @@ func TestPush(t *testing.T) { for i := 0; i < size; i++ { value := utils2.RandString(10) 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) { 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) if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) { t.Error("push error") } - Del(testDB, utils2.ToBytesList(key)) + testDB.Remove(key) // rpush multi key = utils2.RandString(10) @@ -39,16 +39,16 @@ func TestPush(t *testing.T) { value := utils2.RandString(10) values[i+1] = []byte(value) } - result := RPush(testDB, values) + result := execRPush(testDB, values) if intResult, _ := result.(*reply.IntReply); intResult.Code != int64(size) { 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:]) if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) { t.Error("push error") } - Del(testDB, utils2.ToBytesList(key)) + testDB.Remove(key) // left push single key = utils2.RandString(10) @@ -56,17 +56,17 @@ func TestPush(t *testing.T) { for i := 0; i < size; i++ { value := utils2.RandString(10) 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) { 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) if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) { t.Error("push error") } - Del(testDB, utils2.ToBytesList(key)) + testDB.Remove(key) // left push multi key = utils2.RandString(10) @@ -78,33 +78,33 @@ func TestPush(t *testing.T) { values[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) { 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) if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) { t.Error("push error") } - Del(testDB, utils2.ToBytesList(key)) + testDB.Remove(key) } func TestLRange(t *testing.T) { // prepare list - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) size := 100 key := utils2.RandString(10) values := make([][]byte, size) for i := 0; i < size; i++ { value := utils2.RandString(10) - RPush(testDB, utils2.ToBytesList(key, value)) + execRPush(testDB, utils2.ToBytesList(key, value)) values[i] = []byte(value) } start := "0" end := "9" - actual := LRange(testDB, utils2.ToBytesList(key, start, end)) + actual := execLRange(testDB, utils2.ToBytesList(key, start, end)) expected := reply.MakeMultiBulkReply(values[0:10]) if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) { t.Error(fmt.Sprintf("range error [%s, %s]", start, end)) @@ -112,7 +112,7 @@ func TestLRange(t *testing.T) { start = "0" end = "200" - actual = LRange(testDB, utils2.ToBytesList(key, start, end)) + actual = execLRange(testDB, utils2.ToBytesList(key, start, end)) expected = reply.MakeMultiBulkReply(values) if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) { t.Error(fmt.Sprintf("range error [%s, %s]", start, end)) @@ -120,7 +120,7 @@ func TestLRange(t *testing.T) { start = "0" 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]) if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) { t.Error(fmt.Sprintf("range error [%s, %s]", start, end)) @@ -128,7 +128,7 @@ func TestLRange(t *testing.T) { start = "0" end = "-200" - actual = LRange(testDB, utils2.ToBytesList(key, start, end)) + actual = execLRange(testDB, utils2.ToBytesList(key, start, end)) expected = reply.MakeMultiBulkReply(values[0:0]) if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) { t.Error(fmt.Sprintf("range error [%s, %s]", start, end)) @@ -136,7 +136,7 @@ func TestLRange(t *testing.T) { start = "-10" end = "-1" - actual = LRange(testDB, utils2.ToBytesList(key, start, end)) + actual = execLRange(testDB, utils2.ToBytesList(key, start, end)) expected = reply.MakeMultiBulkReply(values[90:]) if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) { t.Error(fmt.Sprintf("range error [%s, %s]", start, end)) @@ -145,23 +145,23 @@ func TestLRange(t *testing.T) { func TestLIndex(t *testing.T) { // prepare list - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) size := 100 key := utils2.RandString(10) values := make([][]byte, size) for i := 0; i < size; i++ { value := utils2.RandString(10) - RPush(testDB, utils2.ToBytesList(key, value)) + execRPush(testDB, utils2.ToBytesList(key, 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) { t.Error(fmt.Sprintf("expected %d, actually %d", size, intResult.Code)) } 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]) if !utils.BytesEquals(result.ToBytes(), expected.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++ { - result = LIndex(testDB, utils2.ToBytesList(key, strconv.Itoa(-i))) + result = execLIndex(testDB, utils2.ToBytesList(key, strconv.Itoa(-i))) expected := reply.MakeBulkReply(values[size-i]) if !utils.BytesEquals(result.ToBytes(), expected.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) { // prepare list - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) key := utils2.RandString(10) 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 { 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 { 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 { 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 { 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 { 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 { t.Error(fmt.Sprintf("expected %d, actually %d", 2, intResult.Code)) } } func TestLSet(t *testing.T) { - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) key := utils2.RandString(10) values := []string{key, "a", "b", "c", "d", "e", "f"} - RPush(testDB, utils2.ToBytesList(values...)) + execRPush(testDB, utils2.ToBytesList(values...)) // test positive index size := len(values) - 1 for i := 0; i < size; i++ { indexStr := strconv.Itoa(i) 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 { 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)) if !utils.BytesEquals(result.ToBytes(), expected.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 for i := 1; i <= size; i++ { 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 { 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)) if !utils.BytesEquals(result.ToBytes(), expected.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 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") if !utils.BytesEquals(result.ToBytes(), expected.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()) { 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") if !utils.BytesEquals(result.ToBytes(), expected.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) { - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) key := utils2.RandString(10) values := []string{key, "a", "b", "c", "d", "e", "f"} - RPush(testDB, utils2.ToBytesList(values...)) + execRPush(testDB, utils2.ToBytesList(values...)) size := len(values) - 1 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])) if !utils.BytesEquals(result.ToBytes(), expected.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{} if !utils.BytesEquals(result.ToBytes(), expected.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) { - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) key := utils2.RandString(10) values := []string{key, "a", "b", "c", "d", "e", "f"} - RPush(testDB, utils2.ToBytesList(values...)) + execRPush(testDB, utils2.ToBytesList(values...)) size := len(values) - 1 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])) if !utils.BytesEquals(result.ToBytes(), expected.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{} if !utils.BytesEquals(result.ToBytes(), expected.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) { - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) key1 := utils2.RandString(10) key2 := utils2.RandString(10) values := []string{key1, "a", "b", "c", "d", "e", "f"} - RPush(testDB, utils2.ToBytesList(values...)) + execRPush(testDB, utils2.ToBytesList(values...)) size := len(values) - 1 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])) if !utils.BytesEquals(result.ToBytes(), expected.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()) { 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{} if !utils.BytesEquals(result.ToBytes(), expected.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) { - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) key := utils2.RandString(10) - result := RPushX(testDB, utils2.ToBytesList(key, "1")) + result := execRPushX(testDB, utils2.ToBytesList(key, "1")) expected := reply.MakeIntReply(int64(0)) if !utils.BytesEquals(result.ToBytes(), expected.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++ { value := utils2.RandString(10) - result := RPushX(testDB, utils2.ToBytesList(key, value)) + result := execRPushX(testDB, utils2.ToBytesList(key, value)) expected := reply.MakeIntReply(int64(i + 2)) if !utils.BytesEquals(result.ToBytes(), expected.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)) if !utils.BytesEquals(result.ToBytes(), expected2.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) { - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) key := utils2.RandString(10) - result := RPushX(testDB, utils2.ToBytesList(key, "1")) + result := execRPushX(testDB, utils2.ToBytesList(key, "1")) expected := reply.MakeIntReply(int64(0)) if !utils.BytesEquals(result.ToBytes(), expected.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++ { value := utils2.RandString(10) - result := LPushX(testDB, utils2.ToBytesList(key, value)) + result := execLPushX(testDB, utils2.ToBytesList(key, value)) expected := reply.MakeIntReply(int64(i + 2)) if !utils.BytesEquals(result.ToBytes(), expected.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)) if !utils.BytesEquals(result.ToBytes(), expected2.ToBytes()) { t.Error(fmt.Sprintf("expected %s, actually %s", string(expected2.ToBytes()), string(result.ToBytes()))) diff --git a/prepare.go b/prepare.go new file mode 100644 index 0000000..4de41bc --- /dev/null +++ b/prepare.go @@ -0,0 +1,5 @@ +package godis + +func noPre(args [][]byte) ([]string, [][][]byte) { + return nil, nil +} diff --git a/redis/reply/errors.go b/redis/reply/errors.go index 12b19fe..40f2734 100644 --- a/redis/reply/errors.go +++ b/redis/reply/errors.go @@ -28,10 +28,23 @@ func (r *ArgNumErrReply) Error() string { 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 type SyntaxErrReply struct{} var syntaxErrBytes = []byte("-Err syntax error\r\n") +var theSyntaxErrReply = &SyntaxErrReply{} + +// MakeSyntaxErrReply creates syntax error +func MakeSyntaxErrReply() *SyntaxErrReply { + return theSyntaxErrReply +} // ToBytes marshals redis.Reply func (r *SyntaxErrReply) ToBytes() []byte { diff --git a/router.go b/router.go index 56636c2..3f63491 100644 --- a/router.go +++ b/router.go @@ -1,102 +1,23 @@ package godis -func makeRouter() map[string]cmdFunc { - routerMap := make(map[string]cmdFunc) - routerMap["ping"] = Ping +import "strings" - routerMap["del"] = Del - 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 +var cmdTable = make(map[string]*command) - routerMap["set"] = Set - routerMap["setnx"] = SetNX - routerMap["setex"] = SetEX - routerMap["psetex"] = PSetEX - routerMap["mset"] = MSet - routerMap["mget"] = MGet - routerMap["msetnx"] = MSetNX - routerMap["get"] = Get - routerMap["getset"] = GetSet - routerMap["incr"] = Incr - routerMap["incrby"] = IncrBy - routerMap["incrbyfloat"] = IncrByFloat - routerMap["decr"] = Decr - routerMap["decrby"] = DecrBy - - 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 +type command struct { + executor ExecFunc + prepare PreFunc // return related keys and rollback command + arity int // allow number of args, arity < 0 means len(args) >= -arity +} + +// RegisterCommand registers a new command +// arity means allowed number of cmdArgs, arity < 0 means len(args) >= -arity. +// for example: the arity of `get` is 2, `mget` is -2 +func RegisterCommand(name string, executor ExecFunc, prepare PreFunc, arity int) { + name = strings.ToLower(name) + cmdTable[name] = &command{ + executor: executor, + prepare: prepare, + arity: arity, + } } diff --git a/server.go b/server.go index 16eacd5..8e518b3 100644 --- a/server.go +++ b/server.go @@ -39,3 +39,7 @@ func isAuthenticated(c redis.Connection) bool { } return c.GetPassword() == config.Properties.RequirePass } + +func init() { + RegisterCommand("ping", Ping, nil, -1) +} diff --git a/server_test.go b/server_test.go index ca1bb1e..291cadc 100644 --- a/server_test.go +++ b/server_test.go @@ -21,18 +21,20 @@ func TestPing(t *testing.T) { func TestAuth(t *testing.T) { passwd := utils.RandString(10) 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") - 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") config.Properties.RequirePass = passwd defer func() { 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") - 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") } diff --git a/set.go b/set.go index a40b5cc..0a2b449 100644 --- a/set.go +++ b/set.go @@ -35,11 +35,8 @@ func (db *DB) getOrInitSet(key string) (set *HashSet.Set, inited bool, errReply return set, inited, nil } -// SAdd adds members into set -func SAdd(db *DB, args [][]byte) redis.Reply { - if len(args) < 2 { - return reply.MakeErrReply("ERR wrong number of arguments for 'sadd' command") - } +// execSAdd adds members into set +func execSAdd(db *DB, args [][]byte) redis.Reply { key := string(args[0]) members := args[1:] @@ -60,11 +57,8 @@ func SAdd(db *DB, args [][]byte) redis.Reply { return reply.MakeIntReply(int64(counter)) } -// SIsMember checks if the given value is member of set -func SIsMember(db *DB, args [][]byte) redis.Reply { - if len(args) != 2 { - return reply.MakeErrReply("ERR wrong number of arguments for 'sismember' command") - } +// execSIsMember checks if the given value is member of set +func execSIsMember(db *DB, args [][]byte) redis.Reply { key := string(args[0]) member := string(args[1]) @@ -87,11 +81,8 @@ func SIsMember(db *DB, args [][]byte) redis.Reply { return reply.MakeIntReply(0) } -// SRem removes a member from set -func SRem(db *DB, args [][]byte) redis.Reply { - if len(args) < 2 { - return reply.MakeErrReply("ERR wrong number of arguments for 'srem' command") - } +// execSRem removes a member from set +func execSRem(db *DB, args [][]byte) redis.Reply { key := string(args[0]) members := args[1:] @@ -119,11 +110,8 @@ func SRem(db *DB, args [][]byte) redis.Reply { return reply.MakeIntReply(int64(counter)) } -// SCard gets the number of members in a set -func SCard(db *DB, args [][]byte) redis.Reply { - if len(args) != 1 { - return reply.MakeErrReply("ERR wrong number of arguments for 'scard' command") - } +// execSCard gets the number of members in a set +func execSCard(db *DB, args [][]byte) redis.Reply { key := string(args[0]) db.RLock(key) @@ -140,11 +128,8 @@ func SCard(db *DB, args [][]byte) redis.Reply { return reply.MakeIntReply(int64(set.Len())) } -// SMembers gets all members in a set -func SMembers(db *DB, args [][]byte) redis.Reply { - if len(args) != 1 { - return reply.MakeErrReply("ERR wrong number of arguments for 'smembers' command") - } +// execSMembers gets all members in a set +func execSMembers(db *DB, args [][]byte) redis.Reply { key := string(args[0]) // lock @@ -170,11 +155,8 @@ func SMembers(db *DB, args [][]byte) redis.Reply { return reply.MakeMultiBulkReply(arr) } -// SInter intersect multiple sets -func SInter(db *DB, args [][]byte) redis.Reply { - if len(args) < 1 { - return reply.MakeErrReply("ERR wrong number of arguments for 'sinter' command") - } +// execSInter intersect multiple sets +func execSInter(db *DB, args [][]byte) redis.Reply { keys := make([]string, len(args)) for i, arg := range args { keys[i] = string(arg) @@ -216,11 +198,8 @@ func SInter(db *DB, args [][]byte) redis.Reply { return reply.MakeMultiBulkReply(arr) } -// SInterStore intersects multiple sets and store the result in a key -func SInterStore(db *DB, args [][]byte) redis.Reply { - if len(args) < 2 { - return reply.MakeErrReply("ERR wrong number of arguments for 'sinterstore' command") - } +// execSInterStore intersects multiple sets and store the result in a key +func execSInterStore(db *DB, args [][]byte) redis.Reply { dest := string(args[0]) keys := make([]string, len(args)-1) keyArgs := args[1:] @@ -267,11 +246,8 @@ func SInterStore(db *DB, args [][]byte) redis.Reply { return reply.MakeIntReply(int64(set.Len())) } -// SUnion adds multiple sets -func SUnion(db *DB, args [][]byte) redis.Reply { - if len(args) < 1 { - return reply.MakeErrReply("ERR wrong number of arguments for 'sunion' command") - } +// execSUnion adds multiple sets +func execSUnion(db *DB, args [][]byte) redis.Reply { keys := make([]string, len(args)) for i, arg := range args { keys[i] = string(arg) @@ -313,11 +289,8 @@ func SUnion(db *DB, args [][]byte) redis.Reply { return reply.MakeMultiBulkReply(arr) } -// SUnionStore adds multiple sets and store the result in a key -func SUnionStore(db *DB, args [][]byte) redis.Reply { - if len(args) < 2 { - return reply.MakeErrReply("ERR wrong number of arguments for 'sunionstore' command") - } +// execSUnionStore adds multiple sets and store the result in a key +func execSUnionStore(db *DB, args [][]byte) redis.Reply { dest := string(args[0]) keys := make([]string, len(args)-1) keyArgs := args[1:] @@ -364,11 +337,8 @@ func SUnionStore(db *DB, args [][]byte) redis.Reply { return reply.MakeIntReply(int64(set.Len())) } -// SDiff subtracts multiple sets -func SDiff(db *DB, args [][]byte) redis.Reply { - if len(args) < 1 { - return reply.MakeErrReply("ERR wrong number of arguments for 'sdiff' command") - } +// execSDiff subtracts multiple sets +func execSDiff(db *DB, args [][]byte) redis.Reply { keys := make([]string, len(args)) for i, arg := range args { keys[i] = string(arg) @@ -417,11 +387,8 @@ func SDiff(db *DB, args [][]byte) redis.Reply { return reply.MakeMultiBulkReply(arr) } -// SDiffStore subtracts multiple sets and store the result in a key -func SDiffStore(db *DB, args [][]byte) redis.Reply { - if len(args) < 2 { - return reply.MakeErrReply("ERR wrong number of arguments for 'sdiffstore' command") - } +// execSDiffStore subtracts multiple sets and store the result in a key +func execSDiffStore(db *DB, args [][]byte) redis.Reply { dest := string(args[0]) keys := make([]string, len(args)-1) keyArgs := args[1:] @@ -477,8 +444,8 @@ func SDiffStore(db *DB, args [][]byte) redis.Reply { return reply.MakeIntReply(int64(set.Len())) } -// SRandMember gets random members from set -func SRandMember(db *DB, args [][]byte) redis.Reply { +// execSRandMember gets random members from set +func execSRandMember(db *DB, args [][]byte) redis.Reply { if len(args) != 1 && len(args) != 2 { 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{} } + +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) +} diff --git a/set_test.go b/set_test.go index 2683fc7..820cace 100644 --- a/set_test.go +++ b/set_test.go @@ -11,29 +11,29 @@ import ( // basic add get and remove func TestSAdd(t *testing.T) { - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) size := 100 // test sadd key := utils.RandString(10) for i := 0; i < size; i++ { member := strconv.Itoa(i) - result := SAdd(testDB, utils.ToBytesList(key, member)) + result := execSAdd(testDB, utils.ToBytesList(key, member)) asserts.AssertIntReply(t, result, 1) } // test scard - result := SCard(testDB, utils.ToBytesList(key)) + result := execSCard(testDB, utils.ToBytesList(key)) asserts.AssertIntReply(t, result, size) // test is member for i := 0; i < size; i++ { member := strconv.Itoa(i) - result := SIsMember(testDB, utils.ToBytesList(key, member)) + result := execSIsMember(testDB, utils.ToBytesList(key, member)) asserts.AssertIntReply(t, result, 1) } // test members - result = SMembers(testDB, utils.ToBytesList(key)) + result = execSMembers(testDB, utils.ToBytesList(key)) multiBulk, ok := result.(*reply.MultiBulkReply) if !ok { 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) { - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) size := 100 // mock data key := utils.RandString(10) for i := 0; i < size; i++ { member := strconv.Itoa(i) - SAdd(testDB, utils.ToBytesList(key, member)) + execSAdd(testDB, utils.ToBytesList(key, member)) } for i := 0; i < size; i++ { member := strconv.Itoa(i) - SRem(testDB, utils.ToBytesList(key, member)) - result := SIsMember(testDB, utils.ToBytesList(key, member)) + execSRem(testDB, utils.ToBytesList(key, member)) + result := execSIsMember(testDB, utils.ToBytesList(key, member)) asserts.AssertIntReply(t, result, 0) } } func TestSInter(t *testing.T) { - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) size := 100 step := 10 @@ -75,39 +75,39 @@ func TestSInter(t *testing.T) { keys = append(keys, key) for j := start; j < size+start; j++ { member := strconv.Itoa(j) - SAdd(testDB, utils.ToBytesList(key, member)) + execSAdd(testDB, utils.ToBytesList(key, member)) } start += step } - result := SInter(testDB, utils.ToBytesList(keys...)) + result := execSInter(testDB, utils.ToBytesList(keys...)) asserts.AssertMultiBulkReplySize(t, result, 70) destKey := utils.RandString(10) keysWithDest := []string{destKey} keysWithDest = append(keysWithDest, keys...) - result = SInterStore(testDB, utils.ToBytesList(keysWithDest...)) + result = execSInterStore(testDB, utils.ToBytesList(keysWithDest...)) asserts.AssertIntReply(t, result, 70) // test empty set - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) key0 := utils.RandString(10) - Del(testDB, utils.ToBytesList(key0)) + testDB.Remove(key0) key1 := utils.RandString(10) - SAdd(testDB, utils.ToBytesList(key1, "a", "b")) + execSAdd(testDB, utils.ToBytesList(key1, "a", "b")) key2 := utils.RandString(10) - SAdd(testDB, utils.ToBytesList(key2, "1", "2")) - result = SInter(testDB, utils.ToBytesList(key0, key1, key2)) + execSAdd(testDB, utils.ToBytesList(key2, "1", "2")) + result = execSInter(testDB, utils.ToBytesList(key0, key1, key2)) asserts.AssertMultiBulkReplySize(t, result, 0) - result = SInter(testDB, utils.ToBytesList(key1, key2)) + result = execSInter(testDB, utils.ToBytesList(key1, key2)) 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) - 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) } func TestSUnion(t *testing.T) { - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) size := 100 step := 10 @@ -118,22 +118,22 @@ func TestSUnion(t *testing.T) { keys = append(keys, key) for j := start; j < size+start; j++ { member := strconv.Itoa(j) - SAdd(testDB, utils.ToBytesList(key, member)) + execSAdd(testDB, utils.ToBytesList(key, member)) } start += step } - result := SUnion(testDB, utils.ToBytesList(keys...)) + result := execSUnion(testDB, utils.ToBytesList(keys...)) asserts.AssertMultiBulkReplySize(t, result, 130) destKey := utils.RandString(10) keysWithDest := []string{destKey} keysWithDest = append(keysWithDest, keys...) - result = SUnionStore(testDB, utils.ToBytesList(keysWithDest...)) + result = execSUnionStore(testDB, utils.ToBytesList(keysWithDest...)) asserts.AssertIntReply(t, result, 130) } func TestSDiff(t *testing.T) { - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) size := 100 step := 20 @@ -144,52 +144,52 @@ func TestSDiff(t *testing.T) { keys = append(keys, key) for j := start; j < size+start; j++ { member := strconv.Itoa(j) - SAdd(testDB, utils.ToBytesList(key, member)) + execSAdd(testDB, utils.ToBytesList(key, member)) } start += step } - result := SDiff(testDB, utils.ToBytesList(keys...)) + result := execSDiff(testDB, utils.ToBytesList(keys...)) asserts.AssertMultiBulkReplySize(t, result, step) destKey := utils.RandString(10) keysWithDest := []string{destKey} keysWithDest = append(keysWithDest, keys...) - result = SDiffStore(testDB, utils.ToBytesList(keysWithDest...)) + result = execSDiffStore(testDB, utils.ToBytesList(keysWithDest...)) asserts.AssertIntReply(t, result, step) // test empty set - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) key0 := utils.RandString(10) - Del(testDB, utils.ToBytesList(key0)) + testDB.Remove(key0) key1 := utils.RandString(10) - SAdd(testDB, utils.ToBytesList(key1, "a", "b")) + execSAdd(testDB, utils.ToBytesList(key1, "a", "b")) key2 := utils.RandString(10) - SAdd(testDB, utils.ToBytesList(key2, "a", "b")) - result = SDiff(testDB, utils.ToBytesList(key0, key1, key2)) + execSAdd(testDB, utils.ToBytesList(key2, "a", "b")) + result = execSDiff(testDB, utils.ToBytesList(key0, key1, key2)) asserts.AssertMultiBulkReplySize(t, result, 0) - result = SDiff(testDB, utils.ToBytesList(key1, key2)) + result = execSDiff(testDB, utils.ToBytesList(key1, key2)) 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) - 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) } func TestSRandMember(t *testing.T) { - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) key := utils.RandString(10) for j := 0; j < 100; 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) if !ok && len(br.Arg) > 0 { t.Error(fmt.Sprintf("expected bulk reply, actually %s", result.ToBytes())) return } - result = SRandMember(testDB, utils.ToBytesList(key, "10")) + result = execSRandMember(testDB, utils.ToBytesList(key, "10")) asserts.AssertMultiBulkReplySize(t, result, 10) multiBulk, ok := result.(*reply.MultiBulkReply) if !ok { @@ -205,12 +205,12 @@ func TestSRandMember(t *testing.T) { return } - result = SRandMember(testDB, utils.ToBytesList(key, "110")) + result = execSRandMember(testDB, utils.ToBytesList(key, "110")) asserts.AssertMultiBulkReplySize(t, result, 100) - result = SRandMember(testDB, utils.ToBytesList(key, "-10")) + result = execSRandMember(testDB, utils.ToBytesList(key, "-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) } diff --git a/sortedset.go b/sortedset.go index 34b1606..687c842 100644 --- a/sortedset.go +++ b/sortedset.go @@ -36,10 +36,10 @@ func (db *DB) getOrInitSortedSet(key string) (sortedSet *SortedSet.SortedSet, in return sortedSet, inited, nil } -// ZAdd adds member into sorted set -func ZAdd(db *DB, args [][]byte) redis.Reply { - if len(args) < 3 || len(args)%2 != 1 { - return reply.MakeErrReply("ERR wrong number of arguments for 'zadd' command") +// execZAdd adds member into sorted set +func execZAdd(db *DB, args [][]byte) redis.Reply { + if len(args)%2 != 1 { + return reply.MakeSyntaxErrReply() } key := string(args[0]) size := (len(args) - 1) / 2 @@ -79,12 +79,9 @@ func ZAdd(db *DB, args [][]byte) redis.Reply { return reply.MakeIntReply(int64(i)) } -// ZScore gets score of a member in sortedset -func ZScore(db *DB, args [][]byte) redis.Reply { +// execZScore gets score of a member in sortedset +func execZScore(db *DB, args [][]byte) redis.Reply { // parse args - if len(args) != 2 { - return reply.MakeErrReply("ERR wrong number of arguments for 'zscore' command") - } key := string(args[0]) member := string(args[1]) @@ -106,12 +103,9 @@ func ZScore(db *DB, args [][]byte) redis.Reply { return reply.MakeBulkReply([]byte(value)) } -// ZRank gets index of a member in sortedset, ascending order, start from 0 -func ZRank(db *DB, args [][]byte) redis.Reply { +// execZRank gets index of a member in sortedset, ascending order, start from 0 +func execZRank(db *DB, args [][]byte) redis.Reply { // parse args - if len(args) != 2 { - return reply.MakeErrReply("ERR wrong number of arguments for 'zrank' command") - } key := string(args[0]) member := string(args[1]) @@ -133,12 +127,9 @@ func ZRank(db *DB, args [][]byte) redis.Reply { return reply.MakeIntReply(rank) } -// ZRevRank gets index of a member in sortedset, descending order, start from 0 -func ZRevRank(db *DB, args [][]byte) redis.Reply { +// execZRevRank gets index of a member in sortedset, descending order, start from 0 +func execZRevRank(db *DB, args [][]byte) redis.Reply { // parse args - if len(args) != 2 { - return reply.MakeErrReply("ERR wrong number of arguments for 'zrevrank' command") - } key := string(args[0]) member := string(args[1]) @@ -160,12 +151,9 @@ func ZRevRank(db *DB, args [][]byte) redis.Reply { return reply.MakeIntReply(rank) } -// ZCard gets number of members in sortedset -func ZCard(db *DB, args [][]byte) redis.Reply { +// execZCard gets number of members in sortedset +func execZCard(db *DB, args [][]byte) redis.Reply { // parse args - if len(args) != 1 { - return reply.MakeErrReply("ERR wrong number of arguments for 'zcard' command") - } key := string(args[0]) // get entity @@ -182,8 +170,8 @@ func ZCard(db *DB, args [][]byte) redis.Reply { return reply.MakeIntReply(sortedSet.Len()) } -// ZRange gets members in range, sort by score in ascending order -func ZRange(db *DB, args [][]byte) redis.Reply { +// execZRange gets members in range, sort by score in ascending order +func execZRange(db *DB, args [][]byte) redis.Reply { // parse args if len(args) != 3 && len(args) != 4 { 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) } -// ZRevRange gets members in range, sort by score in descending order -func ZRevRange(db *DB, args [][]byte) redis.Reply { +// execZRevRange gets members in range, sort by score in descending order +func execZRevRange(db *DB, args [][]byte) redis.Reply { // parse args if len(args) != 3 && len(args) != 4 { 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) } -// ZCount gets number of members which score within given range -func ZCount(db *DB, args [][]byte) redis.Reply { - if len(args) != 3 { - return reply.MakeErrReply("ERR wrong number of arguments for 'zcount' command") - } +// execZCount gets number of members which score within given range +func execZCount(db *DB, args [][]byte) redis.Reply { key := string(args[0]) 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) } -// ZRangeByScore gets members which score within given range, in ascending order -func ZRangeByScore(db *DB, args [][]byte) redis.Reply { +// execZRangeByScore gets members which score within given range, in ascending order +func execZRangeByScore(db *DB, args [][]byte) redis.Reply { if len(args) < 3 { 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) } -// ZRevRangeByScore gets number of members which score within given range, in descending order -func ZRevRangeByScore(db *DB, args [][]byte) redis.Reply { +// execZRevRangeByScore gets number of members which score within given range, in descending order +func execZRevRangeByScore(db *DB, args [][]byte) redis.Reply { if len(args) < 3 { 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) } -// ZRemRangeByScore removes members which score within given range -func ZRemRangeByScore(db *DB, args [][]byte) redis.Reply { +// execZRemRangeByScore removes members which score within given range +func execZRemRangeByScore(db *DB, args [][]byte) redis.Reply { if len(args) != 3 { 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) } -// ZRemRangeByRank removes members within given indexes -func ZRemRangeByRank(db *DB, args [][]byte) redis.Reply { - if len(args) != 3 { - return reply.MakeErrReply("ERR wrong number of arguments for 'zremrangebyrank' command") - } +// execZRemRangeByRank removes members within given indexes +func execZRemRangeByRank(db *DB, args [][]byte) redis.Reply { key := string(args[0]) start, err := strconv.ParseInt(string(args[1]), 10, 64) if err != nil { @@ -549,12 +531,9 @@ func ZRemRangeByRank(db *DB, args [][]byte) redis.Reply { return reply.MakeIntReply(removed) } -// ZRem removes given members -func ZRem(db *DB, args [][]byte) redis.Reply { +// execZRem removes given members +func execZRem(db *DB, args [][]byte) redis.Reply { // parse args - if len(args) < 2 { - return reply.MakeErrReply("ERR wrong number of arguments for 'zrem' command") - } key := string(args[0]) fields := make([]string, len(args)-1) fieldArgs := args[1:] @@ -586,11 +565,8 @@ func ZRem(db *DB, args [][]byte) redis.Reply { return reply.MakeIntReply(deleted) } -// ZIncrBy increments the score of a member -func ZIncrBy(db *DB, args [][]byte) redis.Reply { - if len(args) != 3 { - return reply.MakeErrReply("ERR wrong number of arguments for 'zincrby' command") - } +// execZIncrBy increments the score of a member +func execZIncrBy(db *DB, args [][]byte) redis.Reply { key := string(args[0]) rawDelta := string(args[1]) field := string(args[2]) @@ -620,3 +596,20 @@ func ZIncrBy(db *DB, args [][]byte) redis.Reply { db.AddAof(makeAofCmd("zincrby", args)) 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) +} diff --git a/sortedset_test.go b/sortedset_test.go index 8911ee9..3475648 100644 --- a/sortedset_test.go +++ b/sortedset_test.go @@ -9,7 +9,7 @@ import ( ) func TestZAdd(t *testing.T) { - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) size := 100 // add new members @@ -22,18 +22,18 @@ func TestZAdd(t *testing.T) { scores[i] = rand.Float64() 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) // test zscore and zrank 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) asserts.AssertBulkReply(t, result, score) } // test zcard - result = ZCard(testDB, utils.ToBytesList(key)) + result = execZCard(testDB, utils.ToBytesList(key)) asserts.AssertIntReply(t, result, size) // update members @@ -42,19 +42,19 @@ func TestZAdd(t *testing.T) { scores[i] = rand.Float64() + 100 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 // test updated score 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) asserts.AssertBulkReply(t, result, score) } } func TestZRank(t *testing.T) { - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) size := 100 key := utils.RandString(10) members := make([]string, size) @@ -65,21 +65,21 @@ func TestZRank(t *testing.T) { scores[i] = i setArgs = append(setArgs, strconv.FormatInt(int64(scores[i]), 10), members[i]) } - ZAdd(testDB, utils.ToBytesList(setArgs...)) + execZAdd(testDB, utils.ToBytesList(setArgs...)) // test zrank for i, member := range members { - result := ZRank(testDB, utils.ToBytesList(key, member)) + result := execZRank(testDB, utils.ToBytesList(key, member)) 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) } } func TestZRange(t *testing.T) { // prepare - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) size := 100 key := utils.RandString(10) members := make([]string, size) @@ -90,7 +90,7 @@ func TestZRange(t *testing.T) { scores[i] = 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) for i, v := range members { reverseMembers[size-i-1] = v @@ -98,39 +98,39 @@ func TestZRange(t *testing.T) { start := "0" 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]) - result = ZRange(testDB, utils.ToBytesList(key, start, end, "WITHSCORES")) + result = execZRange(testDB, utils.ToBytesList(key, start, end, "WITHSCORES")) 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]) start = "0" end = "200" - result = ZRange(testDB, utils.ToBytesList(key, start, end)) + result = execZRange(testDB, utils.ToBytesList(key, start, end)) 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) start = "0" 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]) - 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]) start = "0" 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]) - result = ZRevRange(testDB, utils.ToBytesList(key, start, end)) + result = execZRevRange(testDB, utils.ToBytesList(key, start, end)) asserts.AssertMultiBulkReply(t, result, reverseMembers[0:0]) start = "-10" end = "-1" - result = ZRange(testDB, utils.ToBytesList(key, start, end)) + result = execZRange(testDB, utils.ToBytesList(key, start, end)) 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:]) } @@ -144,7 +144,7 @@ func reverse(src []string) []string { func TestZRangeByScore(t *testing.T) { // prepare - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) size := 100 key := utils.RandString(10) members := make([]string, size) @@ -155,49 +155,49 @@ func TestZRangeByScore(t *testing.T) { scores[i] = 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) min := "20" 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]) - result = ZRangeByScore(testDB, utils.ToBytesList(key, min, max, "WITHSCORES")) + result = execZRangeByScore(testDB, utils.ToBytesList(key, min, max, "WITHSCORES")) 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])) min = "-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]) - result = ZRevRangeByScore(testDB, utils.ToBytesList(key, max, min)) + result = execZRevRangeByScore(testDB, utils.ToBytesList(key, max, min)) asserts.AssertMultiBulkReply(t, result, reverse(members[0:11])) min = "90" max = "110" - result = ZRangeByScore(testDB, utils.ToBytesList(key, min, max)) + result = execZRangeByScore(testDB, utils.ToBytesList(key, min, max)) 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:])) min = "(20" 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]) - result = ZRevRangeByScore(testDB, utils.ToBytesList(key, max, min)) + result = execZRevRangeByScore(testDB, utils.ToBytesList(key, max, min)) asserts.AssertMultiBulkReply(t, result, reverse(members[21:30])) min = "20" 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]) - 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])) } func TestZRem(t *testing.T) { - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) size := 100 key := utils.RandString(10) members := make([]string, size) @@ -208,17 +208,17 @@ func TestZRem(t *testing.T) { scores[i] = 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 = append(args, members[0:10]...) - result := ZRem(testDB, utils.ToBytesList(args...)) + result := execZRem(testDB, utils.ToBytesList(args...)) asserts.AssertIntReply(t, result, 10) - result = ZCard(testDB, utils.ToBytesList(key)) + result = execZCard(testDB, utils.ToBytesList(key)) asserts.AssertIntReply(t, result, size-10) // test ZRemRangeByRank - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) size = 100 key = utils.RandString(10) members = make([]string, size) @@ -229,15 +229,15 @@ func TestZRem(t *testing.T) { scores[i] = 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) - result = ZCard(testDB, utils.ToBytesList(key)) + result = execZCard(testDB, utils.ToBytesList(key)) asserts.AssertIntReply(t, result, size-10) // test ZRemRangeByScore - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) size = 100 key = utils.RandString(10) members = make([]string, size) @@ -248,17 +248,17 @@ func TestZRem(t *testing.T) { scores[i] = 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) - result = ZCard(testDB, utils.ToBytesList(key)) + result = execZCard(testDB, utils.ToBytesList(key)) asserts.AssertIntReply(t, result, size-10) } func TestZCount(t *testing.T) { // prepare - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) size := 100 key := utils.RandString(10) members := make([]string, size) @@ -269,37 +269,37 @@ func TestZCount(t *testing.T) { scores[i] = i setArgs = append(setArgs, strconv.FormatInt(int64(scores[i]), 10), members[i]) } - ZAdd(testDB, utils.ToBytesList(setArgs...)) + execZAdd(testDB, utils.ToBytesList(setArgs...)) min := "20" max := "30" - result := ZCount(testDB, utils.ToBytesList(key, min, max)) + result := execZCount(testDB, utils.ToBytesList(key, min, max)) asserts.AssertIntReply(t, result, 11) min = "-10" max = "10" - result = ZCount(testDB, utils.ToBytesList(key, min, max)) + result = execZCount(testDB, utils.ToBytesList(key, min, max)) asserts.AssertIntReply(t, result, 11) min = "90" max = "110" - result = ZCount(testDB, utils.ToBytesList(key, min, max)) + result = execZCount(testDB, utils.ToBytesList(key, min, max)) asserts.AssertIntReply(t, result, 10) min = "(20" max = "(30" - result = ZCount(testDB, utils.ToBytesList(key, min, max)) + result = execZCount(testDB, utils.ToBytesList(key, min, max)) asserts.AssertIntReply(t, result, 9) } func TestZIncrBy(t *testing.T) { - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) 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") - result = ZIncrBy(testDB, utils.ToBytesList(key, "10", "a")) + result = execZIncrBy(testDB, utils.ToBytesList(key, "10", "a")) asserts.AssertBulkReply(t, result, "20") - result = ZScore(testDB, utils.ToBytesList(key, "a")) + result = execZScore(testDB, utils.ToBytesList(key, "a")) asserts.AssertBulkReply(t, result, "20") } diff --git a/string.go b/string.go index f3c97b8..a44ee61 100644 --- a/string.go +++ b/string.go @@ -21,11 +21,8 @@ func (db *DB) getAsString(key string) ([]byte, reply.ErrorReply) { return bytes, nil } -// Get returns string value bound to the given key -func Get(db *DB, args [][]byte) redis.Reply { - if len(args) != 1 { - return reply.MakeErrReply("ERR wrong number of arguments for 'get' command") - } +// execGet returns string value bound to the given key +func execGet(db *DB, args [][]byte) redis.Reply { key := string(args[0]) bytes, err := db.getAsString(key) if err != nil { @@ -45,11 +42,8 @@ const ( const unlimitedTTL int64 = 0 -// Set sets string value and time to live to the given key -func Set(db *DB, args [][]byte) redis.Reply { - if len(args) < 2 { - return reply.MakeErrReply("ERR wrong number of arguments for 'set' command") - } +// execSet sets string value and time to live to the given key +func execSet(db *DB, args [][]byte) redis.Reply { key := string(args[0]) value := args[1] policy := upsertPolicy @@ -149,11 +143,8 @@ func Set(db *DB, args [][]byte) redis.Reply { return &reply.NullBulkReply{} } -// SetNX sets string if not exists -func SetNX(db *DB, args [][]byte) redis.Reply { - if len(args) != 2 { - return reply.MakeErrReply("ERR wrong number of arguments for 'setnx' command") - } +// execSetNX sets string if not exists +func execSetNX(db *DB, args [][]byte) redis.Reply { key := string(args[0]) value := args[1] entity := &DataEntity{ @@ -164,11 +155,8 @@ func SetNX(db *DB, args [][]byte) redis.Reply { return reply.MakeIntReply(int64(result)) } -// SetEX sets string and its ttl -func SetEX(db *DB, args [][]byte) redis.Reply { - if len(args) != 3 { - return reply.MakeErrReply("ERR wrong number of arguments for 'setex' command") - } +// execSetEX sets string and its ttl +func execSetEX(db *DB, args [][]byte) redis.Reply { key := string(args[0]) value := args[2] @@ -196,11 +184,8 @@ func SetEX(db *DB, args [][]byte) redis.Reply { return &reply.OkReply{} } -// PSetEX set a key's time to live in milliseconds -func PSetEX(db *DB, args [][]byte) redis.Reply { - if len(args) != 3 { - return reply.MakeErrReply("ERR wrong number of arguments for 'setex' command") - } +// execPSetEX set a key's time to live in milliseconds +func execPSetEX(db *DB, args [][]byte) redis.Reply { key := string(args[0]) value := args[2] @@ -228,10 +213,10 @@ func PSetEX(db *DB, args [][]byte) redis.Reply { return &reply.OkReply{} } -// MSet sets multi key-value in database -func MSet(db *DB, args [][]byte) redis.Reply { - if len(args)%2 != 0 || len(args) == 0 { - return reply.MakeErrReply("ERR wrong number of arguments for 'mset' command") +// execMSet sets multi key-value in database +func execMSet(db *DB, args [][]byte) redis.Reply { + if len(args)%2 != 0 { + return reply.MakeSyntaxErrReply() } size := len(args) / 2 @@ -253,11 +238,8 @@ func MSet(db *DB, args [][]byte) redis.Reply { return &reply.OkReply{} } -// MGet get multi key-value from database -func MGet(db *DB, args [][]byte) redis.Reply { - if len(args) == 0 { - return reply.MakeErrReply("ERR wrong number of arguments for 'mget' command") - } +// execMGet get multi key-value from database +func execMGet(db *DB, args [][]byte) redis.Reply { keys := make([]string, len(args)) for i, v := range args { keys[i] = string(v) @@ -281,11 +263,11 @@ func MGet(db *DB, args [][]byte) redis.Reply { return reply.MakeMultiBulkReply(result) } -// MSetNX sets multi key-value in database, only if none of the given keys exist -func MSetNX(db *DB, args [][]byte) redis.Reply { +// execMSetNX sets multi key-value in database, only if none of the given keys exist +func execMSetNX(db *DB, args [][]byte) redis.Reply { // parse args - if len(args)%2 != 0 || len(args) == 0 { - return reply.MakeErrReply("ERR wrong number of arguments for 'msetnx' command") + if len(args)%2 != 0 { + return reply.MakeSyntaxErrReply() } size := len(args) / 2 values := make([][]byte, size) @@ -314,11 +296,8 @@ func MSetNX(db *DB, args [][]byte) redis.Reply { return reply.MakeIntReply(1) } -// GetSet sets value of a string-type key and returns its old value -func GetSet(db *DB, args [][]byte) redis.Reply { - if len(args) != 2 { - return reply.MakeErrReply("ERR wrong number of arguments for 'getset' command") - } +// execGetSet sets value of a string-type key and returns its old value +func execGetSet(db *DB, args [][]byte) redis.Reply { key := string(args[0]) value := args[1] @@ -336,11 +315,8 @@ func GetSet(db *DB, args [][]byte) redis.Reply { return reply.MakeBulkReply(old) } -// Incr increments the integer value of a key by one -func Incr(db *DB, args [][]byte) redis.Reply { - if len(args) != 1 { - return reply.MakeErrReply("ERR wrong number of arguments for 'incr' command") - } +// execIncr increments the integer value of a key by one +func execIncr(db *DB, args [][]byte) redis.Reply { key := string(args[0]) db.Lock(key) @@ -368,11 +344,8 @@ func Incr(db *DB, args [][]byte) redis.Reply { return reply.MakeIntReply(1) } -// IncrBy increments the integer value of a key by given value -func IncrBy(db *DB, args [][]byte) redis.Reply { - if len(args) != 2 { - return reply.MakeErrReply("ERR wrong number of arguments for 'incrby' command") - } +// execIncrBy increments the integer value of a key by given value +func execIncrBy(db *DB, args [][]byte) redis.Reply { key := string(args[0]) rawDelta := string(args[1]) delta, err := strconv.ParseInt(rawDelta, 10, 64) @@ -406,11 +379,8 @@ func IncrBy(db *DB, args [][]byte) redis.Reply { return reply.MakeIntReply(delta) } -// IncrByFloat increments the float value of a key by given value -func IncrByFloat(db *DB, args [][]byte) redis.Reply { - if len(args) != 2 { - return reply.MakeErrReply("ERR wrong number of arguments for 'incrbyfloat' command") - } +// execIncrByFloat increments the float value of a key by given value +func execIncrByFloat(db *DB, args [][]byte) redis.Reply { key := string(args[0]) rawDelta := string(args[1]) delta, err := decimal.NewFromString(rawDelta) @@ -444,11 +414,8 @@ func IncrByFloat(db *DB, args [][]byte) redis.Reply { return reply.MakeBulkReply(args[1]) } -// Decr decrements the integer value of a key by one -func Decr(db *DB, args [][]byte) redis.Reply { - if len(args) != 1 { - return reply.MakeErrReply("ERR wrong number of arguments for 'decr' command") - } +// execDecr decrements the integer value of a key by one +func execDecr(db *DB, args [][]byte) redis.Reply { key := string(args[0]) db.Lock(key) @@ -477,11 +444,8 @@ func Decr(db *DB, args [][]byte) redis.Reply { return reply.MakeIntReply(-1) } -// DecrBy decrements the integer value of a key by onedecrement -func DecrBy(db *DB, args [][]byte) redis.Reply { - if len(args) != 2 { - return reply.MakeErrReply("ERR wrong number of arguments for 'decrby' command") - } +// execDecrBy decrements the integer value of a key by onedecrement +func execDecrBy(db *DB, args [][]byte) redis.Reply { key := string(args[0]) rawDelta := string(args[1]) delta, err := strconv.ParseInt(rawDelta, 10, 64) @@ -514,3 +478,22 @@ func DecrBy(db *DB, args [][]byte) redis.Reply { db.AddAof(makeAofCmd("decrby", args)) 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) +} diff --git a/string_test.go b/string_test.go index fa28afd..c646036 100644 --- a/string_test.go +++ b/string_test.go @@ -13,55 +13,55 @@ import ( var testDB = makeTestDB() func TestSet(t *testing.T) { - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) key := utils2.RandString(10) value := utils2.RandString(10) // normal set - Set(testDB, utils2.ToBytesList(key, value)) - actual := Get(testDB, utils2.ToBytesList(key)) + execSet(testDB, utils2.ToBytesList(key, value)) + actual := execGet(testDB, utils2.ToBytesList(key)) expected := reply.MakeBulkReply([]byte(value)) if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) { t.Error("expected: " + string(expected.ToBytes()) + ", actual: " + string(actual.ToBytes())) } // set nx - actual = Set(testDB, utils2.ToBytesList(key, value, "NX")) + actual = execSet(testDB, utils2.ToBytesList(key, value, "NX")) if _, ok := actual.(*reply.NullBulkReply); !ok { t.Error("expected true actual false") } - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) key = utils2.RandString(10) value = utils2.RandString(10) - Set(testDB, utils2.ToBytesList(key, value, "NX")) - actual = Get(testDB, utils2.ToBytesList(key)) + execSet(testDB, utils2.ToBytesList(key, value, "NX")) + actual = execGet(testDB, utils2.ToBytesList(key)) expected = reply.MakeBulkReply([]byte(value)) if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) { t.Error("expected: " + string(expected.ToBytes()) + ", actual: " + string(actual.ToBytes())) } // set xx - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) key = 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 { t.Error("expected true actually false ") } - Set(testDB, utils2.ToBytesList(key, value)) - Set(testDB, utils2.ToBytesList(key, value, "XX")) - actual = Get(testDB, utils2.ToBytesList(key)) + execSet(testDB, utils2.ToBytesList(key, value)) + execSet(testDB, utils2.ToBytesList(key, value, "XX")) + actual = execGet(testDB, utils2.ToBytesList(key)) asserts.AssertBulkReply(t, actual, value) // set ex - Del(testDB, utils2.ToBytesList(key)) + testDB.Remove(key) ttl := "1000" - Set(testDB, utils2.ToBytesList(key, value, "EX", ttl)) - actual = Get(testDB, utils2.ToBytesList(key)) + execSet(testDB, utils2.ToBytesList(key, value, "EX", ttl)) + actual = execGet(testDB, utils2.ToBytesList(key)) asserts.AssertBulkReply(t, actual, value) - actual = TTL(testDB, utils2.ToBytesList(key)) + actual = execTTL(testDB, utils2.ToBytesList(key)) intResult, ok := actual.(*reply.IntReply) if !ok { t.Error(fmt.Sprintf("expected int reply, actually %s", actual.ToBytes())) @@ -73,12 +73,12 @@ func TestSet(t *testing.T) { } // set px - Del(testDB, utils2.ToBytesList(key)) + testDB.Remove(key) ttlPx := "1000000" - Set(testDB, utils2.ToBytesList(key, value, "PX", ttlPx)) - actual = Get(testDB, utils2.ToBytesList(key)) + execSet(testDB, utils2.ToBytesList(key, value, "PX", ttlPx)) + actual = execGet(testDB, utils2.ToBytesList(key)) asserts.AssertBulkReply(t, actual, value) - actual = TTL(testDB, utils2.ToBytesList(key)) + actual = execTTL(testDB, utils2.ToBytesList(key)) intResult, ok = actual.(*reply.IntReply) if !ok { 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) { - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) key := utils2.RandString(10) value := utils2.RandString(10) - SetNX(testDB, utils2.ToBytesList(key, value)) - actual := Get(testDB, utils2.ToBytesList(key)) + execSetNX(testDB, utils2.ToBytesList(key, value)) + actual := execGet(testDB, utils2.ToBytesList(key)) expected := reply.MakeBulkReply([]byte(value)) if !utils.BytesEquals(actual.ToBytes(), expected.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)) if !utils.BytesEquals(actual.ToBytes(), expected2.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) { - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) key := utils2.RandString(10) value := utils2.RandString(10) ttl := "1000" - SetEX(testDB, utils2.ToBytesList(key, ttl, value)) - actual := Get(testDB, utils2.ToBytesList(key)) + execSetEX(testDB, utils2.ToBytesList(key, ttl, value)) + actual := execGet(testDB, utils2.ToBytesList(key)) asserts.AssertBulkReply(t, actual, value) - actual = TTL(testDB, utils2.ToBytesList(key)) + actual = execTTL(testDB, utils2.ToBytesList(key)) intResult, ok := actual.(*reply.IntReply) if !ok { 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) { - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) key := utils2.RandString(10) value := utils2.RandString(10) ttl := "1000000" - PSetEX(testDB, utils2.ToBytesList(key, ttl, value)) - actual := Get(testDB, utils2.ToBytesList(key)) + execPSetEX(testDB, utils2.ToBytesList(key, ttl, value)) + actual := execGet(testDB, utils2.ToBytesList(key)) asserts.AssertBulkReply(t, actual, value) - actual = PTTL(testDB, utils2.ToBytesList(key)) + actual = execPTTL(testDB, utils2.ToBytesList(key)) intResult, ok := actual.(*reply.IntReply) if !ok { 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) { - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) size := 10 keys := make([]string, size) values := make([][]byte, size) @@ -162,8 +162,8 @@ func TestMSet(t *testing.T) { values[i] = []byte(value) args = append(args, keys[i], value) } - MSet(testDB, utils2.ToBytesList(args...)) - actual := MGet(testDB, utils2.ToBytesList(keys...)) + execMSet(testDB, utils2.ToBytesList(args...)) + actual := execMGet(testDB, utils2.ToBytesList(keys...)) expected := reply.MakeMultiBulkReply(values) if !utils.BytesEquals(actual.ToBytes(), expected.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) { - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) size := 10 key := utils2.RandString(10) for i := 0; i < size; i++ { - Incr(testDB, utils2.ToBytesList(key)) - actual := Get(testDB, utils2.ToBytesList(key)) + execIncr(testDB, utils2.ToBytesList(key)) + actual := execGet(testDB, utils2.ToBytesList(key)) expected := reply.MakeBulkReply([]byte(strconv.FormatInt(int64(i+1), 10))) if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) { t.Error("expected: " + string(expected.ToBytes()) + ", actual: " + string(actual.ToBytes())) } } for i := 0; i < size; i++ { - IncrBy(testDB, utils2.ToBytesList(key, "-1")) - actual := Get(testDB, utils2.ToBytesList(key)) + execIncrBy(testDB, utils2.ToBytesList(key, "-1")) + actual := execGet(testDB, utils2.ToBytesList(key)) expected := reply.MakeBulkReply([]byte(strconv.FormatInt(int64(size-i-1), 10))) if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) { t.Error("expected: " + string(expected.ToBytes()) + ", actual: " + string(actual.ToBytes())) } } - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) key = utils2.RandString(10) for i := 0; i < size; i++ { - IncrBy(testDB, utils2.ToBytesList(key, "1")) - actual := Get(testDB, utils2.ToBytesList(key)) + execIncrBy(testDB, utils2.ToBytesList(key, "1")) + actual := execGet(testDB, utils2.ToBytesList(key)) expected := reply.MakeBulkReply([]byte(strconv.FormatInt(int64(i+1), 10))) if !utils.BytesEquals(actual.ToBytes(), expected.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++ { - IncrByFloat(testDB, utils2.ToBytesList(key, "-1.0")) - actual := Get(testDB, utils2.ToBytesList(key)) + execIncrByFloat(testDB, utils2.ToBytesList(key, "-1.0")) + actual := execGet(testDB, utils2.ToBytesList(key)) expected := -i - 1 bulk, ok := actual.(*reply.BulkReply) if !ok { @@ -224,18 +224,18 @@ func TestIncr(t *testing.T) { } func TestDecr(t *testing.T) { - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) size := 10 key := utils2.RandString(10) for i := 0; i < size; i++ { - Decr(testDB, utils2.ToBytesList(key)) - actual := Get(testDB, utils2.ToBytesList(key)) + execDecr(testDB, utils2.ToBytesList(key)) + actual := execGet(testDB, utils2.ToBytesList(key)) asserts.AssertBulkReply(t, actual, strconv.Itoa(-i-1)) } - Del(testDB, utils2.ToBytesList(key)) + testDB.Remove(key) for i := 0; i < size; i++ { - DecrBy(testDB, utils2.ToBytesList(key, "1")) - actual := Get(testDB, utils2.ToBytesList(key)) + execDecrBy(testDB, utils2.ToBytesList(key, "1")) + actual := execGet(testDB, utils2.ToBytesList(key)) expected := -i - 1 bulk, ok := actual.(*reply.BulkReply) if !ok { @@ -255,11 +255,11 @@ func TestDecr(t *testing.T) { } func TestGetSet(t *testing.T) { - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) key := 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) if !ok { t.Errorf("expect null bulk reply, get: %s", string(result.ToBytes())) @@ -267,23 +267,23 @@ func TestGetSet(t *testing.T) { } value2 := utils2.RandString(10) - result = GetSet(testDB, utils2.ToBytesList(key, value2)) + result = execGetSet(testDB, utils2.ToBytesList(key, value2)) asserts.AssertBulkReply(t, result, value) - result = Get(testDB, utils2.ToBytesList(key)) + result = execGet(testDB, utils2.ToBytesList(key)) asserts.AssertBulkReply(t, result, value2) } func TestMSetNX(t *testing.T) { - FlushAll(testDB, [][]byte{}) + execFlushAll(testDB, [][]byte{}) size := 10 args := make([]string, 0, size*2) for i := 0; i < size; i++ { str := utils2.RandString(10) args = append(args, str, str) } - result := MSetNX(testDB, utils2.ToBytesList(args...)) + result := execMSetNX(testDB, utils2.ToBytesList(args...)) 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) }