Add sorted sets support.

This commit is contained in:
Vladimir Mihailenco 2012-07-27 17:21:50 +03:00
parent 10f9adac76
commit 4814ee7600
3 changed files with 570 additions and 45 deletions

View File

@ -6,6 +6,16 @@ import (
//------------------------------------------------------------------------------
type Limit struct {
Offset, Count int64
}
func NewLimit(offset, count int64) *Limit {
return &Limit{offset, count}
}
//------------------------------------------------------------------------------
func (c *Client) Auth(password string) *StatusReq {
req := NewStatusReq("AUTH", password)
c.Run(req)
@ -641,6 +651,207 @@ func (c *Client) SUnionStore(destination string, keys ...string) *IntReq {
//------------------------------------------------------------------------------
type ZMember struct {
Score float64
Member string
}
func NewZMember(score float64, member string) *ZMember {
return &ZMember{score, member}
}
func (m *ZMember) ScoreString() string {
return strconv.FormatFloat(m.Score, 'f', -1, 32)
}
func (c *Client) ZAdd(key string, members ...*ZMember) *IntReq {
args := []string{"ZADD", key}
for _, m := range members {
args = append(args, m.ScoreString(), m.Member)
}
req := NewIntReq(args...)
c.Run(req)
return req
}
func (c *Client) ZCard(key string) *IntReq {
req := NewIntReq("ZCARD", key)
c.Run(req)
return req
}
func (c *Client) ZCount(key, min, max string) *IntReq {
req := NewIntReq("ZCOUNT", key, min, max)
c.Run(req)
return req
}
func (c *Client) ZIncrBy(key string, increment int64, member string) *IntReq {
req := NewIntReq("ZINCRBY", key, strconv.FormatInt(increment, 10), member)
c.Run(req)
return req
}
func (c *Client) ZInterStore(
destination string,
numkeys int64,
keys []string,
weights []int64,
aggregate string,
) *IntReq {
args := []string{"ZINTERSTORE", destination, strconv.FormatInt(numkeys, 10)}
args = append(args, keys...)
if weights != nil {
args = append(args, "WEIGHTS")
for _, w := range weights {
args = append(args, strconv.FormatInt(w, 10))
}
}
if aggregate != "" {
args = append(args, "AGGREGATE", aggregate)
}
req := NewIntReq(args...)
c.Run(req)
return req
}
func (c *Client) ZRange(key string, start, stop int64, withScores bool) *MultiBulkReq {
args := []string{
"ZRANGE",
key,
strconv.FormatInt(start, 10),
strconv.FormatInt(stop, 10),
}
if withScores {
args = append(args, "WITHSCORES")
}
req := NewMultiBulkReq(args...)
c.Run(req)
return req
}
func (c *Client) ZRangeByScore(
key string,
min, max string,
withScores bool,
limit *Limit,
) *MultiBulkReq {
args := []string{"ZRANGEBYSCORE", key, min, max}
if withScores {
args = append(args, "WITHSCORES")
}
if limit != nil {
args = append(
args,
"LIMIT",
strconv.FormatInt(limit.Offset, 10),
strconv.FormatInt(limit.Count, 10),
)
}
req := NewMultiBulkReq(args...)
c.Run(req)
return req
}
func (c *Client) ZRank(key, member string) *IntNilReq {
req := NewIntNilReq("ZRANK", key, member)
c.Run(req)
return req
}
func (c *Client) ZRem(key string, members ...string) *IntReq {
args := append([]string{"ZREM", key}, members...)
req := NewIntReq(args...)
c.Run(req)
return req
}
func (c *Client) ZRemRangeByRank(key string, start, stop int64) *IntReq {
req := NewIntReq(
"ZREMRANGEBYRANK",
key,
strconv.FormatInt(start, 10),
strconv.FormatInt(stop, 10),
)
c.Run(req)
return req
}
func (c *Client) ZRemRangeByScore(key, min, max string) *IntReq {
req := NewIntReq("ZREMRANGEBYSCORE", key, min, max)
c.Run(req)
return req
}
func (c *Client) ZRevRange(key, start, stop string, withScores bool) *MultiBulkReq {
args := []string{"ZREVRANGE", key, start, stop}
if withScores {
args = append(args, "WITHSCORES")
}
req := NewMultiBulkReq(args...)
c.Run(req)
return req
}
func (c *Client) ZRevRangeByScore(
key, start, stop string,
withScores bool,
limit *Limit,
) *MultiBulkReq {
args := []string{"ZREVRANGEBYSCORE", key, start, stop}
if withScores {
args = append(args, "WITHSCORES")
}
if limit != nil {
args = append(
args,
"LIMIT",
strconv.FormatInt(limit.Offset, 10),
strconv.FormatInt(limit.Count, 10),
)
}
req := NewMultiBulkReq(args...)
c.Run(req)
return req
}
func (c *Client) ZRevRank(key, member string) *IntNilReq {
req := NewIntNilReq("ZREVRANK", key, member)
c.Run(req)
return req
}
func (c *Client) ZScore(key, member string) *FloatReq {
req := NewFloatReq("ZSCORE", key, member)
c.Run(req)
return req
}
func (c *Client) ZUnionStore(
destination string,
numkeys int64,
keys []string,
weights []int64,
aggregate string,
) *IntReq {
args := []string{"ZUNIONSTORE", destination, strconv.FormatInt(numkeys, 10)}
args = append(args, keys...)
if weights != nil {
args = append(args, "WEIGHTS")
for _, w := range weights {
args = append(args, strconv.FormatInt(w, 10))
}
}
if aggregate != "" {
args = append(args, "AGGREGATE", aggregate)
}
req := NewIntReq(args...)
c.Run(req)
return req
}
//------------------------------------------------------------------------------
func (c *Client) PubSubClient() *PubSubClient {
return NewPubSubClient(c.connect, c.disconnect)
}

View File

@ -108,9 +108,7 @@ func (t *RedisTest) TestKeys(c *C) {
keys, err := t.redisC.Keys("*").Reply()
c.Check(err, IsNil)
c.Check(keys, HasLen, 2)
c.Check(keys[0], Equals, "foo1")
c.Check(keys[1], Equals, "foo2")
c.Check(keys, DeepEquals, []interface{}{"foo1", "foo2"})
}
func (t *RedisTest) TestMigrate(c *C) {
@ -450,7 +448,6 @@ func (t *RedisTest) TestHGetAll(c *C) {
values, err := t.redisC.HGetAll("myhash").Reply()
c.Check(err, IsNil)
c.Check(values, HasLen, 4)
c.Check(values, DeepEquals, []interface{}{"foo1", "bar1", "foo2", "bar2"})
}
@ -478,10 +475,9 @@ func (t *RedisTest) TestHKeys(c *C) {
t.redisC.HSet("myhash", "foo1", "bar1").Reply()
t.redisC.HSet("myhash", "foo2", "bar2").Reply()
values, err := t.redisC.HKeys("myhash").Reply()
keys, err := t.redisC.HKeys("myhash").Reply()
c.Check(err, IsNil)
c.Check(values, HasLen, 2)
c.Check(values, DeepEquals, []interface{}{"foo1", "foo2"})
c.Check(keys, DeepEquals, []interface{}{"foo1", "foo2"})
}
func (t *RedisTest) TestHLen(c *C) {
@ -499,7 +495,6 @@ func (t *RedisTest) TestHMGet(c *C) {
values, err := t.redisC.HMGet("myhash", "foo1", "foo2", "_").Reply()
c.Check(err, IsNil)
c.Check(values, HasLen, 3)
c.Check(values, DeepEquals, []interface{}{"bar1", "bar2", nil})
}
@ -545,10 +540,9 @@ func (t *RedisTest) TestHVals(c *C) {
t.redisC.HSet("myhash", "foo1", "bar1").Reply()
t.redisC.HSet("myhash", "foo2", "bar2").Reply()
values, err := t.redisC.HVals("myhash").Reply()
vals, err := t.redisC.HVals("myhash").Reply()
c.Check(err, IsNil)
c.Check(values, HasLen, 2)
c.Check(values, DeepEquals, []interface{}{"bar1", "bar2"})
c.Check(vals, DeepEquals, []interface{}{"bar1", "bar2"})
}
//------------------------------------------------------------------------------
@ -558,7 +552,6 @@ func (t *RedisTest) TestBLPop(c *C) {
values, err := t.redisC.BLPop(0, "list1", "list2").Reply()
c.Check(err, IsNil)
c.Check(values, HasLen, 2)
c.Check(values, DeepEquals, []interface{}{"list1", "a"})
}
@ -567,7 +560,6 @@ func (t *RedisTest) TestBrPop(c *C) {
values, err := t.redisC.BRPop(0, "list1", "list2").Reply()
c.Check(err, IsNil)
c.Check(values, HasLen, 2)
c.Check(values, DeepEquals, []interface{}{"list1", "c"})
}
@ -606,7 +598,6 @@ func (t *RedisTest) TestLInsert(c *C) {
values, err := t.redisC.LRange("list", 0, -1).Reply()
c.Check(err, IsNil)
c.Check(values, HasLen, 3)
c.Check(values, DeepEquals, []interface{}{"Hello", "There", "World"})
}
@ -630,7 +621,6 @@ func (t *RedisTest) TestLPop(c *C) {
values, err := t.redisC.LRange("list", 0, -1).Reply()
c.Check(err, IsNil)
c.Check(values, HasLen, 2)
c.Check(values, DeepEquals, []interface{}{"two", "three"})
}
@ -640,7 +630,6 @@ func (t *RedisTest) TestLPush(c *C) {
values, err := t.redisC.LRange("list", 0, -1).Reply()
c.Check(err, IsNil)
c.Check(values, HasLen, 2)
c.Check(values, DeepEquals, []interface{}{"Hello", "World"})
}
@ -661,7 +650,7 @@ func (t *RedisTest) TestLPushX(c *C) {
values, err = t.redisC.LRange("list2", 0, -1).Reply()
c.Check(err, IsNil)
c.Check(values, HasLen, 0)
c.Check(values, DeepEquals, []interface{}{})
}
func (t *RedisTest) TestLRange(c *C) {
@ -671,22 +660,19 @@ func (t *RedisTest) TestLRange(c *C) {
values, err := t.redisC.LRange("list", 0, 0).Reply()
c.Check(err, IsNil)
c.Check(values, HasLen, 1)
c.Check(values, DeepEquals, []interface{}{"one"})
values, err = t.redisC.LRange("list", -3, 2).Reply()
c.Check(err, IsNil)
c.Check(values, HasLen, 3)
c.Check(values, DeepEquals, []interface{}{"one", "two", "three"})
values, err = t.redisC.LRange("list", -100, 100).Reply()
c.Check(err, IsNil)
c.Check(values, HasLen, 3)
c.Check(values, DeepEquals, []interface{}{"one", "two", "three"})
values, err = t.redisC.LRange("list", 5, 10).Reply()
c.Check(err, IsNil)
c.Check(values, HasLen, 0)
c.Check(values, DeepEquals, []interface{}{})
}
func (t *RedisTest) TestLRem(c *C) {
@ -701,7 +687,6 @@ func (t *RedisTest) TestLRem(c *C) {
values, err := t.redisC.LRange("list", 0, -1).Reply()
c.Check(err, IsNil)
c.Check(values, HasLen, 2)
c.Check(values, DeepEquals, []interface{}{"hello", "foo"})
}
@ -720,7 +705,6 @@ func (t *RedisTest) TestLSet(c *C) {
values, err := t.redisC.LRange("list", 0, -1).Reply()
c.Check(err, IsNil)
c.Check(values, HasLen, 3)
c.Check(values, DeepEquals, []interface{}{"four", "five", "three"})
}
@ -735,7 +719,6 @@ func (t *RedisTest) TestLTrim(c *C) {
values, err := t.redisC.LRange("list", 0, -1).Reply()
c.Check(err, IsNil)
c.Check(values, HasLen, 2)
c.Check(values, DeepEquals, []interface{}{"two", "three"})
}
@ -750,7 +733,6 @@ func (t *RedisTest) TestRPop(c *C) {
values, err := t.redisC.LRange("list", 0, -1).Reply()
c.Check(err, IsNil)
c.Check(values, HasLen, 2)
c.Check(values, DeepEquals, []interface{}{"one", "two"})
}
@ -765,12 +747,10 @@ func (t *RedisTest) TestRPopLPush(c *C) {
values, err := t.redisC.LRange("list", 0, -1).Reply()
c.Check(err, IsNil)
c.Check(values, HasLen, 2)
c.Check(values, DeepEquals, []interface{}{"one", "two"})
values, err = t.redisC.LRange("list2", 0, -1).Reply()
c.Check(err, IsNil)
c.Check(values, HasLen, 1)
c.Check(values, DeepEquals, []interface{}{"three"})
}
@ -785,7 +765,6 @@ func (t *RedisTest) TestRPush(c *C) {
values, err := t.redisC.LRange("list", 0, -1).Reply()
c.Check(err, IsNil)
c.Check(values, HasLen, 2)
c.Check(values, DeepEquals, []interface{}{"Hello", "World"})
}
@ -804,12 +783,11 @@ func (t *RedisTest) TestRPushX(c *C) {
values, err := t.redisC.LRange("list", 0, -1).Reply()
c.Check(err, IsNil)
c.Check(values, HasLen, 2)
c.Check(values, DeepEquals, []interface{}{"Hello", "World"})
values, err = t.redisC.LRange("list2", 0, -1).Reply()
c.Check(err, IsNil)
c.Check(values, HasLen, 0)
c.Check(values, DeepEquals, []interface{}{})
}
//------------------------------------------------------------------------------
@ -829,9 +807,7 @@ func (t *RedisTest) TestSAdd(c *C) {
members, err := t.redisC.SMembers("set").Reply()
c.Check(err, IsNil)
c.Check(members, HasLen, 2)
c.Check(members[0], Equals, "World")
c.Check(members[1], Equals, "Hello")
c.Check(members, DeepEquals, []interface{}{"World", "Hello"})
}
func (t *RedisTest) TestSCard(c *C) {
@ -859,7 +835,6 @@ func (t *RedisTest) TestSDiff(c *C) {
values, err := t.redisC.SDiff("set1", "set2").Reply()
c.Check(err, IsNil)
c.Check(values, HasLen, 2)
c.Check(values, DeepEquals, []interface{}{"a", "b"})
}
@ -878,7 +853,6 @@ func (t *RedisTest) TestSDiffStore(c *C) {
values, err := t.redisC.SMembers("set").Reply()
c.Check(err, IsNil)
c.Check(values, HasLen, 2)
c.Check(values, DeepEquals, []interface{}{"a", "b"})
}
@ -893,7 +867,6 @@ func (t *RedisTest) TestSInter(c *C) {
values, err := t.redisC.SInter("set1", "set2").Reply()
c.Check(err, IsNil)
c.Check(values, HasLen, 1)
c.Check(values, DeepEquals, []interface{}{"c"})
}
@ -912,7 +885,6 @@ func (t *RedisTest) TestSInterStore(c *C) {
values, err := t.redisC.SMembers("set").Reply()
c.Check(err, IsNil)
c.Check(values, HasLen, 1)
c.Check(values, DeepEquals, []interface{}{"c"})
}
@ -934,7 +906,6 @@ func (t *RedisTest) TestSMembers(c *C) {
values, err := t.redisC.SMembers("set").Reply()
c.Check(err, IsNil)
c.Check(values, HasLen, 2)
c.Check(values, DeepEquals, []interface{}{"World", "Hello"})
}
@ -950,12 +921,10 @@ func (t *RedisTest) TestSMove(c *C) {
values, err := t.redisC.SMembers("set1").Reply()
c.Check(err, IsNil)
c.Check(values, HasLen, 1)
c.Check(values, DeepEquals, []interface{}{"one"})
values, err = t.redisC.SMembers("set2").Reply()
c.Check(err, IsNil)
c.Check(values, HasLen, 2)
c.Check(values, DeepEquals, []interface{}{"three", "two"})
}
@ -1002,7 +971,6 @@ func (t *RedisTest) TestSRem(c *C) {
values, err := t.redisC.SMembers("set").Reply()
c.Check(err, IsNil)
c.Check(values, HasLen, 2)
c.Check(values, DeepEquals, []interface{}{"three", "two"})
}
@ -1040,6 +1008,263 @@ func (t *RedisTest) TestSUnionStore(c *C) {
//------------------------------------------------------------------------------
func (t *RedisTest) TestZAdd(c *C) {
n, err := t.redisC.ZAdd("zset", redis.NewZMember(1, "one")).Reply()
c.Check(err, IsNil)
c.Check(n, Equals, int64(1))
n, err = t.redisC.ZAdd("zset", redis.NewZMember(1, "uno")).Reply()
c.Check(err, IsNil)
c.Check(n, Equals, int64(1))
n, err = t.redisC.ZAdd("zset", redis.NewZMember(2, "two")).Reply()
c.Check(err, IsNil)
c.Check(n, Equals, int64(1))
n, err = t.redisC.ZAdd("zset", redis.NewZMember(3, "two")).Reply()
c.Check(err, IsNil)
c.Check(n, Equals, int64(0))
values, err := t.redisC.ZRange("zset", 0, -1, true).Reply()
c.Check(err, IsNil)
c.Check(values, DeepEquals, []interface{}{"one", "1", "uno", "1", "two", "3"})
}
func (t *RedisTest) TestZCard(c *C) {
t.redisC.ZAdd("zset", redis.NewZMember(1, "one")).Reply()
t.redisC.ZAdd("zset", redis.NewZMember(2, "two")).Reply()
n, err := t.redisC.ZCard("zset").Reply()
c.Check(err, IsNil)
c.Check(n, Equals, int64(2))
}
func (t *RedisTest) TestZCount(c *C) {
t.redisC.ZAdd("zset", redis.NewZMember(1, "one")).Reply()
t.redisC.ZAdd("zset", redis.NewZMember(2, "two")).Reply()
t.redisC.ZAdd("zset", redis.NewZMember(3, "three")).Reply()
n, err := t.redisC.ZCount("zset", "-inf", "+inf").Reply()
c.Check(err, IsNil)
c.Check(n, Equals, int64(3))
n, err = t.redisC.ZCount("zset", "(1", "3").Reply()
c.Check(err, IsNil)
c.Check(n, Equals, int64(2))
}
func (t *RedisTest) TestZIncrBy(c *C) {
t.redisC.ZAdd("zset", redis.NewZMember(1, "one")).Reply()
t.redisC.ZAdd("zset", redis.NewZMember(2, "two")).Reply()
t.redisC.ZIncrBy("zset", 2, "one").Reply()
values, err := t.redisC.ZRange("zset", 0, -1, true).Reply()
c.Check(err, IsNil)
c.Check(values, DeepEquals, []interface{}{"two", "2", "one", "3"})
}
func (t *RedisTest) TestZInterStore(c *C) {
t.redisC.ZAdd("zset1", redis.NewZMember(1, "one")).Reply()
t.redisC.ZAdd("zset1", redis.NewZMember(2, "two")).Reply()
t.redisC.ZAdd("zset2", redis.NewZMember(1, "one")).Reply()
t.redisC.ZAdd("zset2", redis.NewZMember(2, "two")).Reply()
t.redisC.ZAdd("zset3", redis.NewZMember(3, "two")).Reply()
n, err := t.redisC.ZInterStore(
"out",
2,
[]string{"zset1", "zset2"},
[]int64{2, 3},
"",
).Reply()
c.Check(err, IsNil)
c.Check(n, Equals, int64(2))
values, err := t.redisC.ZRange("out", 0, -1, true).Reply()
c.Check(err, IsNil)
c.Check(values, DeepEquals, []interface{}{"one", "5", "two", "10"})
}
func (t *RedisTest) TestZRange(c *C) {
t.redisC.ZAdd("zset", redis.NewZMember(1, "one")).Reply()
t.redisC.ZAdd("zset", redis.NewZMember(2, "two")).Reply()
t.redisC.ZAdd("zset", redis.NewZMember(3, "three")).Reply()
values, err := t.redisC.ZRange("zset", 0, -1, false).Reply()
c.Check(err, IsNil)
c.Check(values, DeepEquals, []interface{}{"one", "two", "three"})
values, err = t.redisC.ZRange("zset", 2, 3, false).Reply()
c.Check(err, IsNil)
c.Check(values, DeepEquals, []interface{}{"three"})
values, err = t.redisC.ZRange("zset", -2, -1, false).Reply()
c.Check(err, IsNil)
c.Check(values, DeepEquals, []interface{}{"two", "three"})
}
func (t *RedisTest) TestZRangeByScore(c *C) {
t.redisC.ZAdd("zset", redis.NewZMember(1, "one")).Reply()
t.redisC.ZAdd("zset", redis.NewZMember(2, "two")).Reply()
t.redisC.ZAdd("zset", redis.NewZMember(3, "three")).Reply()
values, err := t.redisC.ZRangeByScore("zset", "-inf", "+inf", false, nil).Reply()
c.Check(err, IsNil)
c.Check(values, DeepEquals, []interface{}{"one", "two", "three"})
values, err = t.redisC.ZRangeByScore("zset", "1", "2", false, nil).Reply()
c.Check(err, IsNil)
c.Check(values, DeepEquals, []interface{}{"one", "two"})
values, err = t.redisC.ZRangeByScore("zset", "(1", "2", false, nil).Reply()
c.Check(err, IsNil)
c.Check(values, DeepEquals, []interface{}{"two"})
values, err = t.redisC.ZRangeByScore("zset", "(1", "(2", false, nil).Reply()
c.Check(err, IsNil)
c.Check(values, DeepEquals, []interface{}{})
}
func (t *RedisTest) TestZRank(c *C) {
t.redisC.ZAdd("zset", redis.NewZMember(1, "one")).Reply()
t.redisC.ZAdd("zset", redis.NewZMember(2, "two")).Reply()
t.redisC.ZAdd("zset", redis.NewZMember(3, "three")).Reply()
n, err := t.redisC.ZRank("zset", "three").Reply()
c.Check(err, IsNil)
c.Check(n, Equals, int64(2))
n, err = t.redisC.ZRank("zset", "four").Reply()
c.Check(err, Equals, redis.Nil)
c.Check(n, Equals, int64(0))
}
func (t *RedisTest) TestZRem(c *C) {
t.redisC.ZAdd("zset", redis.NewZMember(1, "one")).Reply()
t.redisC.ZAdd("zset", redis.NewZMember(2, "two")).Reply()
t.redisC.ZAdd("zset", redis.NewZMember(3, "three")).Reply()
n, err := t.redisC.ZRem("zset", "two").Reply()
c.Check(err, IsNil)
c.Check(n, Equals, int64(1))
values, err := t.redisC.ZRange("zset", 0, -1, true).Reply()
c.Check(err, IsNil)
c.Check(values, DeepEquals, []interface{}{"one", "1", "three", "3"})
}
func (t *RedisTest) TestZRemRangeByRank(c *C) {
t.redisC.ZAdd("zset", redis.NewZMember(1, "one")).Reply()
t.redisC.ZAdd("zset", redis.NewZMember(2, "two")).Reply()
t.redisC.ZAdd("zset", redis.NewZMember(3, "three")).Reply()
n, err := t.redisC.ZRemRangeByRank("zset", 0, 1).Reply()
c.Check(err, IsNil)
c.Check(n, Equals, int64(2))
values, err := t.redisC.ZRange("zset", 0, -1, true).Reply()
c.Check(err, IsNil)
c.Check(values, DeepEquals, []interface{}{"three", "3"})
}
func (t *RedisTest) TestZRemRangeByScore(c *C) {
t.redisC.ZAdd("zset", redis.NewZMember(1, "one")).Reply()
t.redisC.ZAdd("zset", redis.NewZMember(2, "two")).Reply()
t.redisC.ZAdd("zset", redis.NewZMember(3, "three")).Reply()
n, err := t.redisC.ZRemRangeByScore("zset", "-inf", "(2").Reply()
c.Check(err, IsNil)
c.Check(n, Equals, int64(1))
values, err := t.redisC.ZRange("zset", 0, -1, true).Reply()
c.Check(err, IsNil)
c.Check(values, DeepEquals, []interface{}{"two", "2", "three", "3"})
}
func (t *RedisTest) TestZRevRange(c *C) {
t.redisC.ZAdd("zset", redis.NewZMember(1, "one")).Reply()
t.redisC.ZAdd("zset", redis.NewZMember(2, "two")).Reply()
t.redisC.ZAdd("zset", redis.NewZMember(3, "three")).Reply()
values, err := t.redisC.ZRevRange("zset", "0", "-1", false).Reply()
c.Check(err, IsNil)
c.Check(values, DeepEquals, []interface{}{"three", "two", "one"})
values, err = t.redisC.ZRevRange("zset", "2", "3", false).Reply()
c.Check(err, IsNil)
c.Check(values, DeepEquals, []interface{}{"one"})
values, err = t.redisC.ZRevRange("zset", "-2", "-1", false).Reply()
c.Check(err, IsNil)
c.Check(values, DeepEquals, []interface{}{"two", "one"})
}
func (t *RedisTest) TestZRevRangeByScore(c *C) {
t.redisC.ZAdd("zset", redis.NewZMember(1, "one")).Reply()
t.redisC.ZAdd("zset", redis.NewZMember(2, "two")).Reply()
t.redisC.ZAdd("zset", redis.NewZMember(3, "three")).Reply()
values, err := t.redisC.ZRevRangeByScore("zset", "+inf", "-inf", false, nil).Reply()
c.Check(err, IsNil)
c.Check(values, DeepEquals, []interface{}{"three", "two", "one"})
values, err = t.redisC.ZRevRangeByScore("zset", "2", "(1", false, nil).Reply()
c.Check(err, IsNil)
c.Check(values, DeepEquals, []interface{}{"two"})
values, err = t.redisC.ZRevRangeByScore("zset", "(2", "(1", false, nil).Reply()
c.Check(err, IsNil)
c.Check(values, DeepEquals, []interface{}{})
}
func (t *RedisTest) TestZRevRank(c *C) {
t.redisC.ZAdd("zset", redis.NewZMember(1, "one")).Reply()
t.redisC.ZAdd("zset", redis.NewZMember(2, "two")).Reply()
t.redisC.ZAdd("zset", redis.NewZMember(3, "three")).Reply()
n, err := t.redisC.ZRevRank("zset", "one").Reply()
c.Check(err, IsNil)
c.Check(n, Equals, int64(2))
n, err = t.redisC.ZRevRank("zset", "four").Reply()
c.Check(err, Equals, redis.Nil)
c.Check(n, Equals, int64(0))
}
func (t *RedisTest) TestZScore(c *C) {
t.redisC.ZAdd("zset", redis.NewZMember(1.001, "one")).Reply()
score, err := t.redisC.ZScore("zset", "one").Reply()
c.Check(err, IsNil)
c.Check(score, Equals, float64(1.001))
}
func (t *RedisTest) TestZUnionStore(c *C) {
t.redisC.ZAdd("zset1", redis.NewZMember(1, "one")).Reply()
t.redisC.ZAdd("zset1", redis.NewZMember(2, "two")).Reply()
t.redisC.ZAdd("zset2", redis.NewZMember(1, "one")).Reply()
t.redisC.ZAdd("zset2", redis.NewZMember(2, "two")).Reply()
t.redisC.ZAdd("zset2", redis.NewZMember(3, "three")).Reply()
n, err := t.redisC.ZUnionStore(
"out",
2,
[]string{"zset1", "zset2"},
[]int64{2, 3},
"",
).Reply()
c.Check(err, IsNil)
c.Check(n, Equals, int64(3))
values, err := t.redisC.ZRange("out", 0, -1, true).Reply()
c.Check(err, IsNil)
c.Check(values, DeepEquals, []interface{}{"one", "5", "three", "9", "two", "10"})
}
//------------------------------------------------------------------------------
func (t *RedisTest) TestPubSub(c *C) {
pubsub := t.redisC.PubSubClient()

View File

@ -13,6 +13,16 @@ var Nil = errors.New("(nil)")
//------------------------------------------------------------------------------
func isNil(buf []byte) bool {
return len(buf) == 3 && buf[0] == '$' && buf[1] == '-' && buf[2] == '1'
}
func isEmpty(buf []byte) bool {
return len(buf) == 2 && buf[0] == '$' && buf[1] == '0'
}
//------------------------------------------------------------------------------
func ParseReq(rd *bufreader.Reader) ([]string, error) {
line, err := rd.ReadLine('\n')
if err != nil {
@ -173,6 +183,42 @@ func (r *IntReq) Reply() (int64, error) {
//------------------------------------------------------------------------------
type IntNilReq struct {
*BaseReq
}
func NewIntNilReq(args ...string) *IntNilReq {
return &IntNilReq{
BaseReq: NewBaseReq(args...),
}
}
func (r *IntNilReq) ParseReply(rd *bufreader.Reader) (interface{}, error) {
line, err := rd.ReadLine('\n')
if err != nil {
return nil, err
}
if line[0] == '-' {
return nil, errors.New(string(line[1:]))
} else if line[0] == ':' {
return strconv.ParseInt(string(line[1:]), 10, 64)
} else if isNil(line) {
return nil, Nil
}
return nil, fmt.Errorf("Expected ':', but got %q of %q.", line, rd.Bytes())
}
func (r *IntNilReq) Reply() (int64, error) {
if r.err != nil {
return 0, r.err
}
return r.val.(int64), nil
}
//------------------------------------------------------------------------------
type BoolReq struct {
*BaseReq
}
@ -229,7 +275,7 @@ func (r *BulkReq) ParseReply(rd *bufreader.Reader) (interface{}, error) {
return nil, fmt.Errorf("Expected '$', but got %q of %q.", line, rd.Bytes())
}
if len(line) >= 3 && line[1] == '-' && line[2] == '1' {
if isNil(line) {
return nil, Nil
}
@ -250,6 +296,49 @@ func (r *BulkReq) Reply() (string, error) {
//------------------------------------------------------------------------------
type FloatReq struct {
*BaseReq
}
func NewFloatReq(args ...string) *FloatReq {
return &FloatReq{
BaseReq: NewBaseReq(args...),
}
}
func (r *FloatReq) ParseReply(rd *bufreader.Reader) (interface{}, error) {
line, err := rd.ReadLine('\n')
if err != nil {
return nil, err
}
if line[0] == '-' {
return nil, errors.New(string(line[1:]))
} else if line[0] != '$' {
return nil, fmt.Errorf("Expected '$', but got %q of %q.", line, rd.Bytes())
}
if isNil(line) {
return nil, Nil
}
line, err = rd.ReadLine('\n')
if err != nil {
return nil, err
}
return strconv.ParseFloat(string(line), 64)
}
func (r *FloatReq) Reply() (float64, error) {
if r.err != nil {
return 0, r.err
}
return r.val.(float64), nil
}
//------------------------------------------------------------------------------
type MultiBulkReq struct {
*BaseReq
}
@ -276,7 +365,7 @@ func (r *MultiBulkReq) ParseReply(rd *bufreader.Reader) (interface{}, error) {
if len(line) >= 2 && line[1] == '0' {
return val, nil
} else if len(line) >= 3 && line[1] == '-' && line[2] == '1' {
} else if isNil(line) {
return nil, Nil
}
@ -293,9 +382,9 @@ func (r *MultiBulkReq) ParseReply(rd *bufreader.Reader) (interface{}, error) {
}
val = append(val, n)
} else if line[0] == '$' {
if len(line) >= 2 && line[1] == '0' {
if isEmpty(line) {
val = append(val, "")
} else if len(line) >= 3 && line[1] == '-' && line[2] == '1' {
} else if isNil(line) {
val = append(val, nil)
} else {
line, err = rd.ReadLine('\n')