...

Source file src/github.com/redis/go-redis/v9/sortedset_commands.go

Documentation: github.com/redis/go-redis/v9

     1  package redis
     2  
     3  import (
     4  	"context"
     5  	"strings"
     6  	"time"
     7  
     8  	"github.com/redis/go-redis/v9/internal/hashtag"
     9  )
    10  
    11  type SortedSetCmdable interface {
    12  	BZPopMax(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd
    13  	BZPopMin(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd
    14  	BZMPop(ctx context.Context, timeout time.Duration, order string, count int64, keys ...string) *ZSliceWithKeyCmd
    15  	ZAdd(ctx context.Context, key string, members ...Z) *IntCmd
    16  	ZAddLT(ctx context.Context, key string, members ...Z) *IntCmd
    17  	ZAddGT(ctx context.Context, key string, members ...Z) *IntCmd
    18  	ZAddNX(ctx context.Context, key string, members ...Z) *IntCmd
    19  	ZAddXX(ctx context.Context, key string, members ...Z) *IntCmd
    20  	ZAddArgs(ctx context.Context, key string, args ZAddArgs) *IntCmd
    21  	ZAddArgsIncr(ctx context.Context, key string, args ZAddArgs) *FloatCmd
    22  	ZCard(ctx context.Context, key string) *IntCmd
    23  	ZCount(ctx context.Context, key, min, max string) *IntCmd
    24  	ZLexCount(ctx context.Context, key, min, max string) *IntCmd
    25  	ZIncrBy(ctx context.Context, key string, increment float64, member string) *FloatCmd
    26  	ZInter(ctx context.Context, store *ZStore) *StringSliceCmd
    27  	ZInterWithScores(ctx context.Context, store *ZStore) *ZSliceCmd
    28  	ZInterCard(ctx context.Context, limit int64, keys ...string) *IntCmd
    29  	ZInterStore(ctx context.Context, destination string, store *ZStore) *IntCmd
    30  	ZMPop(ctx context.Context, order string, count int64, keys ...string) *ZSliceWithKeyCmd
    31  	ZMScore(ctx context.Context, key string, members ...string) *FloatSliceCmd
    32  	ZPopMax(ctx context.Context, key string, count ...int64) *ZSliceCmd
    33  	ZPopMin(ctx context.Context, key string, count ...int64) *ZSliceCmd
    34  	ZRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd
    35  	ZRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd
    36  	ZRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd
    37  	ZRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd
    38  	ZRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd
    39  	ZRangeArgs(ctx context.Context, z ZRangeArgs) *StringSliceCmd
    40  	ZRangeArgsWithScores(ctx context.Context, z ZRangeArgs) *ZSliceCmd
    41  	ZRangeStore(ctx context.Context, dst string, z ZRangeArgs) *IntCmd
    42  	ZRank(ctx context.Context, key, member string) *IntCmd
    43  	ZRankWithScore(ctx context.Context, key, member string) *RankWithScoreCmd
    44  	ZRem(ctx context.Context, key string, members ...interface{}) *IntCmd
    45  	ZRemRangeByRank(ctx context.Context, key string, start, stop int64) *IntCmd
    46  	ZRemRangeByScore(ctx context.Context, key, min, max string) *IntCmd
    47  	ZRemRangeByLex(ctx context.Context, key, min, max string) *IntCmd
    48  	ZRevRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd
    49  	ZRevRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd
    50  	ZRevRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd
    51  	ZRevRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd
    52  	ZRevRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd
    53  	ZRevRank(ctx context.Context, key, member string) *IntCmd
    54  	ZRevRankWithScore(ctx context.Context, key, member string) *RankWithScoreCmd
    55  	ZScore(ctx context.Context, key, member string) *FloatCmd
    56  	ZUnionStore(ctx context.Context, dest string, store *ZStore) *IntCmd
    57  	ZRandMember(ctx context.Context, key string, count int) *StringSliceCmd
    58  	ZRandMemberWithScores(ctx context.Context, key string, count int) *ZSliceCmd
    59  	ZUnion(ctx context.Context, store ZStore) *StringSliceCmd
    60  	ZUnionWithScores(ctx context.Context, store ZStore) *ZSliceCmd
    61  	ZDiff(ctx context.Context, keys ...string) *StringSliceCmd
    62  	ZDiffWithScores(ctx context.Context, keys ...string) *ZSliceCmd
    63  	ZDiffStore(ctx context.Context, destination string, keys ...string) *IntCmd
    64  	ZScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd
    65  }
    66  
    67  // BZPopMax Redis `BZPOPMAX key [key ...] timeout` command.
    68  func (c cmdable) BZPopMax(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd {
    69  	args := make([]interface{}, 1+len(keys)+1)
    70  	args[0] = "bzpopmax"
    71  	for i, key := range keys {
    72  		args[1+i] = key
    73  	}
    74  	args[len(args)-1] = formatSec(ctx, timeout)
    75  	cmd := NewZWithKeyCmd(ctx, args...)
    76  	cmd.setReadTimeout(timeout)
    77  	_ = c(ctx, cmd)
    78  	return cmd
    79  }
    80  
    81  // BZPopMin Redis `BZPOPMIN key [key ...] timeout` command.
    82  func (c cmdable) BZPopMin(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd {
    83  	args := make([]interface{}, 1+len(keys)+1)
    84  	args[0] = "bzpopmin"
    85  	for i, key := range keys {
    86  		args[1+i] = key
    87  	}
    88  	args[len(args)-1] = formatSec(ctx, timeout)
    89  	cmd := NewZWithKeyCmd(ctx, args...)
    90  	cmd.setReadTimeout(timeout)
    91  	_ = c(ctx, cmd)
    92  	return cmd
    93  }
    94  
    95  // BZMPop is the blocking variant of ZMPOP.
    96  // When any of the sorted sets contains elements, this command behaves exactly like ZMPOP.
    97  // 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.
    98  // A timeout of zero can be used to block indefinitely.
    99  // example: client.BZMPop(ctx, 0,"max", 1, "set")
   100  func (c cmdable) BZMPop(ctx context.Context, timeout time.Duration, order string, count int64, keys ...string) *ZSliceWithKeyCmd {
   101  	args := make([]interface{}, 3+len(keys), 6+len(keys))
   102  	args[0] = "bzmpop"
   103  	args[1] = formatSec(ctx, timeout)
   104  	args[2] = len(keys)
   105  	for i, key := range keys {
   106  		args[3+i] = key
   107  	}
   108  	args = append(args, strings.ToLower(order), "count", count)
   109  	cmd := NewZSliceWithKeyCmd(ctx, args...)
   110  	cmd.setReadTimeout(timeout)
   111  	_ = c(ctx, cmd)
   112  	return cmd
   113  }
   114  
   115  // ZAddArgs WARN: The GT, LT and NX options are mutually exclusive.
   116  type ZAddArgs struct {
   117  	NX      bool
   118  	XX      bool
   119  	LT      bool
   120  	GT      bool
   121  	Ch      bool
   122  	Members []Z
   123  }
   124  
   125  func (c cmdable) zAddArgs(key string, args ZAddArgs, incr bool) []interface{} {
   126  	a := make([]interface{}, 0, 6+2*len(args.Members))
   127  	a = append(a, "zadd", key)
   128  
   129  	// The GT, LT and NX options are mutually exclusive.
   130  	if args.NX {
   131  		a = append(a, "nx")
   132  	} else {
   133  		if args.XX {
   134  			a = append(a, "xx")
   135  		}
   136  		if args.GT {
   137  			a = append(a, "gt")
   138  		} else if args.LT {
   139  			a = append(a, "lt")
   140  		}
   141  	}
   142  	if args.Ch {
   143  		a = append(a, "ch")
   144  	}
   145  	if incr {
   146  		a = append(a, "incr")
   147  	}
   148  	for _, m := range args.Members {
   149  		a = append(a, m.Score)
   150  		a = append(a, m.Member)
   151  	}
   152  	return a
   153  }
   154  
   155  func (c cmdable) ZAddArgs(ctx context.Context, key string, args ZAddArgs) *IntCmd {
   156  	cmd := NewIntCmd(ctx, c.zAddArgs(key, args, false)...)
   157  	_ = c(ctx, cmd)
   158  	return cmd
   159  }
   160  
   161  func (c cmdable) ZAddArgsIncr(ctx context.Context, key string, args ZAddArgs) *FloatCmd {
   162  	cmd := NewFloatCmd(ctx, c.zAddArgs(key, args, true)...)
   163  	_ = c(ctx, cmd)
   164  	return cmd
   165  }
   166  
   167  // ZAdd Redis `ZADD key score member [score member ...]` command.
   168  func (c cmdable) ZAdd(ctx context.Context, key string, members ...Z) *IntCmd {
   169  	return c.ZAddArgs(ctx, key, ZAddArgs{
   170  		Members: members,
   171  	})
   172  }
   173  
   174  // ZAddLT Redis `ZADD key LT score member [score member ...]` command.
   175  func (c cmdable) ZAddLT(ctx context.Context, key string, members ...Z) *IntCmd {
   176  	return c.ZAddArgs(ctx, key, ZAddArgs{
   177  		LT:      true,
   178  		Members: members,
   179  	})
   180  }
   181  
   182  // ZAddGT Redis `ZADD key GT score member [score member ...]` command.
   183  func (c cmdable) ZAddGT(ctx context.Context, key string, members ...Z) *IntCmd {
   184  	return c.ZAddArgs(ctx, key, ZAddArgs{
   185  		GT:      true,
   186  		Members: members,
   187  	})
   188  }
   189  
   190  // ZAddNX Redis `ZADD key NX score member [score member ...]` command.
   191  func (c cmdable) ZAddNX(ctx context.Context, key string, members ...Z) *IntCmd {
   192  	return c.ZAddArgs(ctx, key, ZAddArgs{
   193  		NX:      true,
   194  		Members: members,
   195  	})
   196  }
   197  
   198  // ZAddXX Redis `ZADD key XX score member [score member ...]` command.
   199  func (c cmdable) ZAddXX(ctx context.Context, key string, members ...Z) *IntCmd {
   200  	return c.ZAddArgs(ctx, key, ZAddArgs{
   201  		XX:      true,
   202  		Members: members,
   203  	})
   204  }
   205  
   206  func (c cmdable) ZCard(ctx context.Context, key string) *IntCmd {
   207  	cmd := NewIntCmd(ctx, "zcard", key)
   208  	_ = c(ctx, cmd)
   209  	return cmd
   210  }
   211  
   212  func (c cmdable) ZCount(ctx context.Context, key, min, max string) *IntCmd {
   213  	cmd := NewIntCmd(ctx, "zcount", key, min, max)
   214  	_ = c(ctx, cmd)
   215  	return cmd
   216  }
   217  
   218  func (c cmdable) ZLexCount(ctx context.Context, key, min, max string) *IntCmd {
   219  	cmd := NewIntCmd(ctx, "zlexcount", key, min, max)
   220  	_ = c(ctx, cmd)
   221  	return cmd
   222  }
   223  
   224  func (c cmdable) ZIncrBy(ctx context.Context, key string, increment float64, member string) *FloatCmd {
   225  	cmd := NewFloatCmd(ctx, "zincrby", key, increment, member)
   226  	_ = c(ctx, cmd)
   227  	return cmd
   228  }
   229  
   230  func (c cmdable) ZInterStore(ctx context.Context, destination string, store *ZStore) *IntCmd {
   231  	args := make([]interface{}, 0, 3+store.len())
   232  	args = append(args, "zinterstore", destination, len(store.Keys))
   233  	args = store.appendArgs(args)
   234  	cmd := NewIntCmd(ctx, args...)
   235  	cmd.SetFirstKeyPos(3)
   236  	_ = c(ctx, cmd)
   237  	return cmd
   238  }
   239  
   240  func (c cmdable) ZInter(ctx context.Context, store *ZStore) *StringSliceCmd {
   241  	args := make([]interface{}, 0, 2+store.len())
   242  	args = append(args, "zinter", len(store.Keys))
   243  	args = store.appendArgs(args)
   244  	cmd := NewStringSliceCmd(ctx, args...)
   245  	cmd.SetFirstKeyPos(2)
   246  	_ = c(ctx, cmd)
   247  	return cmd
   248  }
   249  
   250  func (c cmdable) ZInterWithScores(ctx context.Context, store *ZStore) *ZSliceCmd {
   251  	args := make([]interface{}, 0, 3+store.len())
   252  	args = append(args, "zinter", len(store.Keys))
   253  	args = store.appendArgs(args)
   254  	args = append(args, "withscores")
   255  	cmd := NewZSliceCmd(ctx, args...)
   256  	cmd.SetFirstKeyPos(2)
   257  	_ = c(ctx, cmd)
   258  	return cmd
   259  }
   260  
   261  func (c cmdable) ZInterCard(ctx context.Context, limit int64, keys ...string) *IntCmd {
   262  	numKeys := len(keys)
   263  	args := make([]interface{}, 4+numKeys)
   264  	args[0] = "zintercard"
   265  	args[1] = numKeys
   266  	for i, key := range keys {
   267  		args[2+i] = key
   268  	}
   269  	args[2+numKeys] = "limit"
   270  	args[3+numKeys] = limit
   271  	cmd := NewIntCmd(ctx, args...)
   272  	_ = c(ctx, cmd)
   273  	return cmd
   274  }
   275  
   276  // 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.
   277  // direction: "max" (highest score) or "min" (lowest score), count: > 0
   278  // example: client.ZMPop(ctx, "max", 5, "set1", "set2")
   279  func (c cmdable) ZMPop(ctx context.Context, order string, count int64, keys ...string) *ZSliceWithKeyCmd {
   280  	args := make([]interface{}, 2+len(keys), 5+len(keys))
   281  	args[0] = "zmpop"
   282  	args[1] = len(keys)
   283  	for i, key := range keys {
   284  		args[2+i] = key
   285  	}
   286  	args = append(args, strings.ToLower(order), "count", count)
   287  	cmd := NewZSliceWithKeyCmd(ctx, args...)
   288  	_ = c(ctx, cmd)
   289  	return cmd
   290  }
   291  
   292  func (c cmdable) ZMScore(ctx context.Context, key string, members ...string) *FloatSliceCmd {
   293  	args := make([]interface{}, 2+len(members))
   294  	args[0] = "zmscore"
   295  	args[1] = key
   296  	for i, member := range members {
   297  		args[2+i] = member
   298  	}
   299  	cmd := NewFloatSliceCmd(ctx, args...)
   300  	_ = c(ctx, cmd)
   301  	return cmd
   302  }
   303  
   304  func (c cmdable) ZPopMax(ctx context.Context, key string, count ...int64) *ZSliceCmd {
   305  	args := []interface{}{
   306  		"zpopmax",
   307  		key,
   308  	}
   309  
   310  	switch len(count) {
   311  	case 0:
   312  		break
   313  	case 1:
   314  		args = append(args, count[0])
   315  	default:
   316  		panic("too many arguments")
   317  	}
   318  
   319  	cmd := NewZSliceCmd(ctx, args...)
   320  	_ = c(ctx, cmd)
   321  	return cmd
   322  }
   323  
   324  func (c cmdable) ZPopMin(ctx context.Context, key string, count ...int64) *ZSliceCmd {
   325  	args := []interface{}{
   326  		"zpopmin",
   327  		key,
   328  	}
   329  
   330  	switch len(count) {
   331  	case 0:
   332  		break
   333  	case 1:
   334  		args = append(args, count[0])
   335  	default:
   336  		panic("too many arguments")
   337  	}
   338  
   339  	cmd := NewZSliceCmd(ctx, args...)
   340  	_ = c(ctx, cmd)
   341  	return cmd
   342  }
   343  
   344  // ZRangeArgs is all the options of the ZRange command.
   345  // In version> 6.2.0, you can replace the(cmd):
   346  //
   347  //	ZREVRANGE,
   348  //	ZRANGEBYSCORE,
   349  //	ZREVRANGEBYSCORE,
   350  //	ZRANGEBYLEX,
   351  //	ZREVRANGEBYLEX.
   352  //
   353  // Please pay attention to your redis-server version.
   354  //
   355  // Rev, ByScore, ByLex and Offset+Count options require redis-server 6.2.0 and higher.
   356  type ZRangeArgs struct {
   357  	Key string
   358  
   359  	// When the ByScore option is provided, the open interval(exclusive) can be set.
   360  	// By default, the score intervals specified by <Start> and <Stop> are closed (inclusive).
   361  	// It is similar to the deprecated(6.2.0+) ZRangeByScore command.
   362  	// For example:
   363  	//		ZRangeArgs{
   364  	//			Key: 				"example-key",
   365  	//	 		Start: 				"(3",
   366  	//	 		Stop: 				8,
   367  	//			ByScore:			true,
   368  	//	 	}
   369  	// 	 	cmd: "ZRange example-key (3 8 ByScore"  (3 < score <= 8).
   370  	//
   371  	// For the ByLex option, it is similar to the deprecated(6.2.0+) ZRangeByLex command.
   372  	// You can set the <Start> and <Stop> options as follows:
   373  	//		ZRangeArgs{
   374  	//			Key: 				"example-key",
   375  	//	 		Start: 				"[abc",
   376  	//	 		Stop: 				"(def",
   377  	//			ByLex:				true,
   378  	//	 	}
   379  	//		cmd: "ZRange example-key [abc (def ByLex"
   380  	//
   381  	// For normal cases (ByScore==false && ByLex==false), <Start> and <Stop> should be set to the index range (int).
   382  	// You can read the documentation for more information: https://redis.io/commands/zrange
   383  	Start interface{}
   384  	Stop  interface{}
   385  
   386  	// The ByScore and ByLex options are mutually exclusive.
   387  	ByScore bool
   388  	ByLex   bool
   389  
   390  	Rev bool
   391  
   392  	// limit offset count.
   393  	Offset int64
   394  	Count  int64
   395  }
   396  
   397  func (z ZRangeArgs) appendArgs(args []interface{}) []interface{} {
   398  	// For Rev+ByScore/ByLex, we need to adjust the position of <Start> and <Stop>.
   399  	if z.Rev && (z.ByScore || z.ByLex) {
   400  		args = append(args, z.Key, z.Stop, z.Start)
   401  	} else {
   402  		args = append(args, z.Key, z.Start, z.Stop)
   403  	}
   404  
   405  	if z.ByScore {
   406  		args = append(args, "byscore")
   407  	} else if z.ByLex {
   408  		args = append(args, "bylex")
   409  	}
   410  	if z.Rev {
   411  		args = append(args, "rev")
   412  	}
   413  	if z.Offset != 0 || z.Count != 0 {
   414  		args = append(args, "limit", z.Offset, z.Count)
   415  	}
   416  	return args
   417  }
   418  
   419  func (c cmdable) ZRangeArgs(ctx context.Context, z ZRangeArgs) *StringSliceCmd {
   420  	args := make([]interface{}, 0, 9)
   421  	args = append(args, "zrange")
   422  	args = z.appendArgs(args)
   423  	cmd := NewStringSliceCmd(ctx, args...)
   424  	_ = c(ctx, cmd)
   425  	return cmd
   426  }
   427  
   428  func (c cmdable) ZRangeArgsWithScores(ctx context.Context, z ZRangeArgs) *ZSliceCmd {
   429  	args := make([]interface{}, 0, 10)
   430  	args = append(args, "zrange")
   431  	args = z.appendArgs(args)
   432  	args = append(args, "withscores")
   433  	cmd := NewZSliceCmd(ctx, args...)
   434  	_ = c(ctx, cmd)
   435  	return cmd
   436  }
   437  
   438  func (c cmdable) ZRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd {
   439  	return c.ZRangeArgs(ctx, ZRangeArgs{
   440  		Key:   key,
   441  		Start: start,
   442  		Stop:  stop,
   443  	})
   444  }
   445  
   446  func (c cmdable) ZRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd {
   447  	return c.ZRangeArgsWithScores(ctx, ZRangeArgs{
   448  		Key:   key,
   449  		Start: start,
   450  		Stop:  stop,
   451  	})
   452  }
   453  
   454  type ZRangeBy struct {
   455  	Min, Max      string
   456  	Offset, Count int64
   457  }
   458  
   459  func (c cmdable) zRangeBy(ctx context.Context, zcmd, key string, opt *ZRangeBy, withScores bool) *StringSliceCmd {
   460  	args := []interface{}{zcmd, key, opt.Min, opt.Max}
   461  	if withScores {
   462  		args = append(args, "withscores")
   463  	}
   464  	if opt.Offset != 0 || opt.Count != 0 {
   465  		args = append(
   466  			args,
   467  			"limit",
   468  			opt.Offset,
   469  			opt.Count,
   470  		)
   471  	}
   472  	cmd := NewStringSliceCmd(ctx, args...)
   473  	_ = c(ctx, cmd)
   474  	return cmd
   475  }
   476  
   477  func (c cmdable) ZRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd {
   478  	return c.zRangeBy(ctx, "zrangebyscore", key, opt, false)
   479  }
   480  
   481  func (c cmdable) ZRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd {
   482  	return c.zRangeBy(ctx, "zrangebylex", key, opt, false)
   483  }
   484  
   485  func (c cmdable) ZRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd {
   486  	args := []interface{}{"zrangebyscore", key, opt.Min, opt.Max, "withscores"}
   487  	if opt.Offset != 0 || opt.Count != 0 {
   488  		args = append(
   489  			args,
   490  			"limit",
   491  			opt.Offset,
   492  			opt.Count,
   493  		)
   494  	}
   495  	cmd := NewZSliceCmd(ctx, args...)
   496  	_ = c(ctx, cmd)
   497  	return cmd
   498  }
   499  
   500  func (c cmdable) ZRangeStore(ctx context.Context, dst string, z ZRangeArgs) *IntCmd {
   501  	args := make([]interface{}, 0, 10)
   502  	args = append(args, "zrangestore", dst)
   503  	args = z.appendArgs(args)
   504  	cmd := NewIntCmd(ctx, args...)
   505  	_ = c(ctx, cmd)
   506  	return cmd
   507  }
   508  
   509  func (c cmdable) ZRank(ctx context.Context, key, member string) *IntCmd {
   510  	cmd := NewIntCmd(ctx, "zrank", key, member)
   511  	_ = c(ctx, cmd)
   512  	return cmd
   513  }
   514  
   515  // ZRankWithScore according to the Redis documentation, if member does not exist
   516  // in the sorted set or key does not exist, it will return a redis.Nil error.
   517  func (c cmdable) ZRankWithScore(ctx context.Context, key, member string) *RankWithScoreCmd {
   518  	cmd := NewRankWithScoreCmd(ctx, "zrank", key, member, "withscore")
   519  	_ = c(ctx, cmd)
   520  	return cmd
   521  }
   522  
   523  func (c cmdable) ZRem(ctx context.Context, key string, members ...interface{}) *IntCmd {
   524  	args := make([]interface{}, 2, 2+len(members))
   525  	args[0] = "zrem"
   526  	args[1] = key
   527  	args = appendArgs(args, members)
   528  	cmd := NewIntCmd(ctx, args...)
   529  	_ = c(ctx, cmd)
   530  	return cmd
   531  }
   532  
   533  func (c cmdable) ZRemRangeByRank(ctx context.Context, key string, start, stop int64) *IntCmd {
   534  	cmd := NewIntCmd(
   535  		ctx,
   536  		"zremrangebyrank",
   537  		key,
   538  		start,
   539  		stop,
   540  	)
   541  	_ = c(ctx, cmd)
   542  	return cmd
   543  }
   544  
   545  func (c cmdable) ZRemRangeByScore(ctx context.Context, key, min, max string) *IntCmd {
   546  	cmd := NewIntCmd(ctx, "zremrangebyscore", key, min, max)
   547  	_ = c(ctx, cmd)
   548  	return cmd
   549  }
   550  
   551  func (c cmdable) ZRemRangeByLex(ctx context.Context, key, min, max string) *IntCmd {
   552  	cmd := NewIntCmd(ctx, "zremrangebylex", key, min, max)
   553  	_ = c(ctx, cmd)
   554  	return cmd
   555  }
   556  
   557  func (c cmdable) ZRevRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd {
   558  	cmd := NewStringSliceCmd(ctx, "zrevrange", key, start, stop)
   559  	_ = c(ctx, cmd)
   560  	return cmd
   561  }
   562  
   563  // ZRevRangeWithScores according to the Redis documentation, if member does not exist
   564  // in the sorted set or key does not exist, it will return a redis.Nil error.
   565  func (c cmdable) ZRevRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd {
   566  	cmd := NewZSliceCmd(ctx, "zrevrange", key, start, stop, "withscores")
   567  	_ = c(ctx, cmd)
   568  	return cmd
   569  }
   570  
   571  func (c cmdable) zRevRangeBy(ctx context.Context, zcmd, key string, opt *ZRangeBy) *StringSliceCmd {
   572  	args := []interface{}{zcmd, key, opt.Max, opt.Min}
   573  	if opt.Offset != 0 || opt.Count != 0 {
   574  		args = append(
   575  			args,
   576  			"limit",
   577  			opt.Offset,
   578  			opt.Count,
   579  		)
   580  	}
   581  	cmd := NewStringSliceCmd(ctx, args...)
   582  	_ = c(ctx, cmd)
   583  	return cmd
   584  }
   585  
   586  func (c cmdable) ZRevRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd {
   587  	return c.zRevRangeBy(ctx, "zrevrangebyscore", key, opt)
   588  }
   589  
   590  func (c cmdable) ZRevRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd {
   591  	return c.zRevRangeBy(ctx, "zrevrangebylex", key, opt)
   592  }
   593  
   594  func (c cmdable) ZRevRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd {
   595  	args := []interface{}{"zrevrangebyscore", key, opt.Max, opt.Min, "withscores"}
   596  	if opt.Offset != 0 || opt.Count != 0 {
   597  		args = append(
   598  			args,
   599  			"limit",
   600  			opt.Offset,
   601  			opt.Count,
   602  		)
   603  	}
   604  	cmd := NewZSliceCmd(ctx, args...)
   605  	_ = c(ctx, cmd)
   606  	return cmd
   607  }
   608  
   609  func (c cmdable) ZRevRank(ctx context.Context, key, member string) *IntCmd {
   610  	cmd := NewIntCmd(ctx, "zrevrank", key, member)
   611  	_ = c(ctx, cmd)
   612  	return cmd
   613  }
   614  
   615  func (c cmdable) ZRevRankWithScore(ctx context.Context, key, member string) *RankWithScoreCmd {
   616  	cmd := NewRankWithScoreCmd(ctx, "zrevrank", key, member, "withscore")
   617  	_ = c(ctx, cmd)
   618  	return cmd
   619  }
   620  
   621  func (c cmdable) ZScore(ctx context.Context, key, member string) *FloatCmd {
   622  	cmd := NewFloatCmd(ctx, "zscore", key, member)
   623  	_ = c(ctx, cmd)
   624  	return cmd
   625  }
   626  
   627  func (c cmdable) ZUnion(ctx context.Context, store ZStore) *StringSliceCmd {
   628  	args := make([]interface{}, 0, 2+store.len())
   629  	args = append(args, "zunion", len(store.Keys))
   630  	args = store.appendArgs(args)
   631  	cmd := NewStringSliceCmd(ctx, args...)
   632  	cmd.SetFirstKeyPos(2)
   633  	_ = c(ctx, cmd)
   634  	return cmd
   635  }
   636  
   637  func (c cmdable) ZUnionWithScores(ctx context.Context, store ZStore) *ZSliceCmd {
   638  	args := make([]interface{}, 0, 3+store.len())
   639  	args = append(args, "zunion", len(store.Keys))
   640  	args = store.appendArgs(args)
   641  	args = append(args, "withscores")
   642  	cmd := NewZSliceCmd(ctx, args...)
   643  	cmd.SetFirstKeyPos(2)
   644  	_ = c(ctx, cmd)
   645  	return cmd
   646  }
   647  
   648  func (c cmdable) ZUnionStore(ctx context.Context, dest string, store *ZStore) *IntCmd {
   649  	args := make([]interface{}, 0, 3+store.len())
   650  	args = append(args, "zunionstore", dest, len(store.Keys))
   651  	args = store.appendArgs(args)
   652  	cmd := NewIntCmd(ctx, args...)
   653  	cmd.SetFirstKeyPos(3)
   654  	_ = c(ctx, cmd)
   655  	return cmd
   656  }
   657  
   658  // ZRandMember redis-server version >= 6.2.0.
   659  func (c cmdable) ZRandMember(ctx context.Context, key string, count int) *StringSliceCmd {
   660  	cmd := NewStringSliceCmd(ctx, "zrandmember", key, count)
   661  	_ = c(ctx, cmd)
   662  	return cmd
   663  }
   664  
   665  // ZRandMemberWithScores redis-server version >= 6.2.0.
   666  func (c cmdable) ZRandMemberWithScores(ctx context.Context, key string, count int) *ZSliceCmd {
   667  	cmd := NewZSliceCmd(ctx, "zrandmember", key, count, "withscores")
   668  	_ = c(ctx, cmd)
   669  	return cmd
   670  }
   671  
   672  // ZDiff redis-server version >= 6.2.0.
   673  func (c cmdable) ZDiff(ctx context.Context, keys ...string) *StringSliceCmd {
   674  	args := make([]interface{}, 2+len(keys))
   675  	args[0] = "zdiff"
   676  	args[1] = len(keys)
   677  	for i, key := range keys {
   678  		args[i+2] = key
   679  	}
   680  
   681  	cmd := NewStringSliceCmd(ctx, args...)
   682  	cmd.SetFirstKeyPos(2)
   683  	_ = c(ctx, cmd)
   684  	return cmd
   685  }
   686  
   687  // ZDiffWithScores redis-server version >= 6.2.0.
   688  func (c cmdable) ZDiffWithScores(ctx context.Context, keys ...string) *ZSliceCmd {
   689  	args := make([]interface{}, 3+len(keys))
   690  	args[0] = "zdiff"
   691  	args[1] = len(keys)
   692  	for i, key := range keys {
   693  		args[i+2] = key
   694  	}
   695  	args[len(keys)+2] = "withscores"
   696  
   697  	cmd := NewZSliceCmd(ctx, args...)
   698  	cmd.SetFirstKeyPos(2)
   699  	_ = c(ctx, cmd)
   700  	return cmd
   701  }
   702  
   703  // ZDiffStore redis-server version >=6.2.0.
   704  func (c cmdable) ZDiffStore(ctx context.Context, destination string, keys ...string) *IntCmd {
   705  	args := make([]interface{}, 0, 3+len(keys))
   706  	args = append(args, "zdiffstore", destination, len(keys))
   707  	for _, key := range keys {
   708  		args = append(args, key)
   709  	}
   710  	cmd := NewIntCmd(ctx, args...)
   711  	_ = c(ctx, cmd)
   712  	return cmd
   713  }
   714  
   715  func (c cmdable) ZScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd {
   716  	args := []interface{}{"zscan", key, cursor}
   717  	if match != "" {
   718  		args = append(args, "match", match)
   719  	}
   720  	if count > 0 {
   721  		args = append(args, "count", count)
   722  	}
   723  	cmd := NewScanCmd(ctx, c, args...)
   724  	if hashtag.Present(match) {
   725  		cmd.SetFirstKeyPos(4)
   726  	}
   727  	_ = c(ctx, cmd)
   728  	return cmd
   729  }
   730  
   731  // Z represents sorted set member.
   732  type Z struct {
   733  	Score  float64
   734  	Member interface{}
   735  }
   736  
   737  // ZWithKey represents sorted set member including the name of the key where it was popped.
   738  type ZWithKey struct {
   739  	Z
   740  	Key string
   741  }
   742  
   743  // ZStore is used as an arg to ZInter/ZInterStore and ZUnion/ZUnionStore.
   744  type ZStore struct {
   745  	Keys    []string
   746  	Weights []float64
   747  	// Can be SUM, MIN or MAX.
   748  	Aggregate string
   749  }
   750  
   751  func (z ZStore) len() (n int) {
   752  	n = len(z.Keys)
   753  	if len(z.Weights) > 0 {
   754  		n += 1 + len(z.Weights)
   755  	}
   756  	if z.Aggregate != "" {
   757  		n += 2
   758  	}
   759  	return n
   760  }
   761  
   762  func (z ZStore) appendArgs(args []interface{}) []interface{} {
   763  	for _, key := range z.Keys {
   764  		args = append(args, key)
   765  	}
   766  	if len(z.Weights) > 0 {
   767  		args = append(args, "weights")
   768  		for _, weights := range z.Weights {
   769  			args = append(args, weights)
   770  		}
   771  	}
   772  	if z.Aggregate != "" {
   773  		args = append(args, "aggregate", z.Aggregate)
   774  	}
   775  	return args
   776  }
   777  

View as plain text