diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..68bd83c --- /dev/null +++ b/go.mod @@ -0,0 +1,8 @@ +module github.com/ssdb/gossdb + +go 1.14 + +require ( + github.com/pkg/errors v0.9.1 + github.com/stretchr/testify v1.7.0 +) diff --git a/main_test.go b/main_test.go new file mode 100644 index 0000000..3f9fbc4 --- /dev/null +++ b/main_test.go @@ -0,0 +1,78 @@ +package main + +import ( + "fmt" + "github.com/ssdb/gossdb/ssdb" + "github.com/stretchr/testify/require" + "strconv" + "testing" +) + +func TestData(t *testing.T) { + must := require.New(t) + ip := "127.0.0.1" + port := 8888 + db, err := ssdb.Connect(ip, port) + must.NoError(err) + + defer db.Close() + + //keys := []string{} + //keys = append(keys, "c") + //keys = append(keys, "d") + //val, err = db.Do("multi_get", "a", "b", keys) + mval, err := db.MultiGet("a", "b", "c", "d") + must.NoError(err) + fmt.Printf("%s\n", mval) + + err = db.Set("a", "xxx") + must.NoError(err) + + val, err := db.Get("a") + must.NoError(err) + //fmt.Printf("%s\n", val) + must.Equal(val.String(), "xxx") + + err = db.Del("a") + must.NoError(err) + + val, err = db.Get("a") + must.NoError(err) + //fmt.Printf("%s\n", val) + must.Equal(val.String(), "") + + fmt.Printf("----\n") + + //db.Do("zset", "z", "a", 3) + err = db.ZSet("z", "a", 3) + must.NoError(err) + + //db.Do("multi_zset", "z", "b", -2, "c", 5, "d", 3) + err = db.MultiZSet("z", map[string]int64{"b": -2, "c": 5, "d": 3}) + must.NoError(err) + + resp, err := db.Do("zrscan", "z", "", "", "", 10) + must.NoError(err) + must.False(len(resp)%2 != 1) + + fmt.Printf("Status: %s\n", resp[0]) + for i := 1; i < len(resp); i += 2 { + fmt.Printf(" %s : %3s\n", resp[i], resp[i+1]) + } + + fmt.Println("==zrscan.int64") + respKey, respVal, err := db.ZRScan("z", "", "", "", 10) + for i, n := 0, len(respVal); i < n; i++ { + fmt.Printf(" %s : %d\n", respKey[i], respVal[i]) + } + + //_ = db.Send("dump", "", "", "-1"); + _ = db.Send("sync140") + // receive multi responses on one request + for { + resp, _ := db.Recv() + fmt.Printf("%s\n", strconv.Quote(fmt.Sprintf("%s", resp))) + } + + return +} diff --git a/ssdb/hset.go b/ssdb/hset.go new file mode 100644 index 0000000..4aa2b7b --- /dev/null +++ b/ssdb/hset.go @@ -0,0 +1,467 @@ +package ssdb + +/** +code copy from github.com/seefan/gossdb/client v1.1.3 +*/ + +import ( + "github.com/pkg/errors" +) + +//HSet 设置 hashmap 中指定 key 对应的值内容. +// +// setName hashmap 的名字 +// key hashmap 的 key +// value key 的值 +// 返回 err,执行的错误 +func (c *Client) HSet(setName, key string, value interface{}) (err error) { + resp, err := c.Do("hset", setName, key, value) + if err != nil { + return errors.WithMessagef(err, "Hset %s/%s error ", setName, key) + } + + if len(resp) > 0 && resp[0] == oK { + return nil + } + return makeError(resp, setName, key) +} + +//HGet 获取 hashmap 中指定 key 的值内容. +// +// setName hashmap 的名字 +// key hashmap 的 key +// 返回 value key 的值 +// 返回 err,执行的错误 +func (c *Client) HGet(setName, key string) (value Value, err error) { + resp, err := c.Do("hget", setName, key) + if err != nil { + return "", errors.WithMessagef(err, "Hget %s/%s error", setName, key) + } + if len(resp) == 2 && resp[0] == oK { + return Value(resp[1]), nil + } + return "", makeError(resp, setName, key) +} + +//HDel 删除 hashmap 中的指定 key,不能通过返回值来判断被删除的 key 是否存在. +// +// setName hashmap 的名字 +// key hashmap 的 key +// 返回 err,执行的错误 +func (c *Client) HDel(setName, key string) (err error) { + resp, err := c.Do("hdel", setName, key) + if err != nil { + return errors.WithMessagef(err, "Hdel %s/%s error", setName, key) + } + if len(resp) > 0 && resp[0] == oK { + return nil + } + return makeError(resp, setName, key) +} + +//HExists 判断指定的 key 是否存在于 hashmap 中. +// +// setName hashmap 的名字 +// key hashmap 的 key +// 返回 re,如果当前 key 不存在返回 false +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) HExists(setName, key string) (re bool, err error) { + resp, err := c.Do("hexists", setName, key) + if err != nil { + return false, errors.WithMessagef(err, "Hexists %s/%s error", setName, key) + } + + if len(resp) == 2 && resp[0] == oK { + return resp[1] == "1", nil + } + return false, makeError(resp, setName, key) +} + +//HClear 删除 hashmap 中的所有 key +// +// setName hashmap 的名字 +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) HClear(setName string) (err error) { + resp, err := c.Do("hclear", setName) + if err != nil { + return errors.WithMessagef(err, "Hclear %s error", setName) + } + + if len(resp) > 0 && resp[0] == oK { + return nil + } + return makeError(resp, setName) +} + +//HScan 列出 hashmap 中处于区间 (key_start, key_end] 的 key-value 列表. ("", ""] 表示整个区间. +// +// setName - hashmap 的名字. +// keyStart - 返回的起始 key(不包含), 空字符串表示 -inf. +// keyEnd - 返回的结束 key(包含), 空字符串表示 +inf. +// limit - 最多返回这么多个元素. +// 返回包含 key-value 的关联字典. +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) HScan(setName string, keyStart, keyEnd string, limit int64, reverse ...bool) (map[string]Value, error) { + cmd := "hscan" + if len(reverse) > 0 && reverse[0] { + cmd = "hrscan" + } + + resp, err := c.Do(cmd, setName, keyStart, keyEnd, limit) + + if err != nil { + return nil, errors.WithMessagef(err, "%s %s %s %s %v error", cmd, setName, keyStart, keyEnd, limit) + } + + if len(resp) > 0 && resp[0] == oK { + re := make(map[string]Value) + size := len(resp) + for i := 1; i < size-1; i += 2 { + re[resp[i]] = Value(resp[i+1]) + } + return re, nil + } + return nil, makeError(resp, setName, keyStart, keyEnd, limit) +} + +//HScanArray 列出 hashmap 中处于区间 (key_start, key_end] 的 key,value 列表. ("", ""] 表示整个区间. +// +// setName - hashmap 的名字. +// keyStart - 返回的起始 key(不包含), 空字符串表示 -inf. +// keyEnd - 返回的结束 key(包含), 空字符串表示 +inf. +// limit - 最多返回这么多个元素. +// 返回包含 key-value 的关联字典. +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) HScanArray(setName string, keyStart, keyEnd string, limit int64, reverse ...bool) ([]string, []Value, error) { + cmd := "hscan" + if len(reverse) > 0 && reverse[0] { + cmd = "hrscan" + } + resp, err := c.Do(cmd, setName, keyStart, keyEnd, limit) + + if err != nil { + return nil, nil, errors.WithMessagef(err, "%s %s %s %s %v error", cmd, setName, keyStart, keyEnd, limit) + } + + if len(resp) > 0 && resp[0] == oK { + keys := []string{} + values := []Value{} + size := len(resp) + for i := 1; i < size-1; i += 2 { + keys = append(keys, resp[i]) + values = append(values, Value(resp[i+1])) + } + return keys, values, nil + } + return nil, nil, makeError(resp, setName, keyStart, keyEnd, limit) +} + +//HRScanArray 列出 hashmap 中处于区间 (key_start, key_end] 的 key,value 列表. ("", ""] 表示整个区间. +// +// setName - hashmap 的名字. +// keyStart - 返回的起始 key(不包含), 空字符串表示 -inf. +// keyEnd - 返回的结束 key(包含), 空字符串表示 +inf. +// limit - 最多返回这么多个元素. +// 返回包含 key-value 的关联字典. +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) HRScanArray(setName string, keyStart, keyEnd string, limit int64, reverse ...bool) ([]string, []Value, error) { + return c.HScanArray(setName, keyStart, keyEnd, limit, true) +} + +//HRScan 列出 hashmap 中处于区间 (key_start, key_end] 的 key-value 列表. ("", ""] 表示整个区间. +// +// setName - hashmap 的名字. +// keyStart - 返回的起始 key(不包含), 空字符串表示 -inf. +// keyEnd - 返回的结束 key(包含), 空字符串表示 +inf. +// limit - 最多返回这么多个元素. +// 返回包含 key-value 的关联字典. +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) HRScan(setName string, keyStart, keyEnd string, limit int64) (map[string]Value, error) { + return c.HScan(setName, keyStart, keyEnd, limit, true) +} + +//MultiHSet 批量设置 hashmap 中的 key-value. +// +// setName - hashmap 的名字. +// kvs - 包含 key-value 的关联数组 . +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) MultiHSet(setName string, kvs map[string]interface{}) (err error) { + + args := []interface{}{"multi_hset", setName} + for k, v := range kvs { + args = append(args, k) + args = append(args, v) + } + resp, err := c.Do(args...) + + if err != nil { + return errors.WithMessagef(err, "MultiHset %s %s error", setName, kvs) + } + + if len(resp) > 0 && resp[0] == oK { + return nil + } + return makeError(resp, setName, kvs) +} + +//MultiHGet 批量获取 hashmap 中多个 key 对应的权重值. +// +// setName - hashmap 的名字. +// keys - 包含 key 的数组 . +// 返回 包含 key-value 的关联数组, 如果某个 key 不存在, 则它不会出现在返回数组中. +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) MultiHGet(setName string, key ...string) (val map[string]Value, err error) { + if len(key) == 0 { + return make(map[string]Value), nil + } + + args := make([]interface{}, len(key)+2) + args[0] = "multi_hget" + args[1] = setName + + for i, v := range key { + args[i+2] = v + } + + resp, err := c.Do(args...) + if err != nil { + return nil, errors.WithMessagef(err, "MultiHget %s %s error", setName, key) + } + size := len(resp) + if size > 0 && resp[0] == oK { + val = make(map[string]Value) + for i := 1; i < size && i+1 < size; i += 2 { + val[resp[i]] = Value(resp[i+1]) + } + return val, nil + } + return nil, makeError(resp, key) +} + +//MultiHGetSlice 批量获取 hashmap 中多个 key 对应的权重值. +// +// setName - hashmap 的名字. +// keys - 包含 key 的数组 . +// 返回 包含 key和value 的有序数组, 如果某个 key 不存在, 则它不会出现在返回数组中. +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) MultiHGetSlice(setName string, key ...string) (keys []string, values []Value, err error) { + if len(key) == 0 { + return []string{}, []Value{}, nil + } + args := []interface{}{"multi_hget", setName} + for _, v := range key { + args = append(args, v) + } + resp, err := c.Do(args...) + + if err != nil { + return nil, nil, errors.WithMessagef(err, "MultiHgetSlice %s %s error", setName, key) + } + if len(resp) > 0 && resp[0] == oK { + size := len(resp) + keys := make([]string, 0, (size-1)/2) + values := make([]Value, 0, (size-1)/2) + + for i := 1; i < size && i+1 < size; i += 2 { + keys = append(keys, resp[i]) + values = append(values, Value(resp[i+1])) + } + return keys, values, nil + } + return nil, nil, makeError(resp, key) +} + +//MultiHGetArray 批量获取 hashmap 中多个 key 对应的权重值.(输入分片) +// +// setName - hashmap 的名字. +// keys - 包含 key 的数组 . +// 返回 包含 key-value 的关联数组, 如果某个 key 不存在, 则它不会出现在返回数组中. +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) MultiHGetArray(setName string, key []string) (val map[string]Value, err error) { + return c.MultiHGet(setName, key...) +} + +//MultiHGetSliceArray 批量获取 hashmap 中多个 key 对应的权重值.(输入分片) +// +// setName - hashmap 的名字. +// keys - 包含 key 的数组 . +// 返回 包含 key和value 的有序数组, 如果某个 key 不存在, 则它不会出现在返回数组中. +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) MultiHGetSliceArray(setName string, key []string) (keys []string, values []Value, err error) { + return c.MultiHGetSlice(setName, key...) +} + +//MultiHGetAll 批量获取 hashmap 中全部 对应的权重值. +// +// setName - hashmap 的名字. +// keys - 包含 key 的数组 . +// 返回 包含 key-value 的关联数组, 如果某个 key 不存在, 则它不会出现在返回数组中. +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) MultiHGetAll(setName string) (val map[string]Value, err error) { + + resp, err := c.Do("hgetall", setName) + + if err != nil { + return nil, errors.WithMessagef(err, "MultiHgetAll %s error", setName) + } + size := len(resp) + if size > 0 && resp[0] == oK { + val = make(map[string]Value) + for i := 1; i < size && i+1 < size; i += 2 { + val[resp[i]] = Value(resp[i+1]) + } + return val, nil + } + return nil, makeError(resp) +} + +//MultiHGetAllSlice 批量获取 hashmap 中全部 对应的权重值. +// +// setName - hashmap 的名字. +// 返回 包含 key和value 的有序数组, 如果某个 key 不存在, 则它不会出现在返回数组中. +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) MultiHGetAllSlice(setName string) (keys []string, values []Value, err error) { + + resp, err := c.Do("hgetall", setName) + + if err != nil { + return nil, nil, errors.WithMessagef(err, "MultiHgetAllSlice %s error", setName) + } + if len(resp) > 0 && resp[0] == oK { + size := len(resp) + keys := make([]string, 0, (size-1)/2) + values := make([]Value, 0, (size-1)/2) + + for i := 1; i < size && i+1 < size; i += 2 { + keys = append(keys, resp[i]) + values = append(values, Value(resp[i+1])) + } + return keys, values, nil + } + return nil, nil, makeError(resp) +} + +//MultiHDel 批量删除 hashmap 中的 key. +// +// setName - hashmap 的名字. +// keys - 包含 key 的数组. +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) MultiHDel(setName string, key ...string) (err error) { + if len(key) == 0 { + return nil + } + args := []interface{}{"multi_hdel", setName} + for _, v := range key { + args = append(args, v) + } + resp, err := c.Do(args...) + if err != nil { + return errors.WithMessagef(err, "MultiHdel %s %s error", setName, key) + } + + if len(resp) > 0 && resp[0] == oK { + return nil + } + return makeError(resp, key) +} + +//MultiHDelArray 批量删除 hashmap 中的 key.(输入分片) +// +// setName - hashmap 的名字. +// keys - 包含 key 的数组. +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) MultiHDelArray(setName string, key []string) (err error) { + return c.MultiHDel(setName, key...) +} + +//HList 列出名字处于区间 (name_start, name_end] 的 hashmap. ("", ""] 表示整个区间. +// +// nameStart - 返回的起始 key(不包含), 空字符串表示 -inf. +// nameEnd - 返回的结束 key(包含), 空字符串表示 +inf. +// limit - 最多返回这么多个元素. +// 返回 包含名字的数组 +// 返回 err,执行的错D,操作成功返回 nil +func (c *Client) HList(nameStart, nameEnd string, limit int64) ([]string, error) { + resp, err := c.Do("hlist", nameStart, nameEnd, limit) + if err != nil { + return nil, errors.WithMessagef(err, "Hlist %s %s %v error", nameStart, nameEnd, limit) + } + + if len(resp) > 0 && resp[0] == oK { + size := len(resp) + keyList := make([]string, 0, size-1) + + for i := 1; i < size; i++ { + keyList = append(keyList, resp[i]) + } + return keyList, nil + } + return nil, makeError(resp, nameStart, nameEnd, limit) +} + +//HIncr 设置 hashmap 中指定 key 对应的值增加 num. 参数 num 可以为负数. +// +// setName - hashmap 的名字. +// key 键值 +// num 增加的值 +// 返回 val,整数,增加 num 后的新值 +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) HIncr(setName, key string, num int64) (val int64, err error) { + + resp, err := c.Do("hincr", setName, key, num) + + if err != nil { + return -1, errors.WithMessagef(err, "Hincr %s error", key) + } + if len(resp) == 2 && resp[0] == oK { + return Value(resp[1]).Int64(), nil + } + return -1, makeError(resp, key) +} + +//HSize 返回 hashmap 中的元素个数. +// +// setName - hashmap 的名字. +// 返回 val,整数,增加 num 后的新值 +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) HSize(setName string) (val int64, err error) { + + resp, err := c.Do("hsize", setName) + + if err != nil { + return -1, errors.WithMessagef(err, "Hsize %s error", setName) + } + if len(resp) == 2 && resp[0] == oK { + return Value(resp[1]).Int64(), nil + } + return -1, makeError(resp, setName) +} + +//HKeys 列出 hashmap 中处于区间 (keyStart, keyEnd] 的 key 列表. +// +// name - hashmap 的名字. +// keyStart - 返回的起始 key(不包含), 空字符串表示 -inf. +// keyEnd - 返回的结束 key(包含), 空字符串表示 +inf. +// limit - 最多返回这么多个元素. +// 返回 包含名字的数组 +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) HKeys(setName, keyStart, keyEnd string, limit int64) ([]string, error) { + resp, err := c.Do("hkeys", setName, keyStart, keyEnd, limit) + if err != nil { + return nil, errors.WithMessagef(err, "Hkeys %s %s %s %v error", setName, keyStart, keyEnd, limit) + } + + if len(resp) > 0 && resp[0] == oK { + return resp[1:], nil + } + return nil, makeError(resp, keyStart, keyEnd, limit) +} + +//HGetAll 批量获取 hashmap 中全部 对应的权重值. +// +// setName - hashmap 的名字. +// 返回 包含 key-value 的关联数组, 如果某个 key 不存在, 则它不会出现在返回数组中. +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) HGetAll(setName string) (val map[string]Value, err error) { + return c.MultiHGetAll(setName) +} diff --git a/ssdb/queue.go b/ssdb/queue.go new file mode 100644 index 0000000..6143f78 --- /dev/null +++ b/ssdb/queue.go @@ -0,0 +1,466 @@ +package ssdb + +/** +code copy from github.com/seefan/gossdb/client v1.1.3 +*/ +import ( + "github.com/pkg/errors" +) + +var ( + qTrimCmd = []string{"qtrim_front", "qtrim_back"} + qPushCmd = []string{"qpush_front", "qpush_back"} + qPopCmd = []string{"qpop_front", "qpop_back"} + qSliceCmd = []string{"qslice", "qrange"} +) + +//QSize 返回队列的长度. +// +// name 队列的名字 +// 返回 size,队列的长度; +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) QSize(name string) (size int64, err error) { + resp, err := c.Do("qsize", name) + if err != nil { + return -1, errors.WithMessagef(err, "Qsize %s error", name) + } + + if len(resp) == 2 && resp[0] == oK { + return Value(resp[1]).Int64(), nil + } + return -1, makeError(resp, name) +} + +//QClear 清空一个队列. +// +// name 队列的名字 +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) QClear(name string) (err error) { + resp, err := c.Do("qclear", name) + if err != nil { + return errors.WithMessagef(err, "Qclear %s error", name) + } + + if len(resp) > 0 && resp[0] == oK { + return nil + } + return makeError(resp, name) +} + +//QPushFront 往队列的首部添加一个或者多个元素 +// +// name 队列的名字 +// value 存贮的值,可以为多值. +// 返回 size,添加元素之后, 队列的长度 +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) QPushFront(name string, value ...interface{}) (size int64, err error) { + return c.qPush(name, false, value...) +} + +//qPush 往队列的首部添加一个或者多个元素 +// +// name 队列的名字 +// reverse 是否反向 +// value 存贮的值,可以为多值. +// 返回 size,添加元素之后, 队列的长度 +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) qPush(name string, reverse bool, value ...interface{}) (size int64, err error) { + if len(value) == 0 { + return -1, nil + } + index := 0 + if reverse { + index = 1 + } + args := []interface{}{qPushCmd[index], name} + + args = append(args, value...) + + resp, err := c.Do(args...) + if err != nil { + return -1, errors.WithMessagef(err, "%s %s error", qPushCmd[index], name) + } + if len(resp) == 2 && resp[0] == oK { + return Value(resp[1]).Int64(), nil + } + return -1, makeError(resp, name) +} + +//QPush 往队列的尾部添加一个或者多个元素 +// +// name 队列的名字 +// value 存贮的值,可以为多值. +// 返回 size,添加元素之后, 队列的长度 +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) QPush(name string, value ...interface{}) (size int64, err error) { + return c.qPush(name, true, value...) +} + +//QPushBack 往队列的尾部添加一个或者多个元素 +// +// name 队列的名字 +// value 存贮的值,可以为多值. +// 返回 size,添加元素之后, 队列的长度 +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) QPushBack(name string, value ...interface{}) (size int64, err error) { + return c.qPush(name, true, value...) +} + +//QPopFront 从队列首部弹出最后一个元素. +// +// name 队列的名字 +// 返回 v,返回一个元素,并在队列中删除 v;队列为空时返回空值 +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) QPopFront(name string) (v Value, err error) { + return c.QPop(name) +} + +//QPopBack 从队列尾部弹出最后一个元素. +// +// name 队列的名字 +// 返回 v,返回一个元素,并在队列中删除 v;队列为空时返回空值 +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) QPopBack(name string) (v Value, err error) { + return c.QPop(name, true) +} + +//QPop 从队列首部弹出最后一个元素. +// +// name 队列的名字 +// 返回 v,返回一个元素,并在队列中删除 v;队列为空时返回空值 +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) QPop(name string, reverse ...bool) (v Value, err error) { + index := 0 + if len(reverse) > 0 && !reverse[0] { + index = 1 + } + resp, err := c.Do(qPopCmd[index], name) + if err != nil { + return "", errors.WithMessagef(err, "%s %s error", qPopCmd[index], name) + } + if len(resp) == 2 && resp[0] == oK { + return Value(resp[1]), nil + } + return "", makeError(resp, name) +} + +//QPopFrontArray 从队列首部弹出最后多个元素. +// +// name 队列的名字 +// 返回 v,返回多个元素,并在队列中弹出多个元素; +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) QPopFrontArray(name string, size int64) (v []Value, err error) { + return c.QPopArray(name, size, false) +} + +//QPopBackArray 从队列尾部弹出最后多个元素. +// +// name 队列的名字 +// 返回 v,返回多个元素,并在队列中弹出多个元素; +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) QPopBackArray(name string, size int64) (v []Value, err error) { + return c.QPopArray(name, size, true) +} + +//QPopArray 从队列首部弹出最后多个个元素. +// +// name 队列的名字 +// size 取出元素的数量 +// reverse 是否反转取 +// 返回 v,返回多个元素,并在队列中弹出多个元素; +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) QPopArray(name string, size int64, reverse ...bool) (v []Value, err error) { + index := 1 + if len(reverse) > 0 && !reverse[0] { + index = 0 + } + resp, err := c.Do(qPopCmd[index], name, size) + if err != nil { + return nil, errors.WithMessagef(err, "%s %s error", qPopCmd[index], name) + } + + respsize := len(resp) + if respsize > 0 && resp[0] == oK { + for i := 1; i < respsize; i++ { + v = append(v, Value(resp[i])) + } + return + } + return nil, makeError(resp, name) +} + +//QRange 返回下标处于区域 [offset, offset + limit] 的元素. +// +// name queue 的名字. +// offset 整数, 从此下标处开始返回. 从 0 开始. 可以是负数, 表示从末尾算起. +// limit 正整数, 最多返回这么多个元素. +// 返回 v,返回元素的数组,为空时返回 nil +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) QRange(name string, offset, limit int) (v []Value, err error) { + return c.slice(name, offset, limit, 1) +} + +//QSlice 返回下标处于区域 [begin, end] 的元素. begin 和 end 可以是负数 +// +// name queue 的名字. +// begin 正整数, 从此下标处开始返回。从 0 开始。 +// end 整数, 结束下标。可以是负数, 表示返回所有。 +// 返回 v,返回元素的数组,为空时返回 nil +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) QSlice(name string, begin, end int) (v []Value, err error) { + return c.slice(name, begin, end, 0) +} + +//slice 返回下标处于区域 [begin, end] 的元素. begin 和 end 可以是负数 +// +// name queue 的名字. +// begin 正整数, 从此下标处开始返回。从 0 开始。 +// end 整数, 结束下标。可以是负数, 表示返回所有。 +// [slice,range] 命令 +// 返回 v,返回元素的数组,为空时返回 nil +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) slice(name string, args ...int) (v []Value, err error) { + begin := 0 + end := -1 + index := 0 + if len(args) > 0 { + begin = args[0] + } + if len(args) > 1 { + end = args[1] + } + + if len(args) > 2 { + index = args[2] + } + resp, err := c.Do(qSliceCmd[index], name, begin, end) + if err != nil { + return nil, errors.WithMessagef(err, "%s %s error", qSliceCmd[index], name) + } + size := len(resp) + if size >= 1 && resp[0] == oK { + for i := 1; i < size; i++ { + v = append(v, Value(resp[i])) + } + return + } + return nil, makeError(resp, name) +} + +//QTrim 从队列头部删除多个元素. +// +// name queue 的名字. +// size 最多从队列删除这么多个元素 +// reverse 可选,是否反向执行 +// 返回 delSize,返回被删除的元素数量 +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) QTrim(name string, size int, reverse ...bool) (delSize int64, err error) { + index := 0 + if len(reverse) > 0 && reverse[0] { + index = 1 + } + resp, err := c.Do(qTrimCmd[index], name, size) + if err != nil { + return -1, errors.WithMessagef(err, "%s %s error", qTrimCmd[index], name) + } + if len(resp) == 2 && resp[0] == oK { + return Value(resp[1]).Int64(), nil + } + return -1, makeError(resp, name) +} + +//QTrimFront 从队列头部删除多个元素. +// +// name queue 的名字. +// size 最多从队列删除这么多个元素 +// 返回 v,返回元素的数组,为空时返回 nil +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) QTrimFront(name string, size int) (delSize int64, err error) { + return c.QTrim(name, size) +} + +//QTrimBack 从队列尾部删除多个元素. +// +// name queue 的名字. +// size 最多从队列删除这么多个元素 +// 返回 v,返回元素的数组,为空时返回 nil +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) QTrimBack(name string, size int) (delSize int64, err error) { + return c.QTrim(name, size, true) +} + +//QList 列出名字处于区间 (name_start, name_end] 的 queue/list. +// +// name_start 返回的起始名字(不包含), 空字符串表示 -inf. +// name_end 返回的结束名字(包含), 空字符串表示 +inf. +// limit 最多返回这么多个元素. +// 返回 v,返回元素的数组,为空时返回 nil +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) QList(nameStart, nameEnd string, limit int64) ([]string, error) { + resp, err := c.Do("qlist", nameStart, nameEnd, limit) + if err != nil { + return nil, errors.WithMessagef(err, "Qlist %s %s %v error", nameStart, nameEnd, limit) + } + + if len(resp) > 0 && resp[0] == oK { + size := len(resp) + keyList := make([]string, 0, size-1) + + for i := 1; i < size; i++ { + keyList = append(keyList, resp[i]) + } + return keyList, nil + } + return nil, makeError(resp, nameStart, nameEnd, limit) +} + +//QRList 列出名字处于区间 (name_start, name_end] 的 queue/list. +// +// name_start 返回的起始名字(不包含), 空字符串表示 -inf. +// name_end 返回的结束名字(包含), 空字符串表示 +inf. +// limit 最多返回这么多个元素. +// 返回 v,返回元素的数组,为空时返回 nil +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) QRList(nameStart, nameEnd string, limit int64) ([]string, error) { + resp, err := c.Do("qrlist", nameStart, nameEnd, limit) + if err != nil { + return nil, errors.WithMessagef(err, "Qrlist %s %s %v error", nameStart, nameEnd, limit) + } + + if len(resp) > 0 && resp[0] == oK { + size := len(resp) + keyList := make([]string, 0, size-1) + + for i := 1; i < size; i++ { + keyList = append(keyList, resp[i]) + } + return keyList, nil + } + return nil, makeError(resp, nameStart, nameEnd, limit) +} + +//QSet 更新位于 index 位置的元素. 如果超过现有的元素范围, 会返回错误. +// +// key 队列的名字 +// index 指定的位置,可传负数. +// val 传入的值. +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) QSet(key string, index int64, val interface{}) (err error) { + var resp []string + + resp, err = c.Do("qset", key, index, val) + + if err != nil { + return errors.WithMessagef(err, "Qset %s error", key) + } + if len(resp) > 0 && resp[0] == oK { + return nil + } + return makeError(resp, key) +} + +//QGet 返回指定位置的元素. 0 表示第一个元素, 1 是第二个 ... -1 是最后一个. +// +// key 队列的名字 +// index 指定的位置,可传负数. +// 返回 val,返回的值. +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) QGet(key string, index int64) (Value, error) { + resp, err := c.Do("qget", key, index) + if err != nil { + return "", errors.WithMessagef(err, "Qget %s error", key) + } + if len(resp) == 2 && resp[0] == oK { + return Value(resp[1]), nil + } + return "", makeError(resp, key) +} + +//QFront 返回队列的第一个元素. +// +// key 队列的名字 +// 返回 val,返回的值. +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) QFront(key string) (Value, error) { + resp, err := c.Do("qfront", key) + if err != nil { + return "", errors.WithMessagef(err, "Qfront %s error", key) + } + if len(resp) == 2 && resp[0] == oK { + return Value(resp[1]), nil + } + return "", makeError(resp, key) +} + +//QBack 返回队列的最后一个元素. +// +// key 队列的名字 +// 返回 val,返回的值. +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) QBack(key string) (Value, error) { + resp, err := c.Do("qback", key) + if err != nil { + return "", errors.WithMessagef(err, "Qback %s error", key) + } + if len(resp) == 2 && resp[0] == oK { + return Value(resp[1]), nil + } + return "", makeError(resp, key) +} + +//qPushArray 往队列的首部添加一个或者多个元素 +// +// name 队列的名字 +// reverse 是否反向 +// value 存贮的值,可以为多值. +// 返回 size,添加元素之后, 队列的长度 +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) qPushArray(name string, reverse bool, value []interface{}) (size int64, err error) { + if len(value) == 0 { + return -1, nil + } + index := 0 + if reverse { + index = 1 + } + args := []interface{}{qPushCmd[index], name} + args = append(args, value...) + resp, err := c.Do(args...) + if err != nil { + return -1, errors.WithMessagef(err, "%s %s error", qPushCmd[index], name) + } + if len(resp) == 2 && resp[0] == oK { + return Value(resp[1]).Int64(), nil + } + return -1, makeError(resp, name) +} + +//QPushArray 往队列的尾部添加一个或者多个元素 +// +// name 队列的名字 +// value 存贮的值,可以为多值. +// 返回 size,添加元素之后, 队列的长度 +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) QPushArray(name string, value []interface{}) (size int64, err error) { + return c.qPushArray(name, true, value) +} + +//QPushBackArray 往队列的尾部添加一个或者多个元素 +// +// name 队列的名字 +// value 存贮的值,可以为多值. +// 返回 size,添加元素之后, 队列的长度 +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) QPushBackArray(name string, value []interface{}) (size int64, err error) { + return c.qPushArray(name, true, value) +} + +//QPushFrontArray 往队列的首部添加一个或者多个元素 +// +// name 队列的名字 +// value 存贮的值,可以为多值. +// 返回 size,添加元素之后, 队列的长度 +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) QPushFrontArray(name string, value []interface{}) (size int64, err error) { + return c.qPushArray(name, false, value) +} diff --git a/ssdb/set.go b/ssdb/set.go new file mode 100644 index 0000000..c9a5864 --- /dev/null +++ b/ssdb/set.go @@ -0,0 +1,509 @@ +package ssdb + +/** +code copy from github.com/seefan/gossdb/client v1.1.3 +*/ +import ( + "github.com/pkg/errors" +) + +//Set 设置指定 key 的值内容 +// +// key 键值 +// val 存贮的 value 值,val只支持基本的类型,如果要支持复杂的类型,需要开启连接池的 Encoding 选项 +// ttl 可选,设置的过期时间,单位为秒 +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) Set(key string, val interface{}, ttl ...int64) (err error) { + var resp []string + if len(ttl) > 0 { + resp, err = c.Do("setx", key, val, ttl[0]) + } else { + resp, err = c.Do("set", key, val) + } + if err != nil { + return errors.WithMessagef(err, "Set %s error", key) + } + if len(resp) > 0 && resp[0] == oK { + return nil + } + return makeError(resp, key) +} + +//SetNX 当 key 不存在时, 设置指定 key 的值内容. 如果已存在, 则不设置. +// +// key 键值 +// val 存贮的 value 值,val只支持基本的类型,如果要支持复杂的类型,需要开启连接池的 Encoding 选项 +// 返回 err,可能的错误,操作成功返回 nil +// 返回 val 1: value 已经设置, 0: key 已经存在, 不更新. +func (c *Client) SetNX(key string, val interface{}) (Value, error) { + resp, err := c.Do("setnx", key, val) + + if err != nil { + return "", errors.WithMessagef(err, "Setnx %s error", key) + } + if len(resp) > 0 && resp[0] == oK { + return Value(resp[1]), nil + } + return "", makeError(resp, key) +} + +//Get 获取指定 key 的值内容 +// +// key 键值 +// 返回 一个 Value,可以方便的向其它类型转换 +// 返回 一个可能的错误,操作成功返回 nil +func (c *Client) Get(key string) (Value, error) { + resp, err := c.Do("get", key) + if err != nil { + return "", errors.WithMessagef(err, "Get %s error", key) + } + if len(resp) == 2 && resp[0] == oK { + return Value(resp[1]), nil + } + return "", makeError(resp, key) +} + +//GetSet 更新 key 对应的 value, 并返回更新前的旧的 value. +// +// key 键值 +// val 存贮的 value 值,val只支持基本的类型,如果要支持复杂的类型,需要开启连接池的 Encoding 选项 +// 返回 一个 Value,可以方便的向其它类型转换.如果 key 不存在则返回 "", 否则返回 key 对应的值内容. +// 返回 一个可能的错误,操作成功返回 nil +func (c *Client) GetSet(key string, val interface{}) (Value, error) { + resp, err := c.Do("getset", key, val) + if err != nil { + return "", errors.WithMessagef(err, "Getset %s error", key) + } + if len(resp) == 2 && resp[0] == oK { + return Value(resp[1]), nil + } + return "", makeError(resp, key) +} + +//Expire 设置过期 +// +// key 要设置过期的 key +// ttl 存活时间(秒) +// 返回 re,设置是否成功,如果当前 key 不存在返回 false +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) Expire(key string, ttl int64) (re bool, err error) { + resp, err := c.Do("expire", key, ttl) + if err != nil { + return false, errors.WithMessagef(err, "Expire %s error", key) + } + if len(resp) == 2 && resp[0] == oK { + return resp[1] == "1", nil + } + return false, makeError(resp, key, ttl) +} + +//Exists 查询指定 key 是否存在 +// +// key 要查询的 key +// 返回 re,如果当前 key 不存在返回 false +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) Exists(key string) (re bool, err error) { + resp, err := c.Do("exists", key) + if err != nil { + return false, errors.WithMessagef(err, "Exists %s error", key) + } + + if len(resp) == 2 && resp[0] == oK { + return resp[1] == "1", nil + } + return false, makeError(resp, key) +} + +//Del 删除指定 key +// +// key 要删除的 key +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) Del(key string) error { + resp, err := c.Do("del", key) + if err != nil { + return errors.WithMessagef(err, "Del %s error", key) + } + + //response looks like s: [ok 1] + if len(resp) > 0 && resp[0] == oK { + return nil + } + return makeError(resp, key) +} + +//TTL 返回 key(只针对 KV 类型) 的存活时间. +// +// key 要删除的 key +// 返回 ttl,key 的存活时间(秒), -1 表示没有设置存活时间. +// 返回 err,执行的错误,操作成功返回 nil +func (c *Client) TTL(key string) (ttl int64, err error) { + resp, err := c.Do("ttl", key) + if err != nil { + return -1, errors.WithMessagef(err, "Ttl %s error", key) + } + + //response looks like s: [ok 1] + if len(resp) > 0 && resp[0] == oK { + return Value(resp[1]).Int64(), nil + } + return -1, makeError(resp, key) +} + +//Incr 使 key 对应的值增加 num. 参数 num 可以为负数. +// +// key 键值 +// num 增加的值 +// 返回 val,整数,增加 num 后的新值 +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) Incr(key string, num int64) (val int64, err error) { + + resp, err := c.Do("incr", key, num) + + if err != nil { + return -1, errors.WithMessagef(err, "Incr %s error", key) + } + if len(resp) == 2 && resp[0] == oK { + return Value(resp[1]).Int64(), nil + } + return -1, makeError(resp, key) +} + +//MultiSet 批量设置一批 key-value. +// +// 包含 key-value 的字典 +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) MultiSet(kvs map[string]interface{}) (err error) { + + args := []interface{}{"multi_set"} + + for k, v := range kvs { + args = append(args, k) + args = append(args, v) + } + resp, err := c.Do(args...) + + if err != nil { + return errors.WithMessagef(err, "MultiSet %s error", kvs) + } + + if len(resp) > 0 && resp[0] == oK { + return nil + } + return makeError(resp, kvs) +} + +//MultiGet 批量获取一批 key 对应的值内容. +// +// key,要获取的 key,可以为多个 +// 返回 val,一个包含返回的 map +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) MultiGet(key ...string) (val map[string]Value, err error) { + if len(key) == 0 { + return make(map[string]Value), nil + } + data := []interface{}{"multi_get"} + for _, k := range key { + data = append(data, k) + } + resp, err := c.Do(data...) + + if err != nil { + return nil, errors.WithMessagef(err, "MultiGet %s error", key) + } + + size := len(resp) + if size > 0 && resp[0] == oK { + val = make(map[string]Value) + for i := 1; i < size && i+1 < size; i += 2 { + val[resp[i]] = Value(resp[i+1]) + } + return val, nil + } + return nil, makeError(resp, key) +} + +//MultiGetSlice 批量获取一批 key 对应的值内容. +// +// key,要获取的 key,可以为多个 +// 返回 keys和value分片 +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) MultiGetSlice(key ...string) (keys []string, values []Value, err error) { + if len(key) == 0 { + return []string{}, []Value{}, nil + } + args := []interface{}{"multi_get"} + + for _, v := range key { + args = append(args, v) + } + + resp, err := c.Do(args...) + + if err != nil { + return nil, nil, errors.WithMessagef(err, "MultiGet %s error", key) + } + + size := len(resp) + if size > 0 && resp[0] == oK { + + keys := make([]string, 0, (size-1)/2) + values := make([]Value, 0, (size-1)/2) + + for i := 1; i < size && i+1 < size; i += 2 { + keys = append(keys, resp[i]) + values = append(values, Value(resp[i+1])) + } + return keys, values, nil + } + return nil, nil, makeError(resp, key) +} + +//MultiGetArray 批量获取一批 key 对应的值内容.(输入分片),MultiGet的别名 +// +// key,要获取的 key,可以为多个 +// 返回 val,一个包含返回的 map +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) MultiGetArray(key []string) (val map[string]Value, err error) { + return c.MultiGet(key...) +} + +//MultiGetSliceArray 批量获取一批 key 对应的值内容.(输入分片),MultiGetSlice的别名 +// +// key,要获取的 key,可以为多个 +// 返回 keys和value分片 +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) MultiGetSliceArray(key []string) (keys []string, values []Value, err error) { + return c.MultiGetSlice(key...) +} + +//MultiDel 批量删除一批 key 和其对应的值内容. +// +// key,要删除的 key,可以为多个 +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) MultiDel(key ...string) (err error) { + if len(key) == 0 { + return nil + } + args := []interface{}{"multi_del"} + for _, v := range key { + args = append(args, v) + } + resp, err := c.Do(args...) + if err != nil { + return errors.WithMessagef(err, "MultiDel %s error", key) + } + + if len(resp) > 0 && resp[0] == oK { + return nil + } + return makeError(resp, key) +} + +//Setbit 设置字符串内指定位置的位值(BIT), 字符串的长度会自动扩展. +// +// key 键值 +// offset 位偏移 +// bit 0 或 1 +// 返回 val,原来的位值 +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) Setbit(key string, offset int64, bit int) (uint, error) { + + resp, err := c.Do("setbit", key, offset, bit) + + if err != nil { + return 0, errors.WithMessagef(err, "Setbit %s error", key) + } + if len(resp) == 2 && resp[0] == oK { + return Value(resp[1]).UInt(), nil + } + return 0, makeError(resp, key) +} + +//Getbit 获取字符串内指定位置的位值(BIT). +// +// key 键值 +// offset 位偏移 +// 返回 val,位值 +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) Getbit(key string, offset int64) (uint, error) { + + resp, err := c.Do("getbit", key, offset) + + if err != nil { + return 0, errors.WithMessagef(err, "Getbit %s error", key) + } + if len(resp) == 2 && resp[0] == oK { + return Value(resp[1]).UInt(), nil + } + return 0, makeError(resp, key) +} + +//BitCount 计算字符串的子串所包含的位值为 1 的个数. 若 start 是负数, 则从字符串末尾算起. 若 end 是负数, 则表示从字符串末尾算起(包含). 类似 Redis 的 bitcount +// +// key 键值 +// start 子串的字节偏移 +// end 子串的字节结尾 +// 返回 val,返回位值为 1 的个数 +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) BitCount(key string, start int64, end int64) (int64, error) { + resp, err := c.Do("bitcount", key, start, end) + if err != nil { + return 0, errors.WithMessagef(err, "BitCount %s error", key) + } + if len(resp) == 2 && resp[0] == oK { + //fmt.Println(Value(resp[1]).String()) + return Value(resp[1]).Int64(), nil + } + return 0, makeError(resp, key) +} + +//CountBit 计算字符串的子串所包含的位值为 1 的个数. 若 start 是负数, 则从字符串末尾算起. 若 size 是负数, 则表示从字符串末尾算起, 忽略掉那么多字节. +// +// key 键值 +// start 子串的字节偏移 +// size 子串的字节结尾 +// 返回 val,返回位值为 1 的个数 +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) CountBit(key string, start int64, size int64) (int64, error) { + resp, err := c.Do("countbit", key, start, size) + if err != nil { + return 0, errors.WithMessagef(err, "CountBit %s error", key) + } + if len(resp) == 2 && resp[0] == oK { + //fmt.Println(Value(resp[1]).String()) + return Value(resp[1]).Int64(), nil + } + return 0, makeError(resp, key) +} + +//Substr 获取字符串的子串. +// +// key 键值 +// start int, 子串的字节偏移;若 start 是负数, 则从字符串末尾算起. +// size int,可选, 子串的长度(字节数), 默认为到字符串最后一个字节;若 size 是负数, 则表示从字符串末尾算起, 忽略掉那么多字节(类似 PHP 的 substr()) +// 返回 val,字符串的部分 +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) Substr(key string, start int64, size ...int64) (val string, err error) { + var resp []string + if len(size) > 0 { + resp, err = c.Do("substr", key, start, size[0]) + } else { + resp, err = c.Do("substr", key, start) + } + + if err != nil { + return "", errors.WithMessagef(err, "Substr %s error", key) + } + if len(resp) > 1 && resp[0] == oK { + return resp[1], nil + } + return "", makeError(resp, key) +} + +//StrLen 计算字符串的长度(字节数). +// +// key 键值 +// 返回 字符串的长度, key 不存在则返回 0. +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) StrLen(key string) (int64, error) { + + resp, err := c.Do("strlen", key) + + if err != nil { + return -1, errors.WithMessagef(err, "Strlen %s error", key) + } + if len(resp) > 1 && resp[0] == oK { + return Value(resp[1]).Int64(), nil + } + return -1, makeError(resp, key) +} + +//Keys 列出处于区间 (key_start, key_end] 的 key 列表.("", ""] 表示整个区间. +// +// keyStart int 返回的起始 key(不包含), 空字符串表示 -inf. +// keyEnd int 返回的结束 key(包含), 空字符串表示 +inf. +// limit int 最多返回这么多个元素. +// 返回 返回包含 key 的数组. +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) Keys(keyStart, keyEnd string, limit int64) ([]string, error) { + + resp, err := c.Do("keys", keyStart, keyEnd, limit) + + if err != nil { + return nil, errors.WithMessagef(err, "Keys %s %s error", keyStart, keyEnd) + } + if len(resp) > 0 && resp[0] == oK { + return resp[1:], nil + } + return nil, makeError(resp, keyStart, keyEnd, limit) +} + +//RKeys 列出处于区间 (key_start, key_end] 的 key 列表.("", ""] 表示整个区间.反向选择 +// +// keyStart int 返回的起始 key(不包含), 空字符串表示 -inf. +// keyEnd int 返回的结束 key(包含), 空字符串表示 +inf. +// limit int 最多返回这么多个元素. +// 返回 返回包含 key 的数组. +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) RKeys(keyStart, keyEnd string, limit int64) ([]string, error) { + + resp, err := c.Do("rkeys", keyStart, keyEnd, limit) + + if err != nil { + return nil, errors.WithMessagef(err, "Rkeys %s %s error", keyStart, keyEnd) + } + if len(resp) > 0 && resp[0] == oK { + return resp[1:], nil + } + return nil, makeError(resp, keyStart, keyEnd, limit) +} + +//Scan 列出处于区间 (key_start, key_end] 的 key-value 列表.("", ""] 表示整个区间. +// +// keyStart int 返回的起始 key(不包含), 空字符串表示 -inf. +// keyEnd int 返回的结束 key(包含), 空字符串表示 +inf. +// limit int 最多返回这么多个元素. +// 返回 返回包含 key 的数组. +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) Scan(keyStart, keyEnd string, limit int64) (map[string]Value, error) { + + resp, err := c.Do("scan", keyStart, keyEnd, limit) + + if err != nil { + return nil, errors.WithMessagef(err, "Scan %s %s error", keyStart, keyEnd) + } + if len(resp) > 0 && resp[0] == oK { + re := make(map[string]Value) + size := len(resp) + for i := 1; i < size-1; i += 2 { + re[resp[i]] = Value(resp[i+1]) + } + return re, nil + } + return nil, makeError(resp, keyStart, keyEnd, limit) +} + +//RScan 列出处于区间 (key_start, key_end] 的 key-value 列表, 反向顺序.("", ""] 表示整个区间. +// +// keyStart int 返回的起始 key(不包含), 空字符串表示 -inf. +// keyEnd int 返回的结束 key(包含), 空字符串表示 +inf. +// limit int 最多返回这么多个元素. +// 返回 返回包含 key 的数组. +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) RScan(keyStart, keyEnd string, limit int64) (map[string]Value, error) { + + resp, err := c.Do("rscan", keyStart, keyEnd, limit) + + if err != nil { + return nil, errors.WithMessagef(err, "Rscan %s %s error", keyStart, keyEnd) + } + if len(resp) > 0 && resp[0] == oK { + re := make(map[string]Value) + size := len(resp) + for i := 1; i < size-1; i += 2 { + re[resp[i]] = Value(resp[i+1]) + } + return re, nil + } + return nil, makeError(resp, keyStart, keyEnd, limit) +} diff --git a/ssdb/ssdb.go b/ssdb/ssdb.go index 4848f5d..26ad133 100644 --- a/ssdb/ssdb.go +++ b/ssdb/ssdb.go @@ -35,6 +35,7 @@ func (c *Client) Do(args ...interface{}) ([]string, error) { return resp, err } +/* func (c *Client) Set(key string, val string) (interface{}, error) { resp, err := c.Do("set", key, val) if err != nil { @@ -73,9 +74,9 @@ func (c *Client) Del(key string) (interface{}, error) { } return nil, fmt.Errorf("bad response:resp:%v:", resp) } - +*/ func (c *Client) Send(args ...interface{}) error { - return c.send(args); + return c.send(args) } func (c *Client) send(args []interface{}) error { @@ -123,7 +124,7 @@ func (c *Client) send(args []interface{}) error { } func (c *Client) Recv() ([]string, error) { - return c.recv(); + return c.recv() } func (c *Client) recv() ([]string, error) { diff --git a/ssdb/utils.go b/ssdb/utils.go new file mode 100644 index 0000000..d33b7ce --- /dev/null +++ b/ssdb/utils.go @@ -0,0 +1,30 @@ +package ssdb + +import ( + "fmt" + "github.com/pkg/errors" +) + +const ( + notFound = "not_found" + oK = "ok" + + // public + NotFound = notFound + Ok = oK +) + +//生成错误信息,已经确定是有错误 +func makeError(resp []string, errKey ...interface{}) error { + if len(resp) < 1 { + return errors.New("ssdb response error") + } + //正常返回的不存在不报错,如果要捕捉这个问题请使用exists + if resp[0] == notFound { + return nil + } + if len(errKey) > 0 { + return fmt.Errorf("access ssdb error, code is %v, parameter is %v", resp, errKey) + } + return fmt.Errorf("access ssdb error, code is %v", resp) +} diff --git a/ssdb/value.go b/ssdb/value.go new file mode 100644 index 0000000..8543095 --- /dev/null +++ b/ssdb/value.go @@ -0,0 +1,131 @@ +package ssdb + +/** +code copy from github.com/seefan/gossdb/client v1.1.3 +*/ +import ( + "encoding/json" + "strconv" + "time" +) + +//Value string +// +//扩展值,原始类型为 string +type Value string + +//String 返回 string 的值 +func (v Value) String() string { + return string(v) +} + +//Int64 返回 int64 的值 +func (v Value) Int64() int64 { + if f, e := strconv.ParseInt(string(v), 10, 64); e == nil { + return f + } + return 0 +} + +//Int32 返回 int32 的值 +func (v Value) Int32() int32 { + return int32(v.Int64()) +} + +//Int16 返回 int16 的值 +func (v Value) Int16() int16 { + return int16(v.Int64()) +} + +//Int8 返回 int8 的值 +func (v Value) Int8() int8 { + return int8(v.Int64()) +} + +//Int 返回 int 的值 +func (v Value) Int() int { + return int(v.Int64()) +} + +//UInt64 返回 uint64 的值 +func (v Value) UInt64() uint64 { + if f, e := strconv.ParseUint(string(v), 10, 64); e == nil { + return f + } + return 0 +} + +//UInt32 返回 uint32 类型的值 +func (v Value) UInt32() uint32 { + return uint32(v.UInt64()) +} + +//UInt16 返回 uint16 类型的值 +func (v Value) UInt16() uint16 { + return uint16(v.UInt64()) +} + +//UInt8 返回 uint8 类型的值 +func (v Value) UInt8() uint8 { + return uint8(v.UInt64()) +} + +//Byte 返回 byte 类型的值 +func (v Value) Byte() byte { + return v.UInt8() +} + +//UInt 返回 uint 类型的值 +func (v Value) UInt() uint { + return uint(v.UInt64()) +} + +//Float64 返回 float64 类型的值 +func (v Value) Float64() float64 { + if f, e := strconv.ParseFloat(string(v), 64); e == nil { + return f + } + return 0 +} + +//Float32 返回 float32 类型的值 +func (v Value) Float32() float32 { + return float32(v.Float64()) +} + +//Bool 返回 bool 类型的值 +func (v Value) Bool() bool { + return v == "1" +} + +//Time 返回 time.Time 类型的值 +func (v Value) Time() time.Time { + return time.Unix(v.Int64(), 0) +} + +//Duration 返回 time.Duration 类型的值 +func (v Value) Duration() time.Duration { + return time.Duration(v.Int64()) +} + +//Bytes 返回 []byte 类型的值 +func (v Value) Bytes() []byte { + return []byte(v) +} + +//IsEmpty 判断是否为空 +func (v Value) IsEmpty() bool { + return v == "" +} + +//As 按json 转换指定类型 +// +// value 传入的指针 +// +//示例 +// var abc time.Time +// v.As(&abc) +func (v Value) As(value interface{}) (err error) { + err = json.Unmarshal(v.Bytes(), value) + return +} diff --git a/ssdb/zset.go b/ssdb/zset.go new file mode 100644 index 0000000..e3b5946 --- /dev/null +++ b/ssdb/zset.go @@ -0,0 +1,668 @@ +package ssdb + +/** +code copy from github.com/seefan/gossdb/client v1.1.3 +*/ +import ( + "github.com/pkg/errors" +) + +//ZSet 设置 zset 中指定 key 对应的权重值. +// +// setName zset名称 +// key zset 中的 key. +// score 整数, key 对应的权重值 +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) ZSet(setName, key string, score int64) (err error) { + resp, err := c.Do("zset", setName, key, score) + if err != nil { + return errors.WithMessagef(err, "Zset %s/%s error", setName, key) + } + + if len(resp) > 0 && resp[0] == oK { + return nil + } + return makeError(resp, setName, key) +} + +//ZGet 获取 zset 中指定 key 对应的权重值. +// +// setName zset名称 +// key zset 中的 key. +// 返回 score 整数, key 对应的权重值 +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) ZGet(setName, key string) (score int64, err error) { + resp, err := c.Do("zget", setName, key) + if err != nil { + return 0, errors.WithMessagef(err, "Zget %s/%s error", setName, key) + } + if len(resp) == 2 && resp[0] == oK { + return Value(resp[1]).Int64(), nil + } + return 0, makeError(resp, setName, key) +} + +//ZDel 删除 zset 中指定 key +// +// setName zset名称 +// key zset 中的 key. +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) ZDel(setName, key string) (err error) { + resp, err := c.Do("zdel", setName, key) + if err != nil { + return errors.WithMessagef(err, "Zdel %s/%s error", setName, key) + } + if len(resp) > 0 && resp[0] == oK { + return nil + } + return makeError(resp, setName, key) +} + +//ZExists 判断指定的 key 是否存在于 zset 中. +// +// setName zset名称 +// key zset 中的 key. +// 返回 re 如果存在, 返回 true, 否则返回 false. +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) ZExists(setName, key string) (re bool, err error) { + resp, err := c.Do("zexists", setName, key) + if err != nil { + return false, errors.WithMessagef(err, "Zexists %s/%s error", setName, key) + } + + if len(resp) == 2 && resp[0] == oK { + return resp[1] == "1", nil + } + return false, makeError(resp, setName, key) +} + +//ZCount 返回处于区间 [start,end] key 数量. +// +// setName zset名称 +// start key 的最小权重值(包含), 空字符串表示 -inf. +// end key 的最大权重值(包含), 空字符串表示 +inf. +// 返回 count 返回符合条件的 key 的数量. +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) ZCount(setName string, start, end interface{}) (count int64, err error) { + resp, err := c.Do("zcount", setName, start, end) + if err != nil { + return -1, errors.WithMessagef(err, "Zcount %s %v %v error", setName, start, end) + } + + if len(resp) == 2 && resp[0] == oK { + return Value(resp[1]).Int64(), nil + } + return -1, makeError(resp, setName) +} + +//ZClear 删除 zset 中的所有 key. +// +// setName zset名称 +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) ZClear(setName string) (err error) { + resp, err := c.Do("zclear", setName) + if err != nil { + return errors.WithMessagef(err, "Zclear %s error", setName) + } + + if len(resp) > 0 && resp[0] == oK { + return nil + } + return makeError(resp, setName) +} + +//ZScan 列出 zset 中处于区间 (key_start+score_start, score_end] 的 key-score 列表. +// +// 如果 key_start 为空, 那么对应权重值大于或者等于 score_start 的 key 将被返回. 如果 key_start 不为空, 那么对应权重值大于 score_start 的 key, 或者大于 key_start 且对应权重值等于 score_start 的 key 将被返回. +// 也就是说, 返回的 key 在 (key.score == score_start && key > key_start || key.score > score_start), 并且 key.score <= score_end 区间. 先判断 score_start, score_end, 然后判断 key_start. +// +// setName zset名称 +// keyStart score_start 对应的 key. +// scoreStart 返回 key 的最小权重值(可能不包含, 依赖 key_start), 空字符串表示 -inf. +// scoreEnd 返回 key 的最大权重值(包含), 空字符串表示 +inf. +// limit 最多返回这么多个元素. +// 返回 keys 返回符合条件的 key 的数组. +// 返回 scores 返回符合条件的 key 对应的权重. +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) ZScan(setName string, keyStart string, scoreStart, scoreEnd interface{}, limit int64) (keys []string, scores []int64, err error) { + resp, err := c.Do("zscan", setName, keyStart, scoreStart, scoreEnd, limit) + + if err != nil { + return nil, nil, errors.WithMessagef(err, "Zscan %s %v %v %v %v error", setName, keyStart, scoreStart, scoreEnd, limit) + } + if len(resp) > 0 && resp[0] == oK { + size := len(resp) + keys := make([]string, 0, (size-1)/2) + scores := make([]int64, 0, (size-1)/2) + + for i := 1; i < size-1; i += 2 { + keys = append(keys, resp[i]) + scores = append(scores, Value(resp[i+1]).Int64()) + } + return keys, scores, nil + } + return nil, nil, makeError(resp, setName, keyStart, scoreStart, scoreEnd, limit) +} + +//ZRScan 列出 zset 中的 key-score 列表, 反向顺序 +// +// setName zset名称 +// keyStart score_start 对应的 key. +// scoreStart 返回 key 的最小权重值(可能不包含, 依赖 key_start), 空字符串表示 -inf. +// scoreEnd 返回 key 的最大权重值(包含), 空字符串表示 +inf. +// limit 最多返回这么多个元素. +// 返回 keys 返回符合条件的 key 的数组. +// 返回 scores 返回符合条件的 key 对应的权重. +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) ZRScan(setName string, keyStart string, scoreStart, scoreEnd interface{}, limit int64) (keys []string, scores []int64, err error) { + resp, err := c.Do("zrscan", setName, keyStart, scoreStart, scoreEnd, limit) + + if err != nil { + return nil, nil, errors.WithMessagef(err, "Zrscan %s %v %v %v %v error", setName, keyStart, scoreStart, scoreEnd, limit) + } + + if len(resp) > 0 && resp[0] == oK { + size := len(resp) + keys := make([]string, 0, (size-1)/2) + scores := make([]int64, 0, (size-1)/2) + + for i := 1; i < size-1; i += 2 { + keys = append(keys, resp[i]) + scores = append(scores, Value(resp[i+1]).Int64()) + } + return keys, scores, nil + } + return nil, nil, makeError(resp, setName, keyStart, scoreStart, scoreEnd, limit) +} + +//MultiZSet 批量设置 zset 中的 key-score. +// +// setName zset名称 +// kvs 包含 key-score 的map +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) MultiZSet(setName string, kvs map[string]int64) (err error) { + + args := []interface{}{"multi_zset", setName} + for k, v := range kvs { + args = append(args, k) + args = append(args, v) + } + resp, err := c.Do(args...) + + if err != nil { + return errors.WithMessagef(err, "MultiZset %s %v error", setName, kvs) + } + + if len(resp) > 0 && resp[0] == oK { + return nil + } + return makeError(resp, setName, kvs) +} + +//MultiZGet 批量获取 zset 中的 key-score. +// +// setName zset名称 +// key 要获取key的列表,支持多个key +// 返回 val 包含 key-score 的map +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) MultiZGet(setName string, key ...string) (val map[string]int64, err error) { + if len(key) == 0 { + return make(map[string]int64), nil + } + args := []interface{}{"multi_zget", setName} + + for _, v := range key { + args = append(args, v) + } + + resp, err := c.Do(args...) + + if err != nil { + return nil, errors.WithMessagef(err, "MultiZget %s %s error", setName, key) + } + size := len(resp) + if size > 0 && resp[0] == oK { + val = make(map[string]int64) + for i := 1; i < size && i+1 < size; i += 2 { + val[resp[i]] = Value(resp[i+1]).Int64() + } + return val, nil + } + return nil, makeError(resp, key) +} + +//MultiZGetSlice 批量获取 zset 中的 key-score. +// +// setName zset名称 +// key 要获取key的列表,支持多个key +// 返回 keys 包含 key的slice +// 返回 scores 包含 key对应权重的slice +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) MultiZGetSlice(setName string, key ...string) (keys []string, scores []int64, err error) { + if len(key) == 0 { + return []string{}, []int64{}, nil + } + args := []interface{}{"multi_zget", setName} + for _, v := range key { + args = append(args, v) + } + resp, err := c.Do(args...) + + if err != nil { + return nil, nil, errors.WithMessagef(err, "MultiZget %s %s error", setName, key) + } + + size := len(resp) + if size > 0 && resp[0] == oK { + + keys := make([]string, 0) + scores := make([]int64, 0) + + for i := 1; i < size && i+1 < size; i += 2 { + keys = append(keys, resp[i]) + scores = append(scores, Value(resp[i+1]).Int64()) + } + return keys, scores, nil + } + return nil, nil, makeError(resp, setName, key) +} + +//MultiZGetArray 批量获取 zset 中的 key-score. +// +// setName zset名称 +// key 要获取key的slice +// 返回 val 包含 key-score 的map +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) MultiZGetArray(setName string, key []string) (val map[string]int64, err error) { + return c.MultiZGet(setName, key...) +} + +//MultiZgetSliceArray 批量获取 zset 中的 key-score. +// +// setName zset名称 +// key 要获取key的slice +// 返回 keys 包含 key的slice +// 返回 scores 包含 key对应权重的slice +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) MultiZgetSliceArray(setName string, key []string) (keys []string, scores []int64, err error) { + return c.MultiZGetSlice(setName, key...) +} + +//MultiZDel 批量删除 zset 中的 key-score. +// +// setName zset名称 +// key 要删除key的列表,支持多个key +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) MultiZDel(setName string, key ...string) (err error) { + if len(key) == 0 { + return nil + } + args := []interface{}{"multi_zdel", setName} + for _, v := range key { + args = append(args, v) + } + resp, err := c.Do(args...) + if err != nil { + return errors.WithMessagef(err, "MultiZdel %s %s error", setName, key) + } + + if len(resp) > 0 && resp[0] == oK { + return nil + } + return makeError(resp, setName, key) +} + +//ZIncr 使 zset 中的 key 对应的值增加 num. 参数 num 可以为负数. +// +// setName zset名称 +// key 要增加权重的key +// num 要增加权重值 +// 返回 int64 增加后的新权重值 +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) ZIncr(setName string, key string, num int64) (int64, error) { + if len(key) == 0 { + return 0, nil + } + resp, err := c.Do("zincr", setName, key, num) + if err != nil { + return 0, errors.WithMessagef(err, "Zincr %s %s %v", setName, key, num) + } + + if len(resp) > 1 && resp[0] == oK { + return Value(resp[1]).Int64(), nil + } + return 0, makeError(resp, setName, key) +} + +//ZList 列出名字处于区间 (name_start, name_end] 的 zset. +// +// name_start - 返回的起始名字(不包含), 空字符串表示 -inf. +// name_end - 返回的结束名字(包含), 空字符串表示 +inf. +// limit 最多返回这么多个元素. +// 返回 []string 返回包含名字的slice. +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) ZList(nameStart, nameEnd string, limit int64) ([]string, error) { + resp, err := c.Do("zlist", nameStart, nameEnd, limit) + if err != nil { + return nil, errors.WithMessagef(err, "Zlist %s %s %v error", nameStart, nameEnd, limit) + } + + if len(resp) > 0 && resp[0] == oK { + size := len(resp) + keyList := make([]string, 0, size-1) + + for i := 1; i < size; i++ { + keyList = append(keyList, resp[i]) + } + return keyList, nil + } + return nil, makeError(resp, nameStart, nameEnd, limit) +} + +//ZSize 返回 zset 中的元素个数. +// +// name zset的名称. +// 返回 val 返回包含名字元素的个数. +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) ZSize(name string) (val int64, err error) { + resp, err := c.Do("zsize", name) + if err != nil { + return 0, errors.WithMessagef(err, "Zsize %s error", name) + } + + if len(resp) > 0 && resp[0] == oK { + val = Value(resp[1]).Int64() + return val, nil + } + return 0, makeError(resp, name) +} + +//ZKeys 列出 zset 中的 key 列表. 参见 zscan(). +// +// setName zset名称 +// keyStart score_start 对应的 key. +// scoreStart 返回 key 的最小权重值(可能不包含, 依赖 key_start), 空字符串表示 -inf. +// scoreEnd 返回 key 的最大权重值(包含), 空字符串表示 +inf. +// limit 最多返回这么多个元素. +// 返回 keys 返回符合条件的 key 的数组. +// 返回 scores 返回符合条件的 key 对应的权重. +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) ZKeys(setName string, keyStart string, scoreStart, scoreEnd interface{}, limit int64) (keys []string, err error) { + resp, err := c.Do("zkeys", setName, keyStart, scoreStart, scoreEnd, limit) + + if err != nil { + return nil, errors.WithMessagef(err, "Zkeys %s %v %v %v %v error", setName, keyStart, scoreStart, scoreEnd, limit) + } + if len(resp) > 0 && resp[0] == oK { + size := len(resp) + keys := []string{} + + for i := 1; i < size; i++ { + keys = append(keys, resp[i]) + } + return keys, nil + } + return nil, makeError(resp, setName, keyStart, scoreStart, scoreEnd, limit) +} + +//ZSum 返回 key 处于区间 [start,end] 的 score 的和. +// +// setName zset名称 +// scoreStart key 的最小权重值(可能不包含, 依赖 key_start), 空字符串表示 -inf. +// scoreEnd key 的最大权重值(包含), 空字符串表示 +inf. +// 返回 val 符合条件的 score 的求和 +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) ZSum(setName string, scoreStart, scoreEnd interface{}) (val int64, err error) { + resp, err := c.Do("zsum", setName, scoreStart, scoreEnd) + + if err != nil { + return 0, errors.WithMessagef(err, "Zsum %s %v %v error", setName, scoreStart, scoreEnd) + } + if len(resp) > 0 && resp[0] == oK { + val = Value(resp[1]).Int64() + return val, nil + } + return 0, makeError(resp, setName, scoreStart, scoreEnd) +} + +//ZAvg 返回 key 处于区间 [start,end] 的 score 的平均值. +// +// setName zset名称 +// scoreStart key 的最小权重值(可能不包含, 依赖 key_start), 空字符串表示 -inf. +// scoreEnd key 的最大权重值(包含), 空字符串表示 +inf. +// 返回 val 符合条件的 score 的平均值 +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) ZAvg(setName string, scoreStart, scoreEnd interface{}) (val int64, err error) { + resp, err := c.Do("zavg", setName, scoreStart, scoreEnd) + + if err != nil { + return 0, errors.WithMessagef(err, "Zavg %s %v %v error", setName, scoreStart, scoreEnd) + } + if len(resp) > 0 && resp[0] == oK { + val = Value(resp[1]).Int64() + return val, nil + } + return 0, makeError(resp, setName, scoreStart, scoreEnd) +} + +//ZRank 返回指定 key 在 zset 中的排序位置(排名), 排名从 0 开始. 注意! 本方法可能会非常慢! 请在离线环境中使用. +// +// setName zset名称 +// key 指定key名 +// 返回 val 排名 +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) ZRank(setName, key string) (val int64, err error) { + resp, err := c.Do("zrank", setName, key) + + if err != nil { + return 0, errors.WithMessagef(err, "Zrank %s %s error", setName, key) + } + if len(resp) > 0 && resp[0] == oK { + val = Value(resp[1]).Int64() + return val, nil + } + return 0, makeError(resp, setName, key) +} + +//ZRRank 返回指定 key 在 zset 中的倒序排名.注意! 本方法可能会非常慢! 请在离线环境中使用. +// +// setName zset名称 +// key 指定key名 +// 返回 val 排名 +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) ZRRank(setName, key string) (val int64, err error) { + resp, err := c.Do("zrrank", setName, key) + + if err != nil { + return 0, errors.WithMessagef(err, "Zrrank %s %s error", setName, key) + } + if len(resp) > 0 && resp[0] == oK { + val = Value(resp[1]).Int64() + return val, nil + } + return 0, makeError(resp, setName, key) +} + +//ZRange 根据下标索引区间 [offset, offset + limit) 获取 key-score 对, 下标从 0 开始.注意! 本方法在 offset 越来越大时, 会越慢! +// +// setName zset名称 +// offset 从此下标处开始返回. 从 0 开始. +// limit 最多返回这么多个 key-score 对. +// 返回 val 排名 +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) ZRange(setName string, offset, limit int64) (val map[string]int64, err error) { + resp, err := c.Do("zrange", setName, offset, limit) + + if err != nil { + return nil, errors.WithMessagef(err, "Zrange %s %d %d error", setName, offset, limit) + } + if len(resp) > 0 && resp[0] == oK { + val = make(map[string]int64) + size := len(resp) + for i := 1; i < size-1; i += 2 { + val[resp[i]] = Value(resp[i+1]).Int64() + } + return val, nil + } + return nil, makeError(resp, setName, offset, limit) +} + +//ZRangeSlice 根据下标索引区间 [offset, offset + limit) 获取 获取 key和score 数组对, 下标从 0 开始.注意! 本方法在 offset 越来越大时, 会越慢! +// +// setName zset名称 +// offset 从此下标处开始返回. 从 0 开始. +// limit 最多返回这么多个 key-score 对. +// 返回 val 排名 +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) ZRangeSlice(setName string, offset, limit int64) (key []string, val []int64, err error) { + resp, err := c.Do("zrange", setName, offset, limit) + + if err != nil { + return nil, nil, errors.WithMessagef(err, "Zrange_slice %s %d %d error", setName, offset, limit) + } + if len(resp) > 0 && resp[0] == oK { + val = []int64{} + key = []string{} + size := len(resp) + for i := 1; i < size-1; i += 2 { + key = append(key, resp[i]) + val = append(val, Value(resp[i+1]).Int64()) + } + return key, val, nil + } + return nil, nil, makeError(resp, setName, offset, limit) +} + +//ZRRange 根据下标索引区间 [offset, offset + limit) 获取 key-score 对, 反向顺序获取.注意! 本方法在 offset 越来越大时, 会越慢! +// +// setName zset名称 +// offset 从此下标处开始返回. 从 0 开始. +// limit 最多返回这么多个 key-score 对. +// 返回 val 排名 +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) ZRRange(setName string, offset, limit int64) (val map[string]int64, err error) { + resp, err := c.Do("zrrange", setName, offset, limit) + + if err != nil { + return nil, errors.WithMessagef(err, "Zrrange %s %d %d error", setName, offset, limit) + } + if len(resp) > 0 && resp[0] == oK { + val = make(map[string]int64) + size := len(resp) + + for i := 1; i < size-1; i += 2 { + val[resp[i]] = Value(resp[i+1]).Int64() + } + return val, nil + } + return nil, makeError(resp, setName, offset, limit) +} + +//ZRRangeSlice 根据下标索引区间 [offset, offset + limit) 获取 key和score 数组对, 反向顺序获取.注意! 本方法在 offset 越来越大时, 会越慢! +// +// setName zset名称 +// offset 从此下标处开始返回. 从 0 开始. +// limit 最多返回这么多个 key-score 对. +// 返回 val 排名 +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) ZRRangeSlice(setName string, offset, limit int64) (key []string, val []int64, err error) { + resp, err := c.Do("zrrange", setName, offset, limit) + + if err != nil { + return nil, nil, errors.WithMessagef(err, "Zrrange_slice %s %d %d error", setName, offset, limit) + } + if len(resp) > 0 && resp[0] == oK { + val = []int64{} + key = []string{} + size := len(resp) + + for i := 1; i < size-1; i += 2 { + key = append(key, resp[i]) + val = append(val, Value(resp[i+1]).Int64()) + } + return key, val, nil + } + return nil, nil, makeError(resp, setName, offset, limit) +} + +//ZRemRangeByRank 删除位置处于区间 [start,end] 的元素. +// +// setName zset名称 +// start 区间开始,包含start值 +// end 区间结束,包含end值 +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) ZRemRangeByRank(setName string, start, end int64) (err error) { + resp, err := c.Do("zremrangebyrank", setName, start, end) + + if err != nil { + return errors.WithMessagef(err, "Zremrangebyrank %s %d %d error", setName, start, end) + } + if len(resp) > 0 && resp[0] == oK { + return nil + } + return makeError(resp, setName, start, end) +} + +//ZRemRangeByScore 删除权重处于区间 [start,end] 的元素. +// +// setName zset名称 +// start 区间开始,包含start值 +// end 区间结束,包含end值 +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) ZRemRangeByScore(setName string, start, end int64) (err error) { + resp, err := c.Do("zremrangebyscore", setName, start, end) + + if err != nil { + return errors.WithMessagef(err, "Zremrangebyscore %s %d %d error", setName, start, end) + } + if len(resp) > 0 && resp[0] == oK { + return nil + } + return makeError(resp, setName, start, end) +} + +//ZPopFront 从 zset 首部删除并返回 `limit` 个元素. +// +// setName zset名称 +// limit 最多要删除并返回这么多个 key-score 对. +// 返回 包含 key-score 的map +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) ZPopFront(setName string, limit int64) (val map[string]int64, err error) { + resp, err := c.Do("zpop_front", setName, limit) + + if err != nil { + return nil, errors.WithMessagef(err, "Zpopfront %s %d error", setName, limit) + } + size := len(resp) + if size > 0 && resp[0] == oK { + val = make(map[string]int64) + for i := 1; i < size && i+1 < size; i += 2 { + val[resp[i]] = Value(resp[i+1]).Int64() + } + return val, nil + } + return nil, makeError(resp, setName, limit) +} + +//ZPopBack 从 zset 尾部删除并返回 `limit` 个元素. +// +// setName zset名称 +// limit 最多要删除并返回这么多个 key-score 对. +// 返回 包含 key-score 的map +// 返回 err,可能的错误,操作成功返回 nil +func (c *Client) ZPopBack(setName string, limit int64) (val map[string]int64, err error) { + resp, err := c.Do("zpop_back", setName, limit) + + if err != nil { + return nil, errors.WithMessagef(err, "Zpopback %s %d error", setName, limit) + } + size := len(resp) + if size > 0 && resp[0] == oK { + val = make(map[string]int64) + for i := 1; i < size && i+1 < size; i += 2 { + val[resp[i]] = Value(resp[i+1]).Int64() + } + return val, nil + } + return nil, makeError(resp, setName, limit) +} diff --git a/test.go b/test.go deleted file mode 100644 index 4bc95b9..0000000 --- a/test.go +++ /dev/null @@ -1,61 +0,0 @@ -package main - -import ( - "fmt" - "os" - "strconv" - "./ssdb" -) - -func main() { - ip := "127.0.0.1" - port := 8888 - db, err := ssdb.Connect(ip, port) - if err != nil { - os.Exit(1) - } - - defer db.Close() - var val interface{} - - keys := []string{} - keys = append(keys, "c"); - keys = append(keys, "d"); - val, err = db.Do("multi_get", "a", "b", keys); - fmt.Printf("%s\n", val); - - db.Set("a", "xxx") - val, err = db.Get("a") - fmt.Printf("%s\n", val) - db.Del("a") - val, err = db.Get("a") - fmt.Printf("%s\n", val) - - fmt.Printf("----\n"); - - db.Do("zset", "z", "a", 3) - db.Do("multi_zset", "z", "b", -2, "c", 5, "d", 3) - resp, err := db.Do("zrscan", "z", "", "", "", 10) - if err != nil { - os.Exit(1) - } - if len(resp)%2 != 1 { - fmt.Printf("bad response") - os.Exit(1) - } - - fmt.Printf("Status: %s\n", resp[0]) - for i := 1; i < len(resp); i += 2 { - fmt.Printf(" %s : %3s\n", resp[i], resp[i+1]) - } - - //_ = db.Send("dump", "", "", "-1"); - _ = db.Send("sync140"); - // receive multi responses on one request - for{ - resp, _ := db.Recv() - fmt.Printf("%s\n", strconv.Quote(fmt.Sprintf("%s", resp))); - } - - return -}