add cmd_set commands and its tests

This commit is contained in:
holys 2014-08-15 10:42:40 +08:00
parent b1824af7d9
commit 00abaccbf2
4 changed files with 501 additions and 4 deletions

View File

@ -1,12 +1,12 @@
# LedisDB
Ledisdb is a high performance NoSQL like Redis written by go. It supports some advanced data structure like kv, list, hash, zset, bitmap, and may be alternative for Redis.
Ledisdb is a high performance NoSQL like Redis written by go. It supports some advanced data structure like kv, list, hash, zset, bitmap,set, and may be alternative for Redis.
LedisDB now supports multi databases as backend to store data, you can test and choose the proper one for you.
## Features
+ Rich advanced data structure: KV, List, Hash, ZSet, Bitmap.
+ Rich advanced data structure: KV, List, Hash, ZSet, Bitmap, Set.
+ Stores lots of data, over the memory limit.
+ Various backend database to use: LevelDB, goleveldb, LMDB, RocksDB, BoltDB.
+ Supports expiration and ttl.

View File

@ -129,9 +129,9 @@ func TestDBSet(t *testing.T) {
func TestSetOperation(t *testing.T) {
db := getTestDB()
// testUnion(db, t)
testUnion(db, t)
testInter(db, t)
// testDiff(db, t)
testDiff(db, t)
}
@ -232,6 +232,17 @@ func testInter(db *DB, t *testing.T) {
t.Fatal(n)
}
k1 := []byte("set_k1")
k2 := []byte("set_k2")
db.SAdd(k1, m1, m3, m4)
db.SAdd(k2, m2, m3)
if n, err := db.SInterStore([]byte("set_xxx"), k1, k2); err != nil {
t.Fatal(err)
} else if n != 1 {
t.Fatal(n)
}
v1, _ := db.SInter(key1, key2)
v2, _ := db.SInter(key2, key1)
if len(v1) != len(v2) {

283
server/cmd_set.go Normal file
View File

@ -0,0 +1,283 @@
package server
import (
"github.com/siddontang/ledisdb/ledis"
)
func saddCommand(req *requestContext) error {
args := req.args
if len(args) < 2 {
return ErrCmdParams
}
if n, err := req.db.SAdd(args[0], args[1:]...); err != nil {
return err
} else {
req.resp.writeInteger(n)
}
return nil
}
func soptGeneric(req *requestContext, optType byte) error {
args := req.args
if len(args) < 1 {
return ErrCmdParams
}
var v [][]byte
var err error
switch optType {
case ledis.UnionType:
v, err = req.db.SUnion(args...)
case ledis.DiffType:
v, err = req.db.SDiff(args...)
case ledis.InterType:
v, err = req.db.SInter(args...)
}
if err != nil {
return err
} else {
req.resp.writeSliceArray(v)
}
return nil
}
func soptStoreGeneric(req *requestContext, optType byte) error {
args := req.args
if len(args) < 2 {
return ErrCmdParams
}
var n int64
var err error
switch optType {
case ledis.UnionType:
n, err = req.db.SUnionStore(args[0], args[1:]...)
case ledis.DiffType:
n, err = req.db.SDiffStore(args[0], args[1:]...)
case ledis.InterType:
n, err = req.db.SInterStore(args[0], args[1:]...)
}
if err != nil {
return err
} else {
req.resp.writeInteger(n)
}
return nil
}
func scardCommand(req *requestContext) error {
args := req.args
if len(args) != 1 {
return ErrCmdParams
}
if n, err := req.db.SCard(args[0]); err != nil {
return err
} else {
req.resp.writeInteger(n)
}
return nil
}
func sdiffCommand(req *requestContext) error {
return soptGeneric(req, ledis.DiffType)
}
func sdiffstoreCommand(req *requestContext) error {
return soptStoreGeneric(req, ledis.DiffType)
}
func sinterCommand(req *requestContext) error {
return soptGeneric(req, ledis.InterType)
}
func sinterstoreCommand(req *requestContext) error {
return soptStoreGeneric(req, ledis.InterType)
}
func sismemberCommand(req *requestContext) error {
args := req.args
if len(args) != 2 {
return ErrCmdParams
}
if n, err := req.db.SIsMember(args[0], args[1]); err != nil {
return err
} else {
req.resp.writeInteger(n)
}
return nil
}
func smembersCommand(req *requestContext) error {
args := req.args
if len(args) != 1 {
return ErrCmdParams
}
if v, err := req.db.SMembers(args[0]); err != nil {
return err
} else {
req.resp.writeSliceArray(v)
}
return nil
}
func sremCommand(req *requestContext) error {
args := req.args
if len(args) < 2 {
return ErrCmdParams
}
if n, err := req.db.SRem(args[0], args[1:]...); err != nil {
return err
} else {
req.resp.writeInteger(n)
}
return nil
}
func sunionCommand(req *requestContext) error {
return soptGeneric(req, ledis.UnionType)
}
func sunionstoreCommand(req *requestContext) error {
return soptStoreGeneric(req, ledis.UnionType)
}
func sclearCommand(req *requestContext) error {
args := req.args
if len(args) != 1 {
return ErrCmdParams
}
if n, err := req.db.SClear(args[0]); err != nil {
return err
} else {
req.resp.writeInteger(n)
}
return nil
}
func smclearCommand(req *requestContext) error {
args := req.args
if len(args) < 1 {
return ErrCmdParams
}
if n, err := req.db.SMclear(args...); err != nil {
return err
} else {
req.resp.writeInteger(n)
}
return nil
}
func sexpireCommand(req *requestContext) error {
args := req.args
if len(args) != 2 {
return ErrCmdParams
}
duration, err := ledis.StrInt64(args[1], nil)
if err != nil {
return ErrValue
}
if v, err := req.db.SExpire(args[0], duration); err != nil {
return err
} else {
req.resp.writeInteger(v)
}
return nil
}
func sexpireAtCommand(req *requestContext) error {
args := req.args
if len(args) != 2 {
return ErrCmdParams
}
when, err := ledis.StrInt64(args[1], nil)
if err != nil {
return ErrValue
}
if v, err := req.db.SExpireAt(args[0], when); err != nil {
return err
} else {
req.resp.writeInteger(v)
}
return nil
}
func sttlCommand(req *requestContext) error {
args := req.args
if len(args) != 1 {
return ErrCmdParams
}
if v, err := req.db.STTL(args[0]); err != nil {
return err
} else {
req.resp.writeInteger(v)
}
return nil
}
func spersistCommand(req *requestContext) error {
args := req.args
if len(args) != 1 {
return ErrCmdParams
}
if n, err := req.db.SPersist(args[0]); err != nil {
return err
} else {
req.resp.writeInteger(n)
}
return nil
}
func init() {
register("sadd", saddCommand)
register("scard", scardCommand)
register("sdiff", sdiffCommand)
register("sdiffstore", sdiffstoreCommand)
register("sinter", sinterCommand)
register("sinterstore", sinterstoreCommand)
register("sismember", sismemberCommand)
register("smembers", smembersCommand)
register("srem", sremCommand)
register("sunion", sunionCommand)
register("sunionstore", sunionstoreCommand)
register("sclear", sclearCommand)
register("smclear", smclearCommand)
register("sexpire", sexpireCommand)
register("sexpireat", sexpireAtCommand)
register("sttl", sttlCommand)
register("spersist", spersistCommand)
}

203
server/cmd_set_test.go Normal file
View File

@ -0,0 +1,203 @@
package server
import (
"github.com/siddontang/ledisdb/client/go/ledis"
"testing"
)
func TestSet(t *testing.T) {
c := getTestConn()
defer c.Close()
key1 := "testdb_cmd_set_1"
key2 := "testdb_cmd_set_2"
if n, err := ledis.Int(c.Do("sadd", key1, 0, 1)); err != nil {
t.Fatal(err)
} else if n != 2 {
t.Fatal(n)
}
if n, err := ledis.Int(c.Do("sadd", key2, 0, 1, 2, 3)); err != nil {
t.Fatal(err)
} else if n != 4 {
t.Fatal(n)
}
if n, err := ledis.Int(c.Do("scard", key1)); err != nil {
t.Fatal(err)
} else if n != 2 {
t.Fatal(n)
}
if n, err := ledis.MultiBulk(c.Do("sdiff", key2, key1)); err != nil {
t.Fatal(err)
} else if len(n) != 2 {
t.Fatal(n)
}
if n, err := ledis.Int(c.Do("sdiffstore", []byte("cmd_set_em1"), key2, key1)); err != nil {
t.Fatal(err)
} else if n != 2 {
t.Fatal(n)
}
if n, err := ledis.MultiBulk(c.Do("sunion", key1, key2)); err != nil {
t.Fatal(err)
} else if len(n) != 4 {
t.Fatal(n)
}
if n, err := ledis.Int(c.Do("sunionstore", []byte("cmd_set_em2"), key1, key2)); err != nil {
t.Fatal(err)
} else if n != 4 {
t.Fatal(n)
}
if n, err := ledis.MultiBulk(c.Do("sinter", key1, key2)); err != nil {
t.Fatal(err)
} else if len(n) != 2 {
t.Fatal(n)
}
if n, err := ledis.Int(c.Do("sinterstore", []byte("cmd_set_em3"), key1, key2)); err != nil {
t.Fatal(err)
} else if n != 2 {
t.Fatal(n)
}
if n, err := ledis.Int(c.Do("srem", key1, 0, 1)); err != nil {
t.Fatal(err)
} else if n != 2 {
t.Fatal(n)
}
if n, err := ledis.Int(c.Do("sismember", key2, 0)); err != nil {
t.Fatal(err)
} else if n != 1 {
t.Fatal(n)
}
if n, err := ledis.MultiBulk(c.Do("smembers", key2)); err != nil {
t.Fatal(err)
} else if len(n) != 4 {
t.Fatal(n)
}
if n, err := ledis.Int(c.Do("sclear", key2)); err != nil {
t.Fatal(err)
} else if n != 4 {
t.Fatal(n)
}
c.Do("sadd", key1, 0)
c.Do("sadd", key2, 1)
if n, err := ledis.Int(c.Do("smclear", key1, key2)); err != nil {
t.Fatal(err)
} else if n != 2 {
t.Fatal(n)
}
}
func TestSetErrorParams(t *testing.T) {
c := getTestConn()
defer c.Close()
if _, err := c.Do("sadd", "test_sadd"); err == nil {
t.Fatal("invalid err of %v", err)
}
if _, err := c.Do("scard"); err == nil {
t.Fatal("invalid err of %v", err)
}
if _, err := c.Do("scard", "k1", "k2"); err == nil {
t.Fatal("invalid err of %v", err)
}
if _, err := c.Do("sdiff"); err == nil {
t.Fatal("invalid err of %v", err)
}
if _, err := c.Do("sdiffstore", "dstkey"); err == nil {
t.Fatal("invalid err of %v", err)
}
if _, err := c.Do("sinter"); err == nil {
t.Fatal("invalid err of %v", err)
}
if _, err := c.Do("sinterstore", "dstkey"); err == nil {
t.Fatal("invalid err of %v", err)
}
if _, err := c.Do("sunion"); err == nil {
t.Fatal("invalid err of %v", err)
}
if _, err := c.Do("sunionstore", "dstkey"); err == nil {
t.Fatal("invalid err of %v", err)
}
if _, err := c.Do("sismember", "k1"); err == nil {
t.Fatal("invalid err of %v", err)
}
if _, err := c.Do("sismember", "k1", "m1", "m2"); err == nil {
t.Fatal("invalid err of %v", err)
}
if _, err := c.Do("smembers"); err == nil {
t.Fatal("invalid err of %v", err)
}
if _, err := c.Do("smembers", "k1", "k2"); err == nil {
t.Fatal("invalid err of %v", err)
}
if _, err := c.Do("srem"); err == nil {
t.Fatal("invalid err of %v", err)
}
if _, err := c.Do("srem", "key"); err == nil {
t.Fatal("invalid err of %v", err)
}
if _, err := c.Do("sclear"); err == nil {
t.Fatal("invalid err of %v", err)
}
if _, err := c.Do("sclear", "k1", "k2"); err == nil {
t.Fatal("invalid err of %v", err)
}
if _, err := c.Do("smclear"); err == nil {
t.Fatal("invalid err of %v", err)
}
if _, err := c.Do("sexpire", "set_expire"); err == nil {
t.Fatal("invalid err of %v", err)
}
if _, err := c.Do("sexpire", "set_expire", "aaa"); err == nil {
t.Fatal("invalid err of %v", err)
}
if _, err := c.Do("sexpireat", "set_expireat"); err == nil {
t.Fatal("invalid err of %v", err)
}
if _, err := c.Do("sexpireat", "set_expireat", "aaa"); err == nil {
t.Fatal("invalid err of %v", err)
}
if _, err := c.Do("sttl"); err == nil {
t.Fatal("invalid err of %v", err)
}
if _, err := c.Do("spersist"); err == nil {
t.Fatal("invalid err of %v", err)
}
}