From dc9bffa57da5d18e5a1e852784a8c0cfd570072f Mon Sep 17 00:00:00 2001 From: Vladimir Mihailenco Date: Sat, 5 Jul 2014 13:46:27 +0300 Subject: [PATCH] Rework ZRangeWithScores. --- command.go | 22 ++++---- commands.go | 32 +++--------- parser.go | 71 +++++++++++++------------- redis_test.go | 138 +++++++++++++++++++++++++------------------------- 4 files changed, 124 insertions(+), 139 deletions(-) diff --git a/command.go b/command.go index 0c8992c0..99bbd2b2 100644 --- a/command.go +++ b/command.go @@ -21,7 +21,7 @@ var ( _ Cmder = (*StringSliceCmd)(nil) _ Cmder = (*BoolSliceCmd)(nil) _ Cmder = (*StringStringMapCmd)(nil) - _ Cmder = (*StringFloatMapCmd)(nil) + _ Cmder = (*ZSliceCmd)(nil) _ Cmder = (*ScanCmd)(nil) ) @@ -493,37 +493,37 @@ func (cmd *StringStringMapCmd) parseReply(rd *bufio.Reader) error { //------------------------------------------------------------------------------ -type StringFloatMapCmd struct { +type ZSliceCmd struct { *baseCmd - val map[string]float64 + val []Z } -func NewStringFloatMapCmd(args ...string) *StringFloatMapCmd { - return &StringFloatMapCmd{ +func NewZSliceCmd(args ...string) *ZSliceCmd { + return &ZSliceCmd{ baseCmd: newBaseCmd(args...), } } -func (cmd *StringFloatMapCmd) Val() map[string]float64 { +func (cmd *ZSliceCmd) Val() []Z { return cmd.val } -func (cmd *StringFloatMapCmd) Result() (map[string]float64, error) { +func (cmd *ZSliceCmd) Result() ([]Z, error) { return cmd.val, cmd.err } -func (cmd *StringFloatMapCmd) String() string { +func (cmd *ZSliceCmd) String() string { return cmdString(cmd, cmd.val) } -func (cmd *StringFloatMapCmd) parseReply(rd *bufio.Reader) error { - v, err := parseReply(rd, parseStringFloatMap) +func (cmd *ZSliceCmd) parseReply(rd *bufio.Reader) error { + v, err := parseReply(rd, parseZSlice) if err != nil { cmd.err = err return err } - cmd.val = v.(map[string]float64) + cmd.val = v.([]Z) return nil } diff --git a/commands.go b/commands.go index 8272bb89..a3a35313 100644 --- a/commands.go +++ b/commands.go @@ -854,11 +854,7 @@ func (c *Client) ZRange(key string, start, stop int64) *StringSliceCmd { return c.zRange(key, start, stop, false) } -func (c *Client) ZRangeWithScores(key string, start, stop int64) *StringSliceCmd { - return c.zRange(key, start, stop, true) -} - -func (c *Client) ZRangeWithScoresMap(key string, start, stop int64) *StringFloatMapCmd { +func (c *Client) ZRangeWithScores(key string, start, stop int64) *ZSliceCmd { args := []string{ "ZRANGE", key, @@ -866,7 +862,7 @@ func (c *Client) ZRangeWithScoresMap(key string, start, stop int64) *StringFloat strconv.FormatInt(stop, 10), "WITHSCORES", } - cmd := NewStringFloatMapCmd(args...) + cmd := NewZSliceCmd(args...) c.Process(cmd) return cmd } @@ -899,11 +895,7 @@ func (c *Client) ZRangeByScore(key string, opt ZRangeByScore) *StringSliceCmd { return c.zRangeByScore(key, opt, false) } -func (c *Client) ZRangeByScoreWithScores(key string, opt ZRangeByScore) *StringSliceCmd { - return c.zRangeByScore(key, opt, true) -} - -func (c *Client) ZRangeByScoreWithScoresMap(key string, opt ZRangeByScore) *StringFloatMapCmd { +func (c *Client) ZRangeByScoreWithScores(key string, opt ZRangeByScore) *ZSliceCmd { args := []string{"ZRANGEBYSCORE", key, opt.Min, opt.Max, "WITHSCORES"} if opt.Offset != 0 || opt.Count != 0 { args = append( @@ -913,7 +905,7 @@ func (c *Client) ZRangeByScoreWithScoresMap(key string, opt ZRangeByScore) *Stri strconv.FormatInt(opt.Count, 10), ) } - cmd := NewStringFloatMapCmd(args...) + cmd := NewZSliceCmd(args...) c.Process(cmd) return cmd } @@ -962,13 +954,9 @@ func (c *Client) ZRevRange(key, start, stop string) *StringSliceCmd { return c.zRevRange(key, start, stop, false) } -func (c *Client) ZRevRangeWithScores(key, start, stop string) *StringSliceCmd { - return c.zRevRange(key, start, stop, true) -} - -func (c *Client) ZRevRangeWithScoresMap(key, start, stop string) *StringFloatMapCmd { +func (c *Client) ZRevRangeWithScores(key, start, stop string) *ZSliceCmd { args := []string{"ZREVRANGE", key, start, stop, "WITHSCORES"} - cmd := NewStringFloatMapCmd(args...) + cmd := NewZSliceCmd(args...) c.Process(cmd) return cmd } @@ -995,11 +983,7 @@ func (c *Client) ZRevRangeByScore(key string, opt ZRangeByScore) *StringSliceCmd return c.zRevRangeByScore(key, opt, false) } -func (c *Client) ZRevRangeByScoreWithScores(key string, opt ZRangeByScore) *StringSliceCmd { - return c.zRevRangeByScore(key, opt, true) -} - -func (c *Client) ZRevRangeByScoreWithScoresMap(key string, opt ZRangeByScore) *StringFloatMapCmd { +func (c *Client) ZRevRangeByScoreWithScores(key string, opt ZRangeByScore) *ZSliceCmd { args := []string{"ZREVRANGEBYSCORE", key, opt.Max, opt.Min, "WITHSCORES"} if opt.Offset != 0 || opt.Count != 0 { args = append( @@ -1009,7 +993,7 @@ func (c *Client) ZRevRangeByScoreWithScoresMap(key string, opt ZRangeByScore) *S strconv.FormatInt(opt.Count, 10), ) } - cmd := NewStringFloatMapCmd(args...) + cmd := NewZSliceCmd(args...) c.Process(cmd) return cmd } diff --git a/parser.go b/parser.go index 48dd9b4c..b4c380c7 100644 --- a/parser.go +++ b/parser.go @@ -11,8 +11,7 @@ import ( type multiBulkParser func(rd *bufio.Reader, n int64) (interface{}, error) var ( - errReaderTooSmall = errors.New("redis: reader is too small") - errInvalidReplyType = errors.New("redis: invalid reply type") + errReaderTooSmall = errors.New("redis: reader is too small") ) //------------------------------------------------------------------------------ @@ -175,15 +174,15 @@ func parseSlice(rd *bufio.Reader, n int64) (interface{}, error) { func parseStringSlice(rd *bufio.Reader, n int64) (interface{}, error) { vals := make([]string, 0, n) for i := int64(0); i < n; i++ { - vi, err := parseReply(rd, nil) + viface, err := parseReply(rd, nil) if err != nil { return nil, err } - if v, ok := vi.(string); ok { - vals = append(vals, v) - } else { - return nil, errInvalidReplyType + v, ok := viface.(string) + if !ok { + return nil, fmt.Errorf("got %T, expected string", viface) } + vals = append(vals, v) } return vals, nil } @@ -191,15 +190,15 @@ func parseStringSlice(rd *bufio.Reader, n int64) (interface{}, error) { func parseBoolSlice(rd *bufio.Reader, n int64) (interface{}, error) { vals := make([]bool, 0, n) for i := int64(0); i < n; i++ { - vi, err := parseReply(rd, nil) + viface, err := parseReply(rd, nil) if err != nil { return nil, err } - if v, ok := vi.(int64); ok { - vals = append(vals, v == 1) - } else { - return nil, errInvalidReplyType + v, ok := viface.(int64) + if !ok { + return nil, fmt.Errorf("got %T, expected int64", viface) } + vals = append(vals, v == 1) } return vals, nil } @@ -207,22 +206,22 @@ func parseBoolSlice(rd *bufio.Reader, n int64) (interface{}, error) { func parseStringStringMap(rd *bufio.Reader, n int64) (interface{}, error) { m := make(map[string]string, n/2) for i := int64(0); i < n; i += 2 { - keyI, err := parseReply(rd, nil) + keyiface, err := parseReply(rd, nil) if err != nil { return nil, err } - key, ok := keyI.(string) + key, ok := keyiface.(string) if !ok { - return nil, errInvalidReplyType + return nil, fmt.Errorf("got %T, expected string", keyiface) } - valueI, err := parseReply(rd, nil) + valueiface, err := parseReply(rd, nil) if err != nil { return nil, err } - value, ok := valueI.(string) + value, ok := valueiface.(string) if !ok { - return nil, errInvalidReplyType + return nil, fmt.Errorf("got %T, expected string", valueiface) } m[key] = value @@ -230,32 +229,34 @@ func parseStringStringMap(rd *bufio.Reader, n int64) (interface{}, error) { return m, nil } -func parseStringFloatMap(rd *bufio.Reader, n int64) (interface{}, error) { - m := make(map[string]float64, n/2) +func parseZSlice(rd *bufio.Reader, n int64) (interface{}, error) { + zz := make([]Z, n/2) for i := int64(0); i < n; i += 2 { - keyI, err := parseReply(rd, nil) - if err != nil { - return nil, err - } - key, ok := keyI.(string) - if !ok { - return nil, errInvalidReplyType - } + z := &zz[i/2] - valueI, err := parseReply(rd, nil) + memberiface, err := parseReply(rd, nil) if err != nil { return nil, err } - valueS, ok := valueI.(string) + member, ok := memberiface.(string) if !ok { - return nil, errInvalidReplyType + return nil, fmt.Errorf("got %T, expected string", memberiface) } - value, err := strconv.ParseFloat(valueS, 64) + z.Member = member + + scoreiface, err := parseReply(rd, nil) if err != nil { return nil, err } - - m[key] = value + scorestr, ok := scoreiface.(string) + if !ok { + return nil, fmt.Errorf("got %T, expected string", scoreiface) + } + score, err := strconv.ParseFloat(scorestr, 64) + if err != nil { + return nil, err + } + z.Score = score } - return m, nil + return zz, nil } diff --git a/redis_test.go b/redis_test.go index c7c07c43..4d3e0034 100644 --- a/redis_test.go +++ b/redis_test.go @@ -1984,9 +1984,9 @@ func (t *RedisTest) TestZAdd(c *C) { c.Assert(zAdd.Err(), IsNil) c.Assert(zAdd.Val(), Equals, int64(0)) - zRange := t.client.ZRangeWithScores("zset", 0, -1) - c.Assert(zRange.Err(), IsNil) - c.Assert(zRange.Val(), DeepEquals, []string{"one", "1", "uno", "1", "two", "3"}) + val, err := t.client.ZRangeWithScores("zset", 0, -1).Result() + c.Assert(err, IsNil) + c.Assert(val, DeepEquals, []redis.Z{{1, "one"}, {1, "uno"}, {3, "two"}}) } func (t *RedisTest) TestZCard(c *C) { @@ -2027,9 +2027,9 @@ func (t *RedisTest) TestZIncrBy(c *C) { c.Assert(zIncrBy.Err(), IsNil) c.Assert(zIncrBy.Val(), Equals, float64(3)) - zRange := t.client.ZRangeWithScores("zset", 0, -1) - c.Assert(zRange.Err(), IsNil) - c.Assert(zRange.Val(), DeepEquals, []string{"two", "2", "one", "3"}) + val, err := t.client.ZRangeWithScores("zset", 0, -1).Result() + c.Assert(err, IsNil) + c.Assert(val, DeepEquals, []redis.Z{{2, "two"}, {3, "one"}}) } func (t *RedisTest) TestZInterStore(c *C) { @@ -2050,9 +2050,9 @@ func (t *RedisTest) TestZInterStore(c *C) { c.Assert(zInterStore.Err(), IsNil) c.Assert(zInterStore.Val(), Equals, int64(2)) - zRange := t.client.ZRangeWithScores("out", 0, -1) - c.Assert(zRange.Err(), IsNil) - c.Assert(zRange.Val(), DeepEquals, []string{"one", "5", "two", "10"}) + val, err := t.client.ZRangeWithScores("out", 0, -1).Result() + c.Assert(err, IsNil) + c.Assert(val, DeepEquals, []redis.Z{{5, "one"}, {10, "two"}}) } func (t *RedisTest) TestZRange(c *C) { @@ -2076,7 +2076,7 @@ func (t *RedisTest) TestZRange(c *C) { c.Assert(zRange.Val(), DeepEquals, []string{"two", "three"}) } -func (t *RedisTest) TestZRangeWithScoresMap(c *C) { +func (t *RedisTest) TestZRangeWithScores(c *C) { zAdd := t.client.ZAdd("zset", redis.Z{1, "one"}) c.Assert(zAdd.Err(), IsNil) zAdd = t.client.ZAdd("zset", redis.Z{2, "two"}) @@ -2084,17 +2084,17 @@ func (t *RedisTest) TestZRangeWithScoresMap(c *C) { zAdd = t.client.ZAdd("zset", redis.Z{3, "three"}) c.Assert(zAdd.Err(), IsNil) - zRange := t.client.ZRangeWithScoresMap("zset", 0, -1) - c.Assert(zRange.Err(), IsNil) - c.Assert(zRange.Val(), DeepEquals, map[string]float64{"one": 1, "two": 2, "three": 3}) + val, err := t.client.ZRangeWithScores("zset", 0, -1).Result() + c.Assert(err, IsNil) + c.Assert(val, DeepEquals, []redis.Z{{1, "one"}, {2, "two"}, {3, "three"}}) - zRange = t.client.ZRangeWithScoresMap("zset", 2, 3) - c.Assert(zRange.Err(), IsNil) - c.Assert(zRange.Val(), DeepEquals, map[string]float64{"three": 3}) + val, err = t.client.ZRangeWithScores("zset", 2, 3).Result() + c.Assert(err, IsNil) + c.Assert(val, DeepEquals, []redis.Z{{3, "three"}}) - zRange = t.client.ZRangeWithScoresMap("zset", -2, -1) - c.Assert(zRange.Err(), IsNil) - c.Assert(zRange.Val(), DeepEquals, map[string]float64{"two": 2, "three": 3}) + val, err = t.client.ZRangeWithScores("zset", -2, -1).Result() + c.Assert(err, IsNil) + c.Assert(val, DeepEquals, []redis.Z{{2, "two"}, {3, "three"}}) } func (t *RedisTest) TestZRangeByScore(c *C) { @@ -2142,33 +2142,33 @@ func (t *RedisTest) TestZRangeByScoreWithScoresMap(c *C) { zAdd = t.client.ZAdd("zset", redis.Z{3, "three"}) c.Assert(zAdd.Err(), IsNil) - zRangeByScore := t.client.ZRangeByScoreWithScoresMap("zset", redis.ZRangeByScore{ + val, err := t.client.ZRangeByScoreWithScores("zset", redis.ZRangeByScore{ Min: "-inf", Max: "+inf", - }) - c.Assert(zRangeByScore.Err(), IsNil) - c.Assert(zRangeByScore.Val(), DeepEquals, map[string]float64{"one": 1, "two": 2, "three": 3}) + }).Result() + c.Assert(err, IsNil) + c.Assert(val, DeepEquals, []redis.Z{{1, "one"}, {2, "two"}, {3, "three"}}) - zRangeByScore = t.client.ZRangeByScoreWithScoresMap("zset", redis.ZRangeByScore{ + val, err = t.client.ZRangeByScoreWithScores("zset", redis.ZRangeByScore{ Min: "1", Max: "2", - }) - c.Assert(zRangeByScore.Err(), IsNil) - c.Assert(zRangeByScore.Val(), DeepEquals, map[string]float64{"one": 1, "two": 2}) + }).Result() + c.Assert(err, IsNil) + c.Assert(val, DeepEquals, []redis.Z{{1, "one"}, {2, "two"}}) - zRangeByScore = t.client.ZRangeByScoreWithScoresMap("zset", redis.ZRangeByScore{ + val, err = t.client.ZRangeByScoreWithScores("zset", redis.ZRangeByScore{ Min: "(1", Max: "2", - }) - c.Assert(zRangeByScore.Err(), IsNil) - c.Assert(zRangeByScore.Val(), DeepEquals, map[string]float64{"two": 2}) + }).Result() + c.Assert(err, IsNil) + c.Assert(val, DeepEquals, []redis.Z{{2, "two"}}) - zRangeByScore = t.client.ZRangeByScoreWithScoresMap("zset", redis.ZRangeByScore{ + val, err = t.client.ZRangeByScoreWithScores("zset", redis.ZRangeByScore{ Min: "(1", Max: "(2", - }) - c.Assert(zRangeByScore.Err(), IsNil) - c.Assert(zRangeByScore.Val(), DeepEquals, map[string]float64{}) + }).Result() + c.Assert(err, IsNil) + c.Assert(val, DeepEquals, []redis.Z{}) } func (t *RedisTest) TestZRank(c *C) { @@ -2200,9 +2200,9 @@ func (t *RedisTest) TestZRem(c *C) { c.Assert(zRem.Err(), IsNil) c.Assert(zRem.Val(), Equals, int64(1)) - zRange := t.client.ZRangeWithScores("zset", 0, -1) - c.Assert(zRange.Err(), IsNil) - c.Assert(zRange.Val(), DeepEquals, []string{"one", "1", "three", "3"}) + val, err := t.client.ZRangeWithScores("zset", 0, -1).Result() + c.Assert(err, IsNil) + c.Assert(val, DeepEquals, []redis.Z{{1, "one"}, {3, "three"}}) } func (t *RedisTest) TestZRemRangeByRank(c *C) { @@ -2217,9 +2217,9 @@ func (t *RedisTest) TestZRemRangeByRank(c *C) { c.Assert(zRemRangeByRank.Err(), IsNil) c.Assert(zRemRangeByRank.Val(), Equals, int64(2)) - zRange := t.client.ZRangeWithScores("zset", 0, -1) - c.Assert(zRange.Err(), IsNil) - c.Assert(zRange.Val(), DeepEquals, []string{"three", "3"}) + val, err := t.client.ZRangeWithScores("zset", 0, -1).Result() + c.Assert(err, IsNil) + c.Assert(val, DeepEquals, []redis.Z{{3, "three"}}) } func (t *RedisTest) TestZRemRangeByScore(c *C) { @@ -2234,9 +2234,9 @@ func (t *RedisTest) TestZRemRangeByScore(c *C) { c.Assert(zRemRangeByScore.Err(), IsNil) c.Assert(zRemRangeByScore.Val(), Equals, int64(1)) - zRange := t.client.ZRangeWithScores("zset", 0, -1) - c.Assert(zRange.Err(), IsNil) - c.Assert(zRange.Val(), DeepEquals, []string{"two", "2", "three", "3"}) + val, err := t.client.ZRangeWithScores("zset", 0, -1).Result() + c.Assert(err, IsNil) + c.Assert(val, DeepEquals, []redis.Z{{2, "two"}, {3, "three"}}) } func (t *RedisTest) TestZRevRange(c *C) { @@ -2268,17 +2268,17 @@ func (t *RedisTest) TestZRevRangeWithScoresMap(c *C) { zAdd = t.client.ZAdd("zset", redis.Z{3, "three"}) c.Assert(zAdd.Err(), IsNil) - zRevRange := t.client.ZRevRangeWithScoresMap("zset", "0", "-1") - c.Assert(zRevRange.Err(), IsNil) - c.Assert(zRevRange.Val(), DeepEquals, map[string]float64{"three": 3, "two": 2, "one": 1}) + val, err := t.client.ZRevRangeWithScores("zset", "0", "-1").Result() + c.Assert(err, IsNil) + c.Assert(val, DeepEquals, []redis.Z{{3, "three"}, {2, "two"}, {1, "one"}}) - zRevRange = t.client.ZRevRangeWithScoresMap("zset", "2", "3") - c.Assert(zRevRange.Err(), IsNil) - c.Assert(zRevRange.Val(), DeepEquals, map[string]float64{"one": 1}) + val, err = t.client.ZRevRangeWithScores("zset", "2", "3").Result() + c.Assert(err, IsNil) + c.Assert(val, DeepEquals, []redis.Z{{1, "one"}}) - zRevRange = t.client.ZRevRangeWithScoresMap("zset", "-2", "-1") - c.Assert(zRevRange.Err(), IsNil) - c.Assert(zRevRange.Val(), DeepEquals, map[string]float64{"two": 2, "one": 1}) + val, err = t.client.ZRevRangeWithScores("zset", "-2", "-1").Result() + c.Assert(err, IsNil) + c.Assert(val, DeepEquals, []redis.Z{{2, "two"}, {1, "one"}}) } func (t *RedisTest) TestZRevRangeByScore(c *C) { @@ -2316,7 +2316,7 @@ func (t *RedisTest) TestZRevRangeByScoreWithScores(c *C) { vals, err := t.client.ZRevRangeByScoreWithScores( "zset", redis.ZRangeByScore{Max: "+inf", Min: "-inf"}).Result() c.Assert(err, IsNil) - c.Assert(vals, DeepEquals, []string{"three", "3", "two", "2", "one", "1"}) + c.Assert(vals, DeepEquals, []redis.Z{{3, "three"}, {2, "two"}, {1, "one"}}) } func (t *RedisTest) TestZRevRangeByScoreWithScoresMap(c *C) { @@ -2327,20 +2327,20 @@ func (t *RedisTest) TestZRevRangeByScoreWithScoresMap(c *C) { zAdd = t.client.ZAdd("zset", redis.Z{3, "three"}) c.Assert(zAdd.Err(), IsNil) - zRevRangeByScore := t.client.ZRevRangeByScoreWithScoresMap( - "zset", redis.ZRangeByScore{Max: "+inf", Min: "-inf"}) - c.Assert(zRevRangeByScore.Err(), IsNil) - c.Assert(zRevRangeByScore.Val(), DeepEquals, map[string]float64{"three": 3, "two": 2, "one": 1}) + val, err := t.client.ZRevRangeByScoreWithScores( + "zset", redis.ZRangeByScore{Max: "+inf", Min: "-inf"}).Result() + c.Assert(err, IsNil) + c.Assert(val, DeepEquals, []redis.Z{{3, "three"}, {2, "two"}, {1, "one"}}) - zRevRangeByScore = t.client.ZRevRangeByScoreWithScoresMap( - "zset", redis.ZRangeByScore{Max: "2", Min: "(1"}) - c.Assert(zRevRangeByScore.Err(), IsNil) - c.Assert(zRevRangeByScore.Val(), DeepEquals, map[string]float64{"two": 2}) + val, err = t.client.ZRevRangeByScoreWithScores( + "zset", redis.ZRangeByScore{Max: "2", Min: "(1"}).Result() + c.Assert(err, IsNil) + c.Assert(val, DeepEquals, []redis.Z{{2, "two"}}) - zRevRangeByScore = t.client.ZRevRangeByScoreWithScoresMap( - "zset", redis.ZRangeByScore{Max: "(2", Min: "(1"}) - c.Assert(zRevRangeByScore.Err(), IsNil) - c.Assert(zRevRangeByScore.Val(), DeepEquals, map[string]float64{}) + val, err = t.client.ZRevRangeByScoreWithScores( + "zset", redis.ZRangeByScore{Max: "(2", Min: "(1"}).Result() + c.Assert(err, IsNil) + c.Assert(val, DeepEquals, []redis.Z{}) } func (t *RedisTest) TestZRevRank(c *C) { @@ -2387,9 +2387,9 @@ func (t *RedisTest) TestZUnionStore(c *C) { c.Assert(zUnionStore.Err(), IsNil) c.Assert(zUnionStore.Val(), Equals, int64(3)) - zRange := t.client.ZRangeWithScores("out", 0, -1) - c.Assert(zRange.Err(), IsNil) - c.Assert(zRange.Val(), DeepEquals, []string{"one", "5", "three", "9", "two", "10"}) + val, err := t.client.ZRangeWithScores("out", 0, -1).Result() + c.Assert(err, IsNil) + c.Assert(val, DeepEquals, []redis.Z{{5, "one"}, {9, "three"}, {10, "two"}}) } //------------------------------------------------------------------------------