mirror of https://github.com/go-redis/redis.git
773 lines
22 KiB
Go
773 lines
22 KiB
Go
package redis
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
type SortedSetCmdable interface {
|
|
BZPopMax(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd
|
|
BZPopMin(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd
|
|
BZMPop(ctx context.Context, timeout time.Duration, order string, count int64, keys ...string) *ZSliceWithKeyCmd
|
|
ZAdd(ctx context.Context, key string, members ...Z) *IntCmd
|
|
ZAddLT(ctx context.Context, key string, members ...Z) *IntCmd
|
|
ZAddGT(ctx context.Context, key string, members ...Z) *IntCmd
|
|
ZAddNX(ctx context.Context, key string, members ...Z) *IntCmd
|
|
ZAddXX(ctx context.Context, key string, members ...Z) *IntCmd
|
|
ZAddArgs(ctx context.Context, key string, args ZAddArgs) *IntCmd
|
|
ZAddArgsIncr(ctx context.Context, key string, args ZAddArgs) *FloatCmd
|
|
ZCard(ctx context.Context, key string) *IntCmd
|
|
ZCount(ctx context.Context, key, min, max string) *IntCmd
|
|
ZLexCount(ctx context.Context, key, min, max string) *IntCmd
|
|
ZIncrBy(ctx context.Context, key string, increment float64, member string) *FloatCmd
|
|
ZInter(ctx context.Context, store *ZStore) *StringSliceCmd
|
|
ZInterWithScores(ctx context.Context, store *ZStore) *ZSliceCmd
|
|
ZInterCard(ctx context.Context, limit int64, keys ...string) *IntCmd
|
|
ZInterStore(ctx context.Context, destination string, store *ZStore) *IntCmd
|
|
ZMPop(ctx context.Context, order string, count int64, keys ...string) *ZSliceWithKeyCmd
|
|
ZMScore(ctx context.Context, key string, members ...string) *FloatSliceCmd
|
|
ZPopMax(ctx context.Context, key string, count ...int64) *ZSliceCmd
|
|
ZPopMin(ctx context.Context, key string, count ...int64) *ZSliceCmd
|
|
ZRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd
|
|
ZRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd
|
|
ZRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd
|
|
ZRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd
|
|
ZRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd
|
|
ZRangeArgs(ctx context.Context, z ZRangeArgs) *StringSliceCmd
|
|
ZRangeArgsWithScores(ctx context.Context, z ZRangeArgs) *ZSliceCmd
|
|
ZRangeStore(ctx context.Context, dst string, z ZRangeArgs) *IntCmd
|
|
ZRank(ctx context.Context, key, member string) *IntCmd
|
|
ZRankWithScore(ctx context.Context, key, member string) *RankWithScoreCmd
|
|
ZRem(ctx context.Context, key string, members ...interface{}) *IntCmd
|
|
ZRemRangeByRank(ctx context.Context, key string, start, stop int64) *IntCmd
|
|
ZRemRangeByScore(ctx context.Context, key, min, max string) *IntCmd
|
|
ZRemRangeByLex(ctx context.Context, key, min, max string) *IntCmd
|
|
ZRevRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd
|
|
ZRevRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd
|
|
ZRevRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd
|
|
ZRevRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd
|
|
ZRevRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd
|
|
ZRevRank(ctx context.Context, key, member string) *IntCmd
|
|
ZRevRankWithScore(ctx context.Context, key, member string) *RankWithScoreCmd
|
|
ZScore(ctx context.Context, key, member string) *FloatCmd
|
|
ZUnionStore(ctx context.Context, dest string, store *ZStore) *IntCmd
|
|
ZRandMember(ctx context.Context, key string, count int) *StringSliceCmd
|
|
ZRandMemberWithScores(ctx context.Context, key string, count int) *ZSliceCmd
|
|
ZUnion(ctx context.Context, store ZStore) *StringSliceCmd
|
|
ZUnionWithScores(ctx context.Context, store ZStore) *ZSliceCmd
|
|
ZDiff(ctx context.Context, keys ...string) *StringSliceCmd
|
|
ZDiffWithScores(ctx context.Context, keys ...string) *ZSliceCmd
|
|
ZDiffStore(ctx context.Context, destination string, keys ...string) *IntCmd
|
|
ZScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd
|
|
}
|
|
|
|
// BZPopMax Redis `BZPOPMAX key [key ...] timeout` command.
|
|
func (c cmdable) BZPopMax(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd {
|
|
args := make([]interface{}, 1+len(keys)+1)
|
|
args[0] = "bzpopmax"
|
|
for i, key := range keys {
|
|
args[1+i] = key
|
|
}
|
|
args[len(args)-1] = formatSec(ctx, timeout)
|
|
cmd := NewZWithKeyCmd(ctx, args...)
|
|
cmd.setReadTimeout(timeout)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
// BZPopMin Redis `BZPOPMIN key [key ...] timeout` command.
|
|
func (c cmdable) BZPopMin(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd {
|
|
args := make([]interface{}, 1+len(keys)+1)
|
|
args[0] = "bzpopmin"
|
|
for i, key := range keys {
|
|
args[1+i] = key
|
|
}
|
|
args[len(args)-1] = formatSec(ctx, timeout)
|
|
cmd := NewZWithKeyCmd(ctx, args...)
|
|
cmd.setReadTimeout(timeout)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
// BZMPop is the blocking variant of ZMPOP.
|
|
// When any of the sorted sets contains elements, this command behaves exactly like ZMPOP.
|
|
// When all sorted sets are empty, Redis will block the connection until another client adds members to one of the keys or until the timeout elapses.
|
|
// A timeout of zero can be used to block indefinitely.
|
|
// example: client.BZMPop(ctx, 0,"max", 1, "set")
|
|
func (c cmdable) BZMPop(ctx context.Context, timeout time.Duration, order string, count int64, keys ...string) *ZSliceWithKeyCmd {
|
|
args := make([]interface{}, 3+len(keys), 6+len(keys))
|
|
args[0] = "bzmpop"
|
|
args[1] = formatSec(ctx, timeout)
|
|
args[2] = len(keys)
|
|
for i, key := range keys {
|
|
args[3+i] = key
|
|
}
|
|
args = append(args, strings.ToLower(order), "count", count)
|
|
cmd := NewZSliceWithKeyCmd(ctx, args...)
|
|
cmd.setReadTimeout(timeout)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
// ZAddArgs WARN: The GT, LT and NX options are mutually exclusive.
|
|
type ZAddArgs struct {
|
|
NX bool
|
|
XX bool
|
|
LT bool
|
|
GT bool
|
|
Ch bool
|
|
Members []Z
|
|
}
|
|
|
|
func (c cmdable) zAddArgs(key string, args ZAddArgs, incr bool) []interface{} {
|
|
a := make([]interface{}, 0, 6+2*len(args.Members))
|
|
a = append(a, "zadd", key)
|
|
|
|
// The GT, LT and NX options are mutually exclusive.
|
|
if args.NX {
|
|
a = append(a, "nx")
|
|
} else {
|
|
if args.XX {
|
|
a = append(a, "xx")
|
|
}
|
|
if args.GT {
|
|
a = append(a, "gt")
|
|
} else if args.LT {
|
|
a = append(a, "lt")
|
|
}
|
|
}
|
|
if args.Ch {
|
|
a = append(a, "ch")
|
|
}
|
|
if incr {
|
|
a = append(a, "incr")
|
|
}
|
|
for _, m := range args.Members {
|
|
a = append(a, m.Score)
|
|
a = append(a, m.Member)
|
|
}
|
|
return a
|
|
}
|
|
|
|
func (c cmdable) ZAddArgs(ctx context.Context, key string, args ZAddArgs) *IntCmd {
|
|
cmd := NewIntCmd(ctx, c.zAddArgs(key, args, false)...)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
func (c cmdable) ZAddArgsIncr(ctx context.Context, key string, args ZAddArgs) *FloatCmd {
|
|
cmd := NewFloatCmd(ctx, c.zAddArgs(key, args, true)...)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
// ZAdd Redis `ZADD key score member [score member ...]` command.
|
|
func (c cmdable) ZAdd(ctx context.Context, key string, members ...Z) *IntCmd {
|
|
return c.ZAddArgs(ctx, key, ZAddArgs{
|
|
Members: members,
|
|
})
|
|
}
|
|
|
|
// ZAddLT Redis `ZADD key LT score member [score member ...]` command.
|
|
func (c cmdable) ZAddLT(ctx context.Context, key string, members ...Z) *IntCmd {
|
|
return c.ZAddArgs(ctx, key, ZAddArgs{
|
|
LT: true,
|
|
Members: members,
|
|
})
|
|
}
|
|
|
|
// ZAddGT Redis `ZADD key GT score member [score member ...]` command.
|
|
func (c cmdable) ZAddGT(ctx context.Context, key string, members ...Z) *IntCmd {
|
|
return c.ZAddArgs(ctx, key, ZAddArgs{
|
|
GT: true,
|
|
Members: members,
|
|
})
|
|
}
|
|
|
|
// ZAddNX Redis `ZADD key NX score member [score member ...]` command.
|
|
func (c cmdable) ZAddNX(ctx context.Context, key string, members ...Z) *IntCmd {
|
|
return c.ZAddArgs(ctx, key, ZAddArgs{
|
|
NX: true,
|
|
Members: members,
|
|
})
|
|
}
|
|
|
|
// ZAddXX Redis `ZADD key XX score member [score member ...]` command.
|
|
func (c cmdable) ZAddXX(ctx context.Context, key string, members ...Z) *IntCmd {
|
|
return c.ZAddArgs(ctx, key, ZAddArgs{
|
|
XX: true,
|
|
Members: members,
|
|
})
|
|
}
|
|
|
|
func (c cmdable) ZCard(ctx context.Context, key string) *IntCmd {
|
|
cmd := NewIntCmd(ctx, "zcard", key)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
func (c cmdable) ZCount(ctx context.Context, key, min, max string) *IntCmd {
|
|
cmd := NewIntCmd(ctx, "zcount", key, min, max)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
func (c cmdable) ZLexCount(ctx context.Context, key, min, max string) *IntCmd {
|
|
cmd := NewIntCmd(ctx, "zlexcount", key, min, max)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
func (c cmdable) ZIncrBy(ctx context.Context, key string, increment float64, member string) *FloatCmd {
|
|
cmd := NewFloatCmd(ctx, "zincrby", key, increment, member)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
func (c cmdable) ZInterStore(ctx context.Context, destination string, store *ZStore) *IntCmd {
|
|
args := make([]interface{}, 0, 3+store.len())
|
|
args = append(args, "zinterstore", destination, len(store.Keys))
|
|
args = store.appendArgs(args)
|
|
cmd := NewIntCmd(ctx, args...)
|
|
cmd.SetFirstKeyPos(3)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
func (c cmdable) ZInter(ctx context.Context, store *ZStore) *StringSliceCmd {
|
|
args := make([]interface{}, 0, 2+store.len())
|
|
args = append(args, "zinter", len(store.Keys))
|
|
args = store.appendArgs(args)
|
|
cmd := NewStringSliceCmd(ctx, args...)
|
|
cmd.SetFirstKeyPos(2)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
func (c cmdable) ZInterWithScores(ctx context.Context, store *ZStore) *ZSliceCmd {
|
|
args := make([]interface{}, 0, 3+store.len())
|
|
args = append(args, "zinter", len(store.Keys))
|
|
args = store.appendArgs(args)
|
|
args = append(args, "withscores")
|
|
cmd := NewZSliceCmd(ctx, args...)
|
|
cmd.SetFirstKeyPos(2)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
func (c cmdable) ZInterCard(ctx context.Context, limit int64, keys ...string) *IntCmd {
|
|
args := make([]interface{}, 4+len(keys))
|
|
args[0] = "zintercard"
|
|
numkeys := int64(0)
|
|
for i, key := range keys {
|
|
args[2+i] = key
|
|
numkeys++
|
|
}
|
|
args[1] = numkeys
|
|
args[2+numkeys] = "limit"
|
|
args[3+numkeys] = limit
|
|
cmd := NewIntCmd(ctx, args...)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
// ZMPop Pops one or more elements with the highest or lowest score from the first non-empty sorted set key from the list of provided key names.
|
|
// direction: "max" (highest score) or "min" (lowest score), count: > 0
|
|
// example: client.ZMPop(ctx, "max", 5, "set1", "set2")
|
|
func (c cmdable) ZMPop(ctx context.Context, order string, count int64, keys ...string) *ZSliceWithKeyCmd {
|
|
args := make([]interface{}, 2+len(keys), 5+len(keys))
|
|
args[0] = "zmpop"
|
|
args[1] = len(keys)
|
|
for i, key := range keys {
|
|
args[2+i] = key
|
|
}
|
|
args = append(args, strings.ToLower(order), "count", count)
|
|
cmd := NewZSliceWithKeyCmd(ctx, args...)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
func (c cmdable) ZMScore(ctx context.Context, key string, members ...string) *FloatSliceCmd {
|
|
args := make([]interface{}, 2+len(members))
|
|
args[0] = "zmscore"
|
|
args[1] = key
|
|
for i, member := range members {
|
|
args[2+i] = member
|
|
}
|
|
cmd := NewFloatSliceCmd(ctx, args...)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
func (c cmdable) ZPopMax(ctx context.Context, key string, count ...int64) *ZSliceCmd {
|
|
args := []interface{}{
|
|
"zpopmax",
|
|
key,
|
|
}
|
|
|
|
switch len(count) {
|
|
case 0:
|
|
break
|
|
case 1:
|
|
args = append(args, count[0])
|
|
default:
|
|
panic("too many arguments")
|
|
}
|
|
|
|
cmd := NewZSliceCmd(ctx, args...)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
func (c cmdable) ZPopMin(ctx context.Context, key string, count ...int64) *ZSliceCmd {
|
|
args := []interface{}{
|
|
"zpopmin",
|
|
key,
|
|
}
|
|
|
|
switch len(count) {
|
|
case 0:
|
|
break
|
|
case 1:
|
|
args = append(args, count[0])
|
|
default:
|
|
panic("too many arguments")
|
|
}
|
|
|
|
cmd := NewZSliceCmd(ctx, args...)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
// ZRangeArgs is all the options of the ZRange command.
|
|
// In version> 6.2.0, you can replace the(cmd):
|
|
//
|
|
// ZREVRANGE,
|
|
// ZRANGEBYSCORE,
|
|
// ZREVRANGEBYSCORE,
|
|
// ZRANGEBYLEX,
|
|
// ZREVRANGEBYLEX.
|
|
//
|
|
// Please pay attention to your redis-server version.
|
|
//
|
|
// Rev, ByScore, ByLex and Offset+Count options require redis-server 6.2.0 and higher.
|
|
type ZRangeArgs struct {
|
|
Key string
|
|
|
|
// When the ByScore option is provided, the open interval(exclusive) can be set.
|
|
// By default, the score intervals specified by <Start> and <Stop> are closed (inclusive).
|
|
// It is similar to the deprecated(6.2.0+) ZRangeByScore command.
|
|
// For example:
|
|
// ZRangeArgs{
|
|
// Key: "example-key",
|
|
// Start: "(3",
|
|
// Stop: 8,
|
|
// ByScore: true,
|
|
// }
|
|
// cmd: "ZRange example-key (3 8 ByScore" (3 < score <= 8).
|
|
//
|
|
// For the ByLex option, it is similar to the deprecated(6.2.0+) ZRangeByLex command.
|
|
// You can set the <Start> and <Stop> options as follows:
|
|
// ZRangeArgs{
|
|
// Key: "example-key",
|
|
// Start: "[abc",
|
|
// Stop: "(def",
|
|
// ByLex: true,
|
|
// }
|
|
// cmd: "ZRange example-key [abc (def ByLex"
|
|
//
|
|
// For normal cases (ByScore==false && ByLex==false), <Start> and <Stop> should be set to the index range (int).
|
|
// You can read the documentation for more information: https://redis.io/commands/zrange
|
|
Start interface{}
|
|
Stop interface{}
|
|
|
|
// The ByScore and ByLex options are mutually exclusive.
|
|
ByScore bool
|
|
ByLex bool
|
|
|
|
Rev bool
|
|
|
|
// limit offset count.
|
|
Offset int64
|
|
Count int64
|
|
}
|
|
|
|
func (z ZRangeArgs) appendArgs(args []interface{}) []interface{} {
|
|
// For Rev+ByScore/ByLex, we need to adjust the position of <Start> and <Stop>.
|
|
if z.Rev && (z.ByScore || z.ByLex) {
|
|
args = append(args, z.Key, z.Stop, z.Start)
|
|
} else {
|
|
args = append(args, z.Key, z.Start, z.Stop)
|
|
}
|
|
|
|
if z.ByScore {
|
|
args = append(args, "byscore")
|
|
} else if z.ByLex {
|
|
args = append(args, "bylex")
|
|
}
|
|
if z.Rev {
|
|
args = append(args, "rev")
|
|
}
|
|
if z.Offset != 0 || z.Count != 0 {
|
|
args = append(args, "limit", z.Offset, z.Count)
|
|
}
|
|
return args
|
|
}
|
|
|
|
func (c cmdable) ZRangeArgs(ctx context.Context, z ZRangeArgs) *StringSliceCmd {
|
|
args := make([]interface{}, 0, 9)
|
|
args = append(args, "zrange")
|
|
args = z.appendArgs(args)
|
|
cmd := NewStringSliceCmd(ctx, args...)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
func (c cmdable) ZRangeArgsWithScores(ctx context.Context, z ZRangeArgs) *ZSliceCmd {
|
|
args := make([]interface{}, 0, 10)
|
|
args = append(args, "zrange")
|
|
args = z.appendArgs(args)
|
|
args = append(args, "withscores")
|
|
cmd := NewZSliceCmd(ctx, args...)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
func (c cmdable) ZRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd {
|
|
return c.ZRangeArgs(ctx, ZRangeArgs{
|
|
Key: key,
|
|
Start: start,
|
|
Stop: stop,
|
|
})
|
|
}
|
|
|
|
func (c cmdable) ZRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd {
|
|
return c.ZRangeArgsWithScores(ctx, ZRangeArgs{
|
|
Key: key,
|
|
Start: start,
|
|
Stop: stop,
|
|
})
|
|
}
|
|
|
|
type ZRangeBy struct {
|
|
Min, Max string
|
|
Offset, Count int64
|
|
}
|
|
|
|
func (c cmdable) zRangeBy(ctx context.Context, zcmd, key string, opt *ZRangeBy, withScores bool) *StringSliceCmd {
|
|
args := []interface{}{zcmd, key, opt.Min, opt.Max}
|
|
if withScores {
|
|
args = append(args, "withscores")
|
|
}
|
|
if opt.Offset != 0 || opt.Count != 0 {
|
|
args = append(
|
|
args,
|
|
"limit",
|
|
opt.Offset,
|
|
opt.Count,
|
|
)
|
|
}
|
|
cmd := NewStringSliceCmd(ctx, args...)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
func (c cmdable) ZRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd {
|
|
return c.zRangeBy(ctx, "zrangebyscore", key, opt, false)
|
|
}
|
|
|
|
func (c cmdable) ZRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd {
|
|
return c.zRangeBy(ctx, "zrangebylex", key, opt, false)
|
|
}
|
|
|
|
func (c cmdable) ZRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd {
|
|
args := []interface{}{"zrangebyscore", key, opt.Min, opt.Max, "withscores"}
|
|
if opt.Offset != 0 || opt.Count != 0 {
|
|
args = append(
|
|
args,
|
|
"limit",
|
|
opt.Offset,
|
|
opt.Count,
|
|
)
|
|
}
|
|
cmd := NewZSliceCmd(ctx, args...)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
func (c cmdable) ZRangeStore(ctx context.Context, dst string, z ZRangeArgs) *IntCmd {
|
|
args := make([]interface{}, 0, 10)
|
|
args = append(args, "zrangestore", dst)
|
|
args = z.appendArgs(args)
|
|
cmd := NewIntCmd(ctx, args...)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
func (c cmdable) ZRank(ctx context.Context, key, member string) *IntCmd {
|
|
cmd := NewIntCmd(ctx, "zrank", key, member)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
// ZRankWithScore according to the Redis documentation, if member does not exist
|
|
// in the sorted set or key does not exist, it will return a redis.Nil error.
|
|
func (c cmdable) ZRankWithScore(ctx context.Context, key, member string) *RankWithScoreCmd {
|
|
cmd := NewRankWithScoreCmd(ctx, "zrank", key, member, "withscore")
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
func (c cmdable) ZRem(ctx context.Context, key string, members ...interface{}) *IntCmd {
|
|
args := make([]interface{}, 2, 2+len(members))
|
|
args[0] = "zrem"
|
|
args[1] = key
|
|
args = appendArgs(args, members)
|
|
cmd := NewIntCmd(ctx, args...)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
func (c cmdable) ZRemRangeByRank(ctx context.Context, key string, start, stop int64) *IntCmd {
|
|
cmd := NewIntCmd(
|
|
ctx,
|
|
"zremrangebyrank",
|
|
key,
|
|
start,
|
|
stop,
|
|
)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
func (c cmdable) ZRemRangeByScore(ctx context.Context, key, min, max string) *IntCmd {
|
|
cmd := NewIntCmd(ctx, "zremrangebyscore", key, min, max)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
func (c cmdable) ZRemRangeByLex(ctx context.Context, key, min, max string) *IntCmd {
|
|
cmd := NewIntCmd(ctx, "zremrangebylex", key, min, max)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
func (c cmdable) ZRevRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd {
|
|
cmd := NewStringSliceCmd(ctx, "zrevrange", key, start, stop)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
// ZRevRangeWithScores according to the Redis documentation, if member does not exist
|
|
// in the sorted set or key does not exist, it will return a redis.Nil error.
|
|
func (c cmdable) ZRevRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd {
|
|
cmd := NewZSliceCmd(ctx, "zrevrange", key, start, stop, "withscores")
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
func (c cmdable) zRevRangeBy(ctx context.Context, zcmd, key string, opt *ZRangeBy) *StringSliceCmd {
|
|
args := []interface{}{zcmd, key, opt.Max, opt.Min}
|
|
if opt.Offset != 0 || opt.Count != 0 {
|
|
args = append(
|
|
args,
|
|
"limit",
|
|
opt.Offset,
|
|
opt.Count,
|
|
)
|
|
}
|
|
cmd := NewStringSliceCmd(ctx, args...)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
func (c cmdable) ZRevRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd {
|
|
return c.zRevRangeBy(ctx, "zrevrangebyscore", key, opt)
|
|
}
|
|
|
|
func (c cmdable) ZRevRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd {
|
|
return c.zRevRangeBy(ctx, "zrevrangebylex", key, opt)
|
|
}
|
|
|
|
func (c cmdable) ZRevRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd {
|
|
args := []interface{}{"zrevrangebyscore", key, opt.Max, opt.Min, "withscores"}
|
|
if opt.Offset != 0 || opt.Count != 0 {
|
|
args = append(
|
|
args,
|
|
"limit",
|
|
opt.Offset,
|
|
opt.Count,
|
|
)
|
|
}
|
|
cmd := NewZSliceCmd(ctx, args...)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
func (c cmdable) ZRevRank(ctx context.Context, key, member string) *IntCmd {
|
|
cmd := NewIntCmd(ctx, "zrevrank", key, member)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
func (c cmdable) ZRevRankWithScore(ctx context.Context, key, member string) *RankWithScoreCmd {
|
|
cmd := NewRankWithScoreCmd(ctx, "zrevrank", key, member, "withscore")
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
func (c cmdable) ZScore(ctx context.Context, key, member string) *FloatCmd {
|
|
cmd := NewFloatCmd(ctx, "zscore", key, member)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
func (c cmdable) ZUnion(ctx context.Context, store ZStore) *StringSliceCmd {
|
|
args := make([]interface{}, 0, 2+store.len())
|
|
args = append(args, "zunion", len(store.Keys))
|
|
args = store.appendArgs(args)
|
|
cmd := NewStringSliceCmd(ctx, args...)
|
|
cmd.SetFirstKeyPos(2)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
func (c cmdable) ZUnionWithScores(ctx context.Context, store ZStore) *ZSliceCmd {
|
|
args := make([]interface{}, 0, 3+store.len())
|
|
args = append(args, "zunion", len(store.Keys))
|
|
args = store.appendArgs(args)
|
|
args = append(args, "withscores")
|
|
cmd := NewZSliceCmd(ctx, args...)
|
|
cmd.SetFirstKeyPos(2)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
func (c cmdable) ZUnionStore(ctx context.Context, dest string, store *ZStore) *IntCmd {
|
|
args := make([]interface{}, 0, 3+store.len())
|
|
args = append(args, "zunionstore", dest, len(store.Keys))
|
|
args = store.appendArgs(args)
|
|
cmd := NewIntCmd(ctx, args...)
|
|
cmd.SetFirstKeyPos(3)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
// ZRandMember redis-server version >= 6.2.0.
|
|
func (c cmdable) ZRandMember(ctx context.Context, key string, count int) *StringSliceCmd {
|
|
cmd := NewStringSliceCmd(ctx, "zrandmember", key, count)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
// ZRandMemberWithScores redis-server version >= 6.2.0.
|
|
func (c cmdable) ZRandMemberWithScores(ctx context.Context, key string, count int) *ZSliceCmd {
|
|
cmd := NewZSliceCmd(ctx, "zrandmember", key, count, "withscores")
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
// ZDiff redis-server version >= 6.2.0.
|
|
func (c cmdable) ZDiff(ctx context.Context, keys ...string) *StringSliceCmd {
|
|
args := make([]interface{}, 2+len(keys))
|
|
args[0] = "zdiff"
|
|
args[1] = len(keys)
|
|
for i, key := range keys {
|
|
args[i+2] = key
|
|
}
|
|
|
|
cmd := NewStringSliceCmd(ctx, args...)
|
|
cmd.SetFirstKeyPos(2)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
// ZDiffWithScores redis-server version >= 6.2.0.
|
|
func (c cmdable) ZDiffWithScores(ctx context.Context, keys ...string) *ZSliceCmd {
|
|
args := make([]interface{}, 3+len(keys))
|
|
args[0] = "zdiff"
|
|
args[1] = len(keys)
|
|
for i, key := range keys {
|
|
args[i+2] = key
|
|
}
|
|
args[len(keys)+2] = "withscores"
|
|
|
|
cmd := NewZSliceCmd(ctx, args...)
|
|
cmd.SetFirstKeyPos(2)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
// ZDiffStore redis-server version >=6.2.0.
|
|
func (c cmdable) ZDiffStore(ctx context.Context, destination string, keys ...string) *IntCmd {
|
|
args := make([]interface{}, 0, 3+len(keys))
|
|
args = append(args, "zdiffstore", destination, len(keys))
|
|
for _, key := range keys {
|
|
args = append(args, key)
|
|
}
|
|
cmd := NewIntCmd(ctx, args...)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
func (c cmdable) ZScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd {
|
|
args := []interface{}{"zscan", key, cursor}
|
|
if match != "" {
|
|
args = append(args, "match", match)
|
|
}
|
|
if count > 0 {
|
|
args = append(args, "count", count)
|
|
}
|
|
cmd := NewScanCmd(ctx, c, args...)
|
|
_ = c(ctx, cmd)
|
|
return cmd
|
|
}
|
|
|
|
// Z represents sorted set member.
|
|
type Z struct {
|
|
Score float64
|
|
Member string
|
|
}
|
|
|
|
// ZWithKey represents sorted set member including the name of the key where it was popped.
|
|
type ZWithKey struct {
|
|
Z
|
|
Key string
|
|
}
|
|
|
|
// ZStore is used as an arg to ZInter/ZInterStore and ZUnion/ZUnionStore.
|
|
type ZStore struct {
|
|
Keys []string
|
|
Weights []float64
|
|
// Can be SUM, MIN or MAX.
|
|
Aggregate string
|
|
}
|
|
|
|
func (z ZStore) len() (n int) {
|
|
n = len(z.Keys)
|
|
if len(z.Weights) > 0 {
|
|
n += 1 + len(z.Weights)
|
|
}
|
|
if z.Aggregate != "" {
|
|
n += 2
|
|
}
|
|
return n
|
|
}
|
|
|
|
func (z ZStore) appendArgs(args []interface{}) []interface{} {
|
|
for _, key := range z.Keys {
|
|
args = append(args, key)
|
|
}
|
|
if len(z.Weights) > 0 {
|
|
args = append(args, "weights")
|
|
for _, weights := range z.Weights {
|
|
args = append(args, weights)
|
|
}
|
|
}
|
|
if z.Aggregate != "" {
|
|
args = append(args, "aggregate", z.Aggregate)
|
|
}
|
|
return args
|
|
}
|