blob: 79698babf2824b8b91a5d60a74c7ac2c54868707 [file] [log] [blame]
Joey Armstronge8c091f2023-01-17 16:56:26 -05001package redis
2
3import (
4 "context"
5 "errors"
6 "io"
7 "time"
8
9 "github.com/go-redis/redis/v8/internal"
10)
11
12// KeepTTL is an option for Set command to keep key's existing TTL.
13// For example:
14//
15// rdb.Set(ctx, key, value, redis.KeepTTL)
16const KeepTTL = -1
17
18func usePrecise(dur time.Duration) bool {
19 return dur < time.Second || dur%time.Second != 0
20}
21
22func formatMs(ctx context.Context, dur time.Duration) int64 {
23 if dur > 0 && dur < time.Millisecond {
24 internal.Logger.Printf(
25 ctx,
26 "specified duration is %s, but minimal supported value is %s - truncating to 1ms",
27 dur, time.Millisecond,
28 )
29 return 1
30 }
31 return int64(dur / time.Millisecond)
32}
33
34func formatSec(ctx context.Context, dur time.Duration) int64 {
35 if dur > 0 && dur < time.Second {
36 internal.Logger.Printf(
37 ctx,
38 "specified duration is %s, but minimal supported value is %s - truncating to 1s",
39 dur, time.Second,
40 )
41 return 1
42 }
43 return int64(dur / time.Second)
44}
45
46func appendArgs(dst, src []interface{}) []interface{} {
47 if len(src) == 1 {
48 return appendArg(dst, src[0])
49 }
50
51 dst = append(dst, src...)
52 return dst
53}
54
55func appendArg(dst []interface{}, arg interface{}) []interface{} {
56 switch arg := arg.(type) {
57 case []string:
58 for _, s := range arg {
59 dst = append(dst, s)
60 }
61 return dst
62 case []interface{}:
63 dst = append(dst, arg...)
64 return dst
65 case map[string]interface{}:
66 for k, v := range arg {
67 dst = append(dst, k, v)
68 }
69 return dst
70 default:
71 return append(dst, arg)
72 }
73}
74
75type Cmdable interface {
76 Pipeline() Pipeliner
77 Pipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error)
78
79 TxPipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error)
80 TxPipeline() Pipeliner
81
82 Command(ctx context.Context) *CommandsInfoCmd
83 ClientGetName(ctx context.Context) *StringCmd
84 Echo(ctx context.Context, message interface{}) *StringCmd
85 Ping(ctx context.Context) *StatusCmd
86 Quit(ctx context.Context) *StatusCmd
87 Del(ctx context.Context, keys ...string) *IntCmd
88 Unlink(ctx context.Context, keys ...string) *IntCmd
89 Dump(ctx context.Context, key string) *StringCmd
90 Exists(ctx context.Context, keys ...string) *IntCmd
91 Expire(ctx context.Context, key string, expiration time.Duration) *BoolCmd
92 ExpireAt(ctx context.Context, key string, tm time.Time) *BoolCmd
93 Keys(ctx context.Context, pattern string) *StringSliceCmd
94 Migrate(ctx context.Context, host, port, key string, db int, timeout time.Duration) *StatusCmd
95 Move(ctx context.Context, key string, db int) *BoolCmd
96 ObjectRefCount(ctx context.Context, key string) *IntCmd
97 ObjectEncoding(ctx context.Context, key string) *StringCmd
98 ObjectIdleTime(ctx context.Context, key string) *DurationCmd
99 Persist(ctx context.Context, key string) *BoolCmd
100 PExpire(ctx context.Context, key string, expiration time.Duration) *BoolCmd
101 PExpireAt(ctx context.Context, key string, tm time.Time) *BoolCmd
102 PTTL(ctx context.Context, key string) *DurationCmd
103 RandomKey(ctx context.Context) *StringCmd
104 Rename(ctx context.Context, key, newkey string) *StatusCmd
105 RenameNX(ctx context.Context, key, newkey string) *BoolCmd
106 Restore(ctx context.Context, key string, ttl time.Duration, value string) *StatusCmd
107 RestoreReplace(ctx context.Context, key string, ttl time.Duration, value string) *StatusCmd
108 Sort(ctx context.Context, key string, sort *Sort) *StringSliceCmd
109 SortStore(ctx context.Context, key, store string, sort *Sort) *IntCmd
110 SortInterfaces(ctx context.Context, key string, sort *Sort) *SliceCmd
111 Touch(ctx context.Context, keys ...string) *IntCmd
112 TTL(ctx context.Context, key string) *DurationCmd
113 Type(ctx context.Context, key string) *StatusCmd
114 Append(ctx context.Context, key, value string) *IntCmd
115 Decr(ctx context.Context, key string) *IntCmd
116 DecrBy(ctx context.Context, key string, decrement int64) *IntCmd
117 Get(ctx context.Context, key string) *StringCmd
118 GetRange(ctx context.Context, key string, start, end int64) *StringCmd
119 GetSet(ctx context.Context, key string, value interface{}) *StringCmd
120 Incr(ctx context.Context, key string) *IntCmd
121 IncrBy(ctx context.Context, key string, value int64) *IntCmd
122 IncrByFloat(ctx context.Context, key string, value float64) *FloatCmd
123 MGet(ctx context.Context, keys ...string) *SliceCmd
124 MSet(ctx context.Context, values ...interface{}) *StatusCmd
125 MSetNX(ctx context.Context, values ...interface{}) *BoolCmd
126 Set(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd
127 SetEX(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd
128 SetNX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd
129 SetXX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd
130 SetRange(ctx context.Context, key string, offset int64, value string) *IntCmd
131 StrLen(ctx context.Context, key string) *IntCmd
132
133 GetBit(ctx context.Context, key string, offset int64) *IntCmd
134 SetBit(ctx context.Context, key string, offset int64, value int) *IntCmd
135 BitCount(ctx context.Context, key string, bitCount *BitCount) *IntCmd
136 BitOpAnd(ctx context.Context, destKey string, keys ...string) *IntCmd
137 BitOpOr(ctx context.Context, destKey string, keys ...string) *IntCmd
138 BitOpXor(ctx context.Context, destKey string, keys ...string) *IntCmd
139 BitOpNot(ctx context.Context, destKey string, key string) *IntCmd
140 BitPos(ctx context.Context, key string, bit int64, pos ...int64) *IntCmd
141 BitField(ctx context.Context, key string, args ...interface{}) *IntSliceCmd
142
143 Scan(ctx context.Context, cursor uint64, match string, count int64) *ScanCmd
144 SScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd
145 HScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd
146 ZScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd
147
148 HDel(ctx context.Context, key string, fields ...string) *IntCmd
149 HExists(ctx context.Context, key, field string) *BoolCmd
150 HGet(ctx context.Context, key, field string) *StringCmd
151 HGetAll(ctx context.Context, key string) *StringStringMapCmd
152 HIncrBy(ctx context.Context, key, field string, incr int64) *IntCmd
153 HIncrByFloat(ctx context.Context, key, field string, incr float64) *FloatCmd
154 HKeys(ctx context.Context, key string) *StringSliceCmd
155 HLen(ctx context.Context, key string) *IntCmd
156 HMGet(ctx context.Context, key string, fields ...string) *SliceCmd
157 HSet(ctx context.Context, key string, values ...interface{}) *IntCmd
158 HMSet(ctx context.Context, key string, values ...interface{}) *BoolCmd
159 HSetNX(ctx context.Context, key, field string, value interface{}) *BoolCmd
160 HVals(ctx context.Context, key string) *StringSliceCmd
161
162 BLPop(ctx context.Context, timeout time.Duration, keys ...string) *StringSliceCmd
163 BRPop(ctx context.Context, timeout time.Duration, keys ...string) *StringSliceCmd
164 BRPopLPush(ctx context.Context, source, destination string, timeout time.Duration) *StringCmd
165 LIndex(ctx context.Context, key string, index int64) *StringCmd
166 LInsert(ctx context.Context, key, op string, pivot, value interface{}) *IntCmd
167 LInsertBefore(ctx context.Context, key string, pivot, value interface{}) *IntCmd
168 LInsertAfter(ctx context.Context, key string, pivot, value interface{}) *IntCmd
169 LLen(ctx context.Context, key string) *IntCmd
170 LPop(ctx context.Context, key string) *StringCmd
171 LPos(ctx context.Context, key string, value string, args LPosArgs) *IntCmd
172 LPosCount(ctx context.Context, key string, value string, count int64, args LPosArgs) *IntSliceCmd
173 LPush(ctx context.Context, key string, values ...interface{}) *IntCmd
174 LPushX(ctx context.Context, key string, values ...interface{}) *IntCmd
175 LRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd
176 LRem(ctx context.Context, key string, count int64, value interface{}) *IntCmd
177 LSet(ctx context.Context, key string, index int64, value interface{}) *StatusCmd
178 LTrim(ctx context.Context, key string, start, stop int64) *StatusCmd
179 RPop(ctx context.Context, key string) *StringCmd
180 RPopLPush(ctx context.Context, source, destination string) *StringCmd
181 RPush(ctx context.Context, key string, values ...interface{}) *IntCmd
182 RPushX(ctx context.Context, key string, values ...interface{}) *IntCmd
183
184 SAdd(ctx context.Context, key string, members ...interface{}) *IntCmd
185 SCard(ctx context.Context, key string) *IntCmd
186 SDiff(ctx context.Context, keys ...string) *StringSliceCmd
187 SDiffStore(ctx context.Context, destination string, keys ...string) *IntCmd
188 SInter(ctx context.Context, keys ...string) *StringSliceCmd
189 SInterStore(ctx context.Context, destination string, keys ...string) *IntCmd
190 SIsMember(ctx context.Context, key string, member interface{}) *BoolCmd
191 SMembers(ctx context.Context, key string) *StringSliceCmd
192 SMembersMap(ctx context.Context, key string) *StringStructMapCmd
193 SMove(ctx context.Context, source, destination string, member interface{}) *BoolCmd
194 SPop(ctx context.Context, key string) *StringCmd
195 SPopN(ctx context.Context, key string, count int64) *StringSliceCmd
196 SRandMember(ctx context.Context, key string) *StringCmd
197 SRandMemberN(ctx context.Context, key string, count int64) *StringSliceCmd
198 SRem(ctx context.Context, key string, members ...interface{}) *IntCmd
199 SUnion(ctx context.Context, keys ...string) *StringSliceCmd
200 SUnionStore(ctx context.Context, destination string, keys ...string) *IntCmd
201
202 XAdd(ctx context.Context, a *XAddArgs) *StringCmd
203 XDel(ctx context.Context, stream string, ids ...string) *IntCmd
204 XLen(ctx context.Context, stream string) *IntCmd
205 XRange(ctx context.Context, stream, start, stop string) *XMessageSliceCmd
206 XRangeN(ctx context.Context, stream, start, stop string, count int64) *XMessageSliceCmd
207 XRevRange(ctx context.Context, stream string, start, stop string) *XMessageSliceCmd
208 XRevRangeN(ctx context.Context, stream string, start, stop string, count int64) *XMessageSliceCmd
209 XRead(ctx context.Context, a *XReadArgs) *XStreamSliceCmd
210 XReadStreams(ctx context.Context, streams ...string) *XStreamSliceCmd
211 XGroupCreate(ctx context.Context, stream, group, start string) *StatusCmd
212 XGroupCreateMkStream(ctx context.Context, stream, group, start string) *StatusCmd
213 XGroupSetID(ctx context.Context, stream, group, start string) *StatusCmd
214 XGroupDestroy(ctx context.Context, stream, group string) *IntCmd
215 XGroupDelConsumer(ctx context.Context, stream, group, consumer string) *IntCmd
216 XReadGroup(ctx context.Context, a *XReadGroupArgs) *XStreamSliceCmd
217 XAck(ctx context.Context, stream, group string, ids ...string) *IntCmd
218 XPending(ctx context.Context, stream, group string) *XPendingCmd
219 XPendingExt(ctx context.Context, a *XPendingExtArgs) *XPendingExtCmd
220 XClaim(ctx context.Context, a *XClaimArgs) *XMessageSliceCmd
221 XClaimJustID(ctx context.Context, a *XClaimArgs) *StringSliceCmd
222 XTrim(ctx context.Context, key string, maxLen int64) *IntCmd
223 XTrimApprox(ctx context.Context, key string, maxLen int64) *IntCmd
224 XInfoGroups(ctx context.Context, key string) *XInfoGroupsCmd
225 XInfoStream(ctx context.Context, key string) *XInfoStreamCmd
226
227 BZPopMax(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd
228 BZPopMin(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd
229 ZAdd(ctx context.Context, key string, members ...*Z) *IntCmd
230 ZAddNX(ctx context.Context, key string, members ...*Z) *IntCmd
231 ZAddXX(ctx context.Context, key string, members ...*Z) *IntCmd
232 ZAddCh(ctx context.Context, key string, members ...*Z) *IntCmd
233 ZAddNXCh(ctx context.Context, key string, members ...*Z) *IntCmd
234 ZAddXXCh(ctx context.Context, key string, members ...*Z) *IntCmd
235 ZIncr(ctx context.Context, key string, member *Z) *FloatCmd
236 ZIncrNX(ctx context.Context, key string, member *Z) *FloatCmd
237 ZIncrXX(ctx context.Context, key string, member *Z) *FloatCmd
238 ZCard(ctx context.Context, key string) *IntCmd
239 ZCount(ctx context.Context, key, min, max string) *IntCmd
240 ZLexCount(ctx context.Context, key, min, max string) *IntCmd
241 ZIncrBy(ctx context.Context, key string, increment float64, member string) *FloatCmd
242 ZInterStore(ctx context.Context, destination string, store *ZStore) *IntCmd
243 ZPopMax(ctx context.Context, key string, count ...int64) *ZSliceCmd
244 ZPopMin(ctx context.Context, key string, count ...int64) *ZSliceCmd
245 ZRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd
246 ZRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd
247 ZRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd
248 ZRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd
249 ZRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd
250 ZRank(ctx context.Context, key, member string) *IntCmd
251 ZRem(ctx context.Context, key string, members ...interface{}) *IntCmd
252 ZRemRangeByRank(ctx context.Context, key string, start, stop int64) *IntCmd
253 ZRemRangeByScore(ctx context.Context, key, min, max string) *IntCmd
254 ZRemRangeByLex(ctx context.Context, key, min, max string) *IntCmd
255 ZRevRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd
256 ZRevRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd
257 ZRevRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd
258 ZRevRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd
259 ZRevRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd
260 ZRevRank(ctx context.Context, key, member string) *IntCmd
261 ZScore(ctx context.Context, key, member string) *FloatCmd
262 ZUnionStore(ctx context.Context, dest string, store *ZStore) *IntCmd
263
264 PFAdd(ctx context.Context, key string, els ...interface{}) *IntCmd
265 PFCount(ctx context.Context, keys ...string) *IntCmd
266 PFMerge(ctx context.Context, dest string, keys ...string) *StatusCmd
267
268 BgRewriteAOF(ctx context.Context) *StatusCmd
269 BgSave(ctx context.Context) *StatusCmd
270 ClientKill(ctx context.Context, ipPort string) *StatusCmd
271 ClientKillByFilter(ctx context.Context, keys ...string) *IntCmd
272 ClientList(ctx context.Context) *StringCmd
273 ClientPause(ctx context.Context, dur time.Duration) *BoolCmd
274 ClientID(ctx context.Context) *IntCmd
275 ConfigGet(ctx context.Context, parameter string) *SliceCmd
276 ConfigResetStat(ctx context.Context) *StatusCmd
277 ConfigSet(ctx context.Context, parameter, value string) *StatusCmd
278 ConfigRewrite(ctx context.Context) *StatusCmd
279 DBSize(ctx context.Context) *IntCmd
280 FlushAll(ctx context.Context) *StatusCmd
281 FlushAllAsync(ctx context.Context) *StatusCmd
282 FlushDB(ctx context.Context) *StatusCmd
283 FlushDBAsync(ctx context.Context) *StatusCmd
284 Info(ctx context.Context, section ...string) *StringCmd
285 LastSave(ctx context.Context) *IntCmd
286 Save(ctx context.Context) *StatusCmd
287 Shutdown(ctx context.Context) *StatusCmd
288 ShutdownSave(ctx context.Context) *StatusCmd
289 ShutdownNoSave(ctx context.Context) *StatusCmd
290 SlaveOf(ctx context.Context, host, port string) *StatusCmd
291 Time(ctx context.Context) *TimeCmd
292 DebugObject(ctx context.Context, key string) *StringCmd
293 ReadOnly(ctx context.Context) *StatusCmd
294 ReadWrite(ctx context.Context) *StatusCmd
295 MemoryUsage(ctx context.Context, key string, samples ...int) *IntCmd
296
297 Eval(ctx context.Context, script string, keys []string, args ...interface{}) *Cmd
298 EvalSha(ctx context.Context, sha1 string, keys []string, args ...interface{}) *Cmd
299 ScriptExists(ctx context.Context, hashes ...string) *BoolSliceCmd
300 ScriptFlush(ctx context.Context) *StatusCmd
301 ScriptKill(ctx context.Context) *StatusCmd
302 ScriptLoad(ctx context.Context, script string) *StringCmd
303
304 Publish(ctx context.Context, channel string, message interface{}) *IntCmd
305 PubSubChannels(ctx context.Context, pattern string) *StringSliceCmd
306 PubSubNumSub(ctx context.Context, channels ...string) *StringIntMapCmd
307 PubSubNumPat(ctx context.Context) *IntCmd
308
309 ClusterSlots(ctx context.Context) *ClusterSlotsCmd
310 ClusterNodes(ctx context.Context) *StringCmd
311 ClusterMeet(ctx context.Context, host, port string) *StatusCmd
312 ClusterForget(ctx context.Context, nodeID string) *StatusCmd
313 ClusterReplicate(ctx context.Context, nodeID string) *StatusCmd
314 ClusterResetSoft(ctx context.Context) *StatusCmd
315 ClusterResetHard(ctx context.Context) *StatusCmd
316 ClusterInfo(ctx context.Context) *StringCmd
317 ClusterKeySlot(ctx context.Context, key string) *IntCmd
318 ClusterGetKeysInSlot(ctx context.Context, slot int, count int) *StringSliceCmd
319 ClusterCountFailureReports(ctx context.Context, nodeID string) *IntCmd
320 ClusterCountKeysInSlot(ctx context.Context, slot int) *IntCmd
321 ClusterDelSlots(ctx context.Context, slots ...int) *StatusCmd
322 ClusterDelSlotsRange(ctx context.Context, min, max int) *StatusCmd
323 ClusterSaveConfig(ctx context.Context) *StatusCmd
324 ClusterSlaves(ctx context.Context, nodeID string) *StringSliceCmd
325 ClusterFailover(ctx context.Context) *StatusCmd
326 ClusterAddSlots(ctx context.Context, slots ...int) *StatusCmd
327 ClusterAddSlotsRange(ctx context.Context, min, max int) *StatusCmd
328
329 GeoAdd(ctx context.Context, key string, geoLocation ...*GeoLocation) *IntCmd
330 GeoPos(ctx context.Context, key string, members ...string) *GeoPosCmd
331 GeoRadius(ctx context.Context, key string, longitude, latitude float64, query *GeoRadiusQuery) *GeoLocationCmd
332 GeoRadiusStore(ctx context.Context, key string, longitude, latitude float64, query *GeoRadiusQuery) *IntCmd
333 GeoRadiusByMember(ctx context.Context, key, member string, query *GeoRadiusQuery) *GeoLocationCmd
334 GeoRadiusByMemberStore(ctx context.Context, key, member string, query *GeoRadiusQuery) *IntCmd
335 GeoDist(ctx context.Context, key string, member1, member2, unit string) *FloatCmd
336 GeoHash(ctx context.Context, key string, members ...string) *StringSliceCmd
337}
338
339type StatefulCmdable interface {
340 Cmdable
341 Auth(ctx context.Context, password string) *StatusCmd
342 AuthACL(ctx context.Context, username, password string) *StatusCmd
343 Select(ctx context.Context, index int) *StatusCmd
344 SwapDB(ctx context.Context, index1, index2 int) *StatusCmd
345 ClientSetName(ctx context.Context, name string) *BoolCmd
346}
347
348var (
349 _ Cmdable = (*Client)(nil)
350 _ Cmdable = (*Tx)(nil)
351 _ Cmdable = (*Ring)(nil)
352 _ Cmdable = (*ClusterClient)(nil)
353)
354
355type cmdable func(ctx context.Context, cmd Cmder) error
356
357type statefulCmdable func(ctx context.Context, cmd Cmder) error
358
359//------------------------------------------------------------------------------
360
361func (c statefulCmdable) Auth(ctx context.Context, password string) *StatusCmd {
362 cmd := NewStatusCmd(ctx, "auth", password)
363 _ = c(ctx, cmd)
364 return cmd
365}
366
367// Perform an AUTH command, using the given user and pass.
368// Should be used to authenticate the current connection with one of the connections defined in the ACL list
369// when connecting to a Redis 6.0 instance, or greater, that is using the Redis ACL system.
370func (c statefulCmdable) AuthACL(ctx context.Context, username, password string) *StatusCmd {
371 cmd := NewStatusCmd(ctx, "auth", username, password)
372 _ = c(ctx, cmd)
373 return cmd
374}
375
376func (c cmdable) Wait(ctx context.Context, numSlaves int, timeout time.Duration) *IntCmd {
377 cmd := NewIntCmd(ctx, "wait", numSlaves, int(timeout/time.Millisecond))
378 _ = c(ctx, cmd)
379 return cmd
380}
381
382func (c statefulCmdable) Select(ctx context.Context, index int) *StatusCmd {
383 cmd := NewStatusCmd(ctx, "select", index)
384 _ = c(ctx, cmd)
385 return cmd
386}
387
388func (c statefulCmdable) SwapDB(ctx context.Context, index1, index2 int) *StatusCmd {
389 cmd := NewStatusCmd(ctx, "swapdb", index1, index2)
390 _ = c(ctx, cmd)
391 return cmd
392}
393
394// ClientSetName assigns a name to the connection.
395func (c statefulCmdable) ClientSetName(ctx context.Context, name string) *BoolCmd {
396 cmd := NewBoolCmd(ctx, "client", "setname", name)
397 _ = c(ctx, cmd)
398 return cmd
399}
400
401//------------------------------------------------------------------------------
402
403func (c cmdable) Command(ctx context.Context) *CommandsInfoCmd {
404 cmd := NewCommandsInfoCmd(ctx, "command")
405 _ = c(ctx, cmd)
406 return cmd
407}
408
409// ClientGetName returns the name of the connection.
410func (c cmdable) ClientGetName(ctx context.Context) *StringCmd {
411 cmd := NewStringCmd(ctx, "client", "getname")
412 _ = c(ctx, cmd)
413 return cmd
414}
415
416func (c cmdable) Echo(ctx context.Context, message interface{}) *StringCmd {
417 cmd := NewStringCmd(ctx, "echo", message)
418 _ = c(ctx, cmd)
419 return cmd
420}
421
422func (c cmdable) Ping(ctx context.Context) *StatusCmd {
423 cmd := NewStatusCmd(ctx, "ping")
424 _ = c(ctx, cmd)
425 return cmd
426}
427
428func (c cmdable) Quit(ctx context.Context) *StatusCmd {
429 panic("not implemented")
430}
431
432func (c cmdable) Del(ctx context.Context, keys ...string) *IntCmd {
433 args := make([]interface{}, 1+len(keys))
434 args[0] = "del"
435 for i, key := range keys {
436 args[1+i] = key
437 }
438 cmd := NewIntCmd(ctx, args...)
439 _ = c(ctx, cmd)
440 return cmd
441}
442
443func (c cmdable) Unlink(ctx context.Context, keys ...string) *IntCmd {
444 args := make([]interface{}, 1+len(keys))
445 args[0] = "unlink"
446 for i, key := range keys {
447 args[1+i] = key
448 }
449 cmd := NewIntCmd(ctx, args...)
450 _ = c(ctx, cmd)
451 return cmd
452}
453
454func (c cmdable) Dump(ctx context.Context, key string) *StringCmd {
455 cmd := NewStringCmd(ctx, "dump", key)
456 _ = c(ctx, cmd)
457 return cmd
458}
459
460func (c cmdable) Exists(ctx context.Context, keys ...string) *IntCmd {
461 args := make([]interface{}, 1+len(keys))
462 args[0] = "exists"
463 for i, key := range keys {
464 args[1+i] = key
465 }
466 cmd := NewIntCmd(ctx, args...)
467 _ = c(ctx, cmd)
468 return cmd
469}
470
471func (c cmdable) Expire(ctx context.Context, key string, expiration time.Duration) *BoolCmd {
472 cmd := NewBoolCmd(ctx, "expire", key, formatSec(ctx, expiration))
473 _ = c(ctx, cmd)
474 return cmd
475}
476
477func (c cmdable) ExpireAt(ctx context.Context, key string, tm time.Time) *BoolCmd {
478 cmd := NewBoolCmd(ctx, "expireat", key, tm.Unix())
479 _ = c(ctx, cmd)
480 return cmd
481}
482
483func (c cmdable) Keys(ctx context.Context, pattern string) *StringSliceCmd {
484 cmd := NewStringSliceCmd(ctx, "keys", pattern)
485 _ = c(ctx, cmd)
486 return cmd
487}
488
489func (c cmdable) Migrate(ctx context.Context, host, port, key string, db int, timeout time.Duration) *StatusCmd {
490 cmd := NewStatusCmd(
491 ctx,
492 "migrate",
493 host,
494 port,
495 key,
496 db,
497 formatMs(ctx, timeout),
498 )
499 cmd.setReadTimeout(timeout)
500 _ = c(ctx, cmd)
501 return cmd
502}
503
504func (c cmdable) Move(ctx context.Context, key string, db int) *BoolCmd {
505 cmd := NewBoolCmd(ctx, "move", key, db)
506 _ = c(ctx, cmd)
507 return cmd
508}
509
510func (c cmdable) ObjectRefCount(ctx context.Context, key string) *IntCmd {
511 cmd := NewIntCmd(ctx, "object", "refcount", key)
512 _ = c(ctx, cmd)
513 return cmd
514}
515
516func (c cmdable) ObjectEncoding(ctx context.Context, key string) *StringCmd {
517 cmd := NewStringCmd(ctx, "object", "encoding", key)
518 _ = c(ctx, cmd)
519 return cmd
520}
521
522func (c cmdable) ObjectIdleTime(ctx context.Context, key string) *DurationCmd {
523 cmd := NewDurationCmd(ctx, time.Second, "object", "idletime", key)
524 _ = c(ctx, cmd)
525 return cmd
526}
527
528func (c cmdable) Persist(ctx context.Context, key string) *BoolCmd {
529 cmd := NewBoolCmd(ctx, "persist", key)
530 _ = c(ctx, cmd)
531 return cmd
532}
533
534func (c cmdable) PExpire(ctx context.Context, key string, expiration time.Duration) *BoolCmd {
535 cmd := NewBoolCmd(ctx, "pexpire", key, formatMs(ctx, expiration))
536 _ = c(ctx, cmd)
537 return cmd
538}
539
540func (c cmdable) PExpireAt(ctx context.Context, key string, tm time.Time) *BoolCmd {
541 cmd := NewBoolCmd(
542 ctx,
543 "pexpireat",
544 key,
545 tm.UnixNano()/int64(time.Millisecond),
546 )
547 _ = c(ctx, cmd)
548 return cmd
549}
550
551func (c cmdable) PTTL(ctx context.Context, key string) *DurationCmd {
552 cmd := NewDurationCmd(ctx, time.Millisecond, "pttl", key)
553 _ = c(ctx, cmd)
554 return cmd
555}
556
557func (c cmdable) RandomKey(ctx context.Context) *StringCmd {
558 cmd := NewStringCmd(ctx, "randomkey")
559 _ = c(ctx, cmd)
560 return cmd
561}
562
563func (c cmdable) Rename(ctx context.Context, key, newkey string) *StatusCmd {
564 cmd := NewStatusCmd(ctx, "rename", key, newkey)
565 _ = c(ctx, cmd)
566 return cmd
567}
568
569func (c cmdable) RenameNX(ctx context.Context, key, newkey string) *BoolCmd {
570 cmd := NewBoolCmd(ctx, "renamenx", key, newkey)
571 _ = c(ctx, cmd)
572 return cmd
573}
574
575func (c cmdable) Restore(ctx context.Context, key string, ttl time.Duration, value string) *StatusCmd {
576 cmd := NewStatusCmd(
577 ctx,
578 "restore",
579 key,
580 formatMs(ctx, ttl),
581 value,
582 )
583 _ = c(ctx, cmd)
584 return cmd
585}
586
587func (c cmdable) RestoreReplace(ctx context.Context, key string, ttl time.Duration, value string) *StatusCmd {
588 cmd := NewStatusCmd(
589 ctx,
590 "restore",
591 key,
592 formatMs(ctx, ttl),
593 value,
594 "replace",
595 )
596 _ = c(ctx, cmd)
597 return cmd
598}
599
600type Sort struct {
601 By string
602 Offset, Count int64
603 Get []string
604 Order string
605 Alpha bool
606}
607
608func (sort *Sort) args(key string) []interface{} {
609 args := []interface{}{"sort", key}
610 if sort.By != "" {
611 args = append(args, "by", sort.By)
612 }
613 if sort.Offset != 0 || sort.Count != 0 {
614 args = append(args, "limit", sort.Offset, sort.Count)
615 }
616 for _, get := range sort.Get {
617 args = append(args, "get", get)
618 }
619 if sort.Order != "" {
620 args = append(args, sort.Order)
621 }
622 if sort.Alpha {
623 args = append(args, "alpha")
624 }
625 return args
626}
627
628func (c cmdable) Sort(ctx context.Context, key string, sort *Sort) *StringSliceCmd {
629 cmd := NewStringSliceCmd(ctx, sort.args(key)...)
630 _ = c(ctx, cmd)
631 return cmd
632}
633
634func (c cmdable) SortStore(ctx context.Context, key, store string, sort *Sort) *IntCmd {
635 args := sort.args(key)
636 if store != "" {
637 args = append(args, "store", store)
638 }
639 cmd := NewIntCmd(ctx, args...)
640 _ = c(ctx, cmd)
641 return cmd
642}
643
644func (c cmdable) SortInterfaces(ctx context.Context, key string, sort *Sort) *SliceCmd {
645 cmd := NewSliceCmd(ctx, sort.args(key)...)
646 _ = c(ctx, cmd)
647 return cmd
648}
649
650func (c cmdable) Touch(ctx context.Context, keys ...string) *IntCmd {
651 args := make([]interface{}, len(keys)+1)
652 args[0] = "touch"
653 for i, key := range keys {
654 args[i+1] = key
655 }
656 cmd := NewIntCmd(ctx, args...)
657 _ = c(ctx, cmd)
658 return cmd
659}
660
661func (c cmdable) TTL(ctx context.Context, key string) *DurationCmd {
662 cmd := NewDurationCmd(ctx, time.Second, "ttl", key)
663 _ = c(ctx, cmd)
664 return cmd
665}
666
667func (c cmdable) Type(ctx context.Context, key string) *StatusCmd {
668 cmd := NewStatusCmd(ctx, "type", key)
669 _ = c(ctx, cmd)
670 return cmd
671}
672
673func (c cmdable) Append(ctx context.Context, key, value string) *IntCmd {
674 cmd := NewIntCmd(ctx, "append", key, value)
675 _ = c(ctx, cmd)
676 return cmd
677}
678
679func (c cmdable) Decr(ctx context.Context, key string) *IntCmd {
680 cmd := NewIntCmd(ctx, "decr", key)
681 _ = c(ctx, cmd)
682 return cmd
683}
684
685func (c cmdable) DecrBy(ctx context.Context, key string, decrement int64) *IntCmd {
686 cmd := NewIntCmd(ctx, "decrby", key, decrement)
687 _ = c(ctx, cmd)
688 return cmd
689}
690
691// Redis `GET key` command. It returns redis.Nil error when key does not exist.
692func (c cmdable) Get(ctx context.Context, key string) *StringCmd {
693 cmd := NewStringCmd(ctx, "get", key)
694 _ = c(ctx, cmd)
695 return cmd
696}
697
698func (c cmdable) GetRange(ctx context.Context, key string, start, end int64) *StringCmd {
699 cmd := NewStringCmd(ctx, "getrange", key, start, end)
700 _ = c(ctx, cmd)
701 return cmd
702}
703
704func (c cmdable) GetSet(ctx context.Context, key string, value interface{}) *StringCmd {
705 cmd := NewStringCmd(ctx, "getset", key, value)
706 _ = c(ctx, cmd)
707 return cmd
708}
709
710func (c cmdable) Incr(ctx context.Context, key string) *IntCmd {
711 cmd := NewIntCmd(ctx, "incr", key)
712 _ = c(ctx, cmd)
713 return cmd
714}
715
716func (c cmdable) IncrBy(ctx context.Context, key string, value int64) *IntCmd {
717 cmd := NewIntCmd(ctx, "incrby", key, value)
718 _ = c(ctx, cmd)
719 return cmd
720}
721
722func (c cmdable) IncrByFloat(ctx context.Context, key string, value float64) *FloatCmd {
723 cmd := NewFloatCmd(ctx, "incrbyfloat", key, value)
724 _ = c(ctx, cmd)
725 return cmd
726}
727
728func (c cmdable) MGet(ctx context.Context, keys ...string) *SliceCmd {
729 args := make([]interface{}, 1+len(keys))
730 args[0] = "mget"
731 for i, key := range keys {
732 args[1+i] = key
733 }
734 cmd := NewSliceCmd(ctx, args...)
735 _ = c(ctx, cmd)
736 return cmd
737}
738
739// MSet is like Set but accepts multiple values:
740// - MSet("key1", "value1", "key2", "value2")
741// - MSet([]string{"key1", "value1", "key2", "value2"})
742// - MSet(map[string]interface{}{"key1": "value1", "key2": "value2"})
743func (c cmdable) MSet(ctx context.Context, values ...interface{}) *StatusCmd {
744 args := make([]interface{}, 1, 1+len(values))
745 args[0] = "mset"
746 args = appendArgs(args, values)
747 cmd := NewStatusCmd(ctx, args...)
748 _ = c(ctx, cmd)
749 return cmd
750}
751
752// MSetNX is like SetNX but accepts multiple values:
753// - MSetNX("key1", "value1", "key2", "value2")
754// - MSetNX([]string{"key1", "value1", "key2", "value2"})
755// - MSetNX(map[string]interface{}{"key1": "value1", "key2": "value2"})
756func (c cmdable) MSetNX(ctx context.Context, values ...interface{}) *BoolCmd {
757 args := make([]interface{}, 1, 1+len(values))
758 args[0] = "msetnx"
759 args = appendArgs(args, values)
760 cmd := NewBoolCmd(ctx, args...)
761 _ = c(ctx, cmd)
762 return cmd
763}
764
765// Redis `SET key value [expiration]` command.
766// Use expiration for `SETEX`-like behavior.
767//
768// Zero expiration means the key has no expiration time.
769// KeepTTL(-1) expiration is a Redis KEEPTTL option to keep existing TTL.
770func (c cmdable) Set(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd {
771 args := make([]interface{}, 3, 5)
772 args[0] = "set"
773 args[1] = key
774 args[2] = value
775 if expiration > 0 {
776 if usePrecise(expiration) {
777 args = append(args, "px", formatMs(ctx, expiration))
778 } else {
779 args = append(args, "ex", formatSec(ctx, expiration))
780 }
781 } else if expiration == KeepTTL {
782 args = append(args, "keepttl")
783 }
784
785 cmd := NewStatusCmd(ctx, args...)
786 _ = c(ctx, cmd)
787 return cmd
788}
789
790// Redis `SETEX key expiration value` command.
791func (c cmdable) SetEX(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd {
792 cmd := NewStatusCmd(ctx, "setex", key, formatSec(ctx, expiration), value)
793 _ = c(ctx, cmd)
794 return cmd
795}
796
797// Redis `SET key value [expiration] NX` command.
798//
799// Zero expiration means the key has no expiration time.
800// KeepTTL(-1) expiration is a Redis KEEPTTL option to keep existing TTL.
801func (c cmdable) SetNX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd {
802 var cmd *BoolCmd
803 switch expiration {
804 case 0:
805 // Use old `SETNX` to support old Redis versions.
806 cmd = NewBoolCmd(ctx, "setnx", key, value)
807 case KeepTTL:
808 cmd = NewBoolCmd(ctx, "set", key, value, "keepttl", "nx")
809 default:
810 if usePrecise(expiration) {
811 cmd = NewBoolCmd(ctx, "set", key, value, "px", formatMs(ctx, expiration), "nx")
812 } else {
813 cmd = NewBoolCmd(ctx, "set", key, value, "ex", formatSec(ctx, expiration), "nx")
814 }
815 }
816
817 _ = c(ctx, cmd)
818 return cmd
819}
820
821// Redis `SET key value [expiration] XX` command.
822//
823// Zero expiration means the key has no expiration time.
824// KeepTTL(-1) expiration is a Redis KEEPTTL option to keep existing TTL.
825func (c cmdable) SetXX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd {
826 var cmd *BoolCmd
827 switch expiration {
828 case 0:
829 cmd = NewBoolCmd(ctx, "set", key, value, "xx")
830 case KeepTTL:
831 cmd = NewBoolCmd(ctx, "set", key, value, "keepttl", "xx")
832 default:
833 if usePrecise(expiration) {
834 cmd = NewBoolCmd(ctx, "set", key, value, "px", formatMs(ctx, expiration), "xx")
835 } else {
836 cmd = NewBoolCmd(ctx, "set", key, value, "ex", formatSec(ctx, expiration), "xx")
837 }
838 }
839
840 _ = c(ctx, cmd)
841 return cmd
842}
843
844func (c cmdable) SetRange(ctx context.Context, key string, offset int64, value string) *IntCmd {
845 cmd := NewIntCmd(ctx, "setrange", key, offset, value)
846 _ = c(ctx, cmd)
847 return cmd
848}
849
850func (c cmdable) StrLen(ctx context.Context, key string) *IntCmd {
851 cmd := NewIntCmd(ctx, "strlen", key)
852 _ = c(ctx, cmd)
853 return cmd
854}
855
856//------------------------------------------------------------------------------
857
858func (c cmdable) GetBit(ctx context.Context, key string, offset int64) *IntCmd {
859 cmd := NewIntCmd(ctx, "getbit", key, offset)
860 _ = c(ctx, cmd)
861 return cmd
862}
863
864func (c cmdable) SetBit(ctx context.Context, key string, offset int64, value int) *IntCmd {
865 cmd := NewIntCmd(
866 ctx,
867 "setbit",
868 key,
869 offset,
870 value,
871 )
872 _ = c(ctx, cmd)
873 return cmd
874}
875
876type BitCount struct {
877 Start, End int64
878}
879
880func (c cmdable) BitCount(ctx context.Context, key string, bitCount *BitCount) *IntCmd {
881 args := []interface{}{"bitcount", key}
882 if bitCount != nil {
883 args = append(
884 args,
885 bitCount.Start,
886 bitCount.End,
887 )
888 }
889 cmd := NewIntCmd(ctx, args...)
890 _ = c(ctx, cmd)
891 return cmd
892}
893
894func (c cmdable) bitOp(ctx context.Context, op, destKey string, keys ...string) *IntCmd {
895 args := make([]interface{}, 3+len(keys))
896 args[0] = "bitop"
897 args[1] = op
898 args[2] = destKey
899 for i, key := range keys {
900 args[3+i] = key
901 }
902 cmd := NewIntCmd(ctx, args...)
903 _ = c(ctx, cmd)
904 return cmd
905}
906
907func (c cmdable) BitOpAnd(ctx context.Context, destKey string, keys ...string) *IntCmd {
908 return c.bitOp(ctx, "and", destKey, keys...)
909}
910
911func (c cmdable) BitOpOr(ctx context.Context, destKey string, keys ...string) *IntCmd {
912 return c.bitOp(ctx, "or", destKey, keys...)
913}
914
915func (c cmdable) BitOpXor(ctx context.Context, destKey string, keys ...string) *IntCmd {
916 return c.bitOp(ctx, "xor", destKey, keys...)
917}
918
919func (c cmdable) BitOpNot(ctx context.Context, destKey string, key string) *IntCmd {
920 return c.bitOp(ctx, "not", destKey, key)
921}
922
923func (c cmdable) BitPos(ctx context.Context, key string, bit int64, pos ...int64) *IntCmd {
924 args := make([]interface{}, 3+len(pos))
925 args[0] = "bitpos"
926 args[1] = key
927 args[2] = bit
928 switch len(pos) {
929 case 0:
930 case 1:
931 args[3] = pos[0]
932 case 2:
933 args[3] = pos[0]
934 args[4] = pos[1]
935 default:
936 panic("too many arguments")
937 }
938 cmd := NewIntCmd(ctx, args...)
939 _ = c(ctx, cmd)
940 return cmd
941}
942
943func (c cmdable) BitField(ctx context.Context, key string, args ...interface{}) *IntSliceCmd {
944 a := make([]interface{}, 0, 2+len(args))
945 a = append(a, "bitfield")
946 a = append(a, key)
947 a = append(a, args...)
948 cmd := NewIntSliceCmd(ctx, a...)
949 _ = c(ctx, cmd)
950 return cmd
951}
952
953//------------------------------------------------------------------------------
954
955func (c cmdable) Scan(ctx context.Context, cursor uint64, match string, count int64) *ScanCmd {
956 args := []interface{}{"scan", cursor}
957 if match != "" {
958 args = append(args, "match", match)
959 }
960 if count > 0 {
961 args = append(args, "count", count)
962 }
963 cmd := NewScanCmd(ctx, c, args...)
964 _ = c(ctx, cmd)
965 return cmd
966}
967
968func (c cmdable) SScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd {
969 args := []interface{}{"sscan", key, cursor}
970 if match != "" {
971 args = append(args, "match", match)
972 }
973 if count > 0 {
974 args = append(args, "count", count)
975 }
976 cmd := NewScanCmd(ctx, c, args...)
977 _ = c(ctx, cmd)
978 return cmd
979}
980
981func (c cmdable) HScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd {
982 args := []interface{}{"hscan", key, cursor}
983 if match != "" {
984 args = append(args, "match", match)
985 }
986 if count > 0 {
987 args = append(args, "count", count)
988 }
989 cmd := NewScanCmd(ctx, c, args...)
990 _ = c(ctx, cmd)
991 return cmd
992}
993
994func (c cmdable) ZScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd {
995 args := []interface{}{"zscan", key, cursor}
996 if match != "" {
997 args = append(args, "match", match)
998 }
999 if count > 0 {
1000 args = append(args, "count", count)
1001 }
1002 cmd := NewScanCmd(ctx, c, args...)
1003 _ = c(ctx, cmd)
1004 return cmd
1005}
1006
1007//------------------------------------------------------------------------------
1008
1009func (c cmdable) HDel(ctx context.Context, key string, fields ...string) *IntCmd {
1010 args := make([]interface{}, 2+len(fields))
1011 args[0] = "hdel"
1012 args[1] = key
1013 for i, field := range fields {
1014 args[2+i] = field
1015 }
1016 cmd := NewIntCmd(ctx, args...)
1017 _ = c(ctx, cmd)
1018 return cmd
1019}
1020
1021func (c cmdable) HExists(ctx context.Context, key, field string) *BoolCmd {
1022 cmd := NewBoolCmd(ctx, "hexists", key, field)
1023 _ = c(ctx, cmd)
1024 return cmd
1025}
1026
1027func (c cmdable) HGet(ctx context.Context, key, field string) *StringCmd {
1028 cmd := NewStringCmd(ctx, "hget", key, field)
1029 _ = c(ctx, cmd)
1030 return cmd
1031}
1032
1033func (c cmdable) HGetAll(ctx context.Context, key string) *StringStringMapCmd {
1034 cmd := NewStringStringMapCmd(ctx, "hgetall", key)
1035 _ = c(ctx, cmd)
1036 return cmd
1037}
1038
1039func (c cmdable) HIncrBy(ctx context.Context, key, field string, incr int64) *IntCmd {
1040 cmd := NewIntCmd(ctx, "hincrby", key, field, incr)
1041 _ = c(ctx, cmd)
1042 return cmd
1043}
1044
1045func (c cmdable) HIncrByFloat(ctx context.Context, key, field string, incr float64) *FloatCmd {
1046 cmd := NewFloatCmd(ctx, "hincrbyfloat", key, field, incr)
1047 _ = c(ctx, cmd)
1048 return cmd
1049}
1050
1051func (c cmdable) HKeys(ctx context.Context, key string) *StringSliceCmd {
1052 cmd := NewStringSliceCmd(ctx, "hkeys", key)
1053 _ = c(ctx, cmd)
1054 return cmd
1055}
1056
1057func (c cmdable) HLen(ctx context.Context, key string) *IntCmd {
1058 cmd := NewIntCmd(ctx, "hlen", key)
1059 _ = c(ctx, cmd)
1060 return cmd
1061}
1062
1063// HMGet returns the values for the specified fields in the hash stored at key.
1064// It returns an interface{} to distinguish between empty string and nil value.
1065func (c cmdable) HMGet(ctx context.Context, key string, fields ...string) *SliceCmd {
1066 args := make([]interface{}, 2+len(fields))
1067 args[0] = "hmget"
1068 args[1] = key
1069 for i, field := range fields {
1070 args[2+i] = field
1071 }
1072 cmd := NewSliceCmd(ctx, args...)
1073 _ = c(ctx, cmd)
1074 return cmd
1075}
1076
1077// HSet accepts values in following formats:
1078// - HSet("myhash", "key1", "value1", "key2", "value2")
1079// - HSet("myhash", []string{"key1", "value1", "key2", "value2"})
1080// - HSet("myhash", map[string]interface{}{"key1": "value1", "key2": "value2"})
1081//
1082// Note that it requires Redis v4 for multiple field/value pairs support.
1083func (c cmdable) HSet(ctx context.Context, key string, values ...interface{}) *IntCmd {
1084 args := make([]interface{}, 2, 2+len(values))
1085 args[0] = "hset"
1086 args[1] = key
1087 args = appendArgs(args, values)
1088 cmd := NewIntCmd(ctx, args...)
1089 _ = c(ctx, cmd)
1090 return cmd
1091}
1092
1093// HMSet is a deprecated version of HSet left for compatibility with Redis 3.
1094func (c cmdable) HMSet(ctx context.Context, key string, values ...interface{}) *BoolCmd {
1095 args := make([]interface{}, 2, 2+len(values))
1096 args[0] = "hmset"
1097 args[1] = key
1098 args = appendArgs(args, values)
1099 cmd := NewBoolCmd(ctx, args...)
1100 _ = c(ctx, cmd)
1101 return cmd
1102}
1103
1104func (c cmdable) HSetNX(ctx context.Context, key, field string, value interface{}) *BoolCmd {
1105 cmd := NewBoolCmd(ctx, "hsetnx", key, field, value)
1106 _ = c(ctx, cmd)
1107 return cmd
1108}
1109
1110func (c cmdable) HVals(ctx context.Context, key string) *StringSliceCmd {
1111 cmd := NewStringSliceCmd(ctx, "hvals", key)
1112 _ = c(ctx, cmd)
1113 return cmd
1114}
1115
1116//------------------------------------------------------------------------------
1117
1118func (c cmdable) BLPop(ctx context.Context, timeout time.Duration, keys ...string) *StringSliceCmd {
1119 args := make([]interface{}, 1+len(keys)+1)
1120 args[0] = "blpop"
1121 for i, key := range keys {
1122 args[1+i] = key
1123 }
1124 args[len(args)-1] = formatSec(ctx, timeout)
1125 cmd := NewStringSliceCmd(ctx, args...)
1126 cmd.setReadTimeout(timeout)
1127 _ = c(ctx, cmd)
1128 return cmd
1129}
1130
1131func (c cmdable) BRPop(ctx context.Context, timeout time.Duration, keys ...string) *StringSliceCmd {
1132 args := make([]interface{}, 1+len(keys)+1)
1133 args[0] = "brpop"
1134 for i, key := range keys {
1135 args[1+i] = key
1136 }
1137 args[len(keys)+1] = formatSec(ctx, timeout)
1138 cmd := NewStringSliceCmd(ctx, args...)
1139 cmd.setReadTimeout(timeout)
1140 _ = c(ctx, cmd)
1141 return cmd
1142}
1143
1144func (c cmdable) BRPopLPush(ctx context.Context, source, destination string, timeout time.Duration) *StringCmd {
1145 cmd := NewStringCmd(
1146 ctx,
1147 "brpoplpush",
1148 source,
1149 destination,
1150 formatSec(ctx, timeout),
1151 )
1152 cmd.setReadTimeout(timeout)
1153 _ = c(ctx, cmd)
1154 return cmd
1155}
1156
1157func (c cmdable) LIndex(ctx context.Context, key string, index int64) *StringCmd {
1158 cmd := NewStringCmd(ctx, "lindex", key, index)
1159 _ = c(ctx, cmd)
1160 return cmd
1161}
1162
1163func (c cmdable) LInsert(ctx context.Context, key, op string, pivot, value interface{}) *IntCmd {
1164 cmd := NewIntCmd(ctx, "linsert", key, op, pivot, value)
1165 _ = c(ctx, cmd)
1166 return cmd
1167}
1168
1169func (c cmdable) LInsertBefore(ctx context.Context, key string, pivot, value interface{}) *IntCmd {
1170 cmd := NewIntCmd(ctx, "linsert", key, "before", pivot, value)
1171 _ = c(ctx, cmd)
1172 return cmd
1173}
1174
1175func (c cmdable) LInsertAfter(ctx context.Context, key string, pivot, value interface{}) *IntCmd {
1176 cmd := NewIntCmd(ctx, "linsert", key, "after", pivot, value)
1177 _ = c(ctx, cmd)
1178 return cmd
1179}
1180
1181func (c cmdable) LLen(ctx context.Context, key string) *IntCmd {
1182 cmd := NewIntCmd(ctx, "llen", key)
1183 _ = c(ctx, cmd)
1184 return cmd
1185}
1186
1187func (c cmdable) LPop(ctx context.Context, key string) *StringCmd {
1188 cmd := NewStringCmd(ctx, "lpop", key)
1189 _ = c(ctx, cmd)
1190 return cmd
1191}
1192
1193type LPosArgs struct {
1194 Rank, MaxLen int64
1195}
1196
1197func (c cmdable) LPos(ctx context.Context, key string, value string, a LPosArgs) *IntCmd {
1198 args := []interface{}{"lpos", key, value}
1199 if a.Rank != 0 {
1200 args = append(args, "rank", a.Rank)
1201 }
1202 if a.MaxLen != 0 {
1203 args = append(args, "maxlen", a.MaxLen)
1204 }
1205
1206 cmd := NewIntCmd(ctx, args...)
1207 _ = c(ctx, cmd)
1208 return cmd
1209}
1210
1211func (c cmdable) LPosCount(ctx context.Context, key string, value string, count int64, a LPosArgs) *IntSliceCmd {
1212 args := []interface{}{"lpos", key, value, "count", count}
1213 if a.Rank != 0 {
1214 args = append(args, "rank", a.Rank)
1215 }
1216 if a.MaxLen != 0 {
1217 args = append(args, "maxlen", a.MaxLen)
1218 }
1219 cmd := NewIntSliceCmd(ctx, args...)
1220 _ = c(ctx, cmd)
1221 return cmd
1222}
1223
1224func (c cmdable) LPush(ctx context.Context, key string, values ...interface{}) *IntCmd {
1225 args := make([]interface{}, 2, 2+len(values))
1226 args[0] = "lpush"
1227 args[1] = key
1228 args = appendArgs(args, values)
1229 cmd := NewIntCmd(ctx, args...)
1230 _ = c(ctx, cmd)
1231 return cmd
1232}
1233
1234func (c cmdable) LPushX(ctx context.Context, key string, values ...interface{}) *IntCmd {
1235 args := make([]interface{}, 2, 2+len(values))
1236 args[0] = "lpushx"
1237 args[1] = key
1238 args = appendArgs(args, values)
1239 cmd := NewIntCmd(ctx, args...)
1240 _ = c(ctx, cmd)
1241 return cmd
1242}
1243
1244func (c cmdable) LRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd {
1245 cmd := NewStringSliceCmd(
1246 ctx,
1247 "lrange",
1248 key,
1249 start,
1250 stop,
1251 )
1252 _ = c(ctx, cmd)
1253 return cmd
1254}
1255
1256func (c cmdable) LRem(ctx context.Context, key string, count int64, value interface{}) *IntCmd {
1257 cmd := NewIntCmd(ctx, "lrem", key, count, value)
1258 _ = c(ctx, cmd)
1259 return cmd
1260}
1261
1262func (c cmdable) LSet(ctx context.Context, key string, index int64, value interface{}) *StatusCmd {
1263 cmd := NewStatusCmd(ctx, "lset", key, index, value)
1264 _ = c(ctx, cmd)
1265 return cmd
1266}
1267
1268func (c cmdable) LTrim(ctx context.Context, key string, start, stop int64) *StatusCmd {
1269 cmd := NewStatusCmd(
1270 ctx,
1271 "ltrim",
1272 key,
1273 start,
1274 stop,
1275 )
1276 _ = c(ctx, cmd)
1277 return cmd
1278}
1279
1280func (c cmdable) RPop(ctx context.Context, key string) *StringCmd {
1281 cmd := NewStringCmd(ctx, "rpop", key)
1282 _ = c(ctx, cmd)
1283 return cmd
1284}
1285
1286func (c cmdable) RPopLPush(ctx context.Context, source, destination string) *StringCmd {
1287 cmd := NewStringCmd(ctx, "rpoplpush", source, destination)
1288 _ = c(ctx, cmd)
1289 return cmd
1290}
1291
1292func (c cmdable) RPush(ctx context.Context, key string, values ...interface{}) *IntCmd {
1293 args := make([]interface{}, 2, 2+len(values))
1294 args[0] = "rpush"
1295 args[1] = key
1296 args = appendArgs(args, values)
1297 cmd := NewIntCmd(ctx, args...)
1298 _ = c(ctx, cmd)
1299 return cmd
1300}
1301
1302func (c cmdable) RPushX(ctx context.Context, key string, values ...interface{}) *IntCmd {
1303 args := make([]interface{}, 2, 2+len(values))
1304 args[0] = "rpushx"
1305 args[1] = key
1306 args = appendArgs(args, values)
1307 cmd := NewIntCmd(ctx, args...)
1308 _ = c(ctx, cmd)
1309 return cmd
1310}
1311
1312//------------------------------------------------------------------------------
1313
1314func (c cmdable) SAdd(ctx context.Context, key string, members ...interface{}) *IntCmd {
1315 args := make([]interface{}, 2, 2+len(members))
1316 args[0] = "sadd"
1317 args[1] = key
1318 args = appendArgs(args, members)
1319 cmd := NewIntCmd(ctx, args...)
1320 _ = c(ctx, cmd)
1321 return cmd
1322}
1323
1324func (c cmdable) SCard(ctx context.Context, key string) *IntCmd {
1325 cmd := NewIntCmd(ctx, "scard", key)
1326 _ = c(ctx, cmd)
1327 return cmd
1328}
1329
1330func (c cmdable) SDiff(ctx context.Context, keys ...string) *StringSliceCmd {
1331 args := make([]interface{}, 1+len(keys))
1332 args[0] = "sdiff"
1333 for i, key := range keys {
1334 args[1+i] = key
1335 }
1336 cmd := NewStringSliceCmd(ctx, args...)
1337 _ = c(ctx, cmd)
1338 return cmd
1339}
1340
1341func (c cmdable) SDiffStore(ctx context.Context, destination string, keys ...string) *IntCmd {
1342 args := make([]interface{}, 2+len(keys))
1343 args[0] = "sdiffstore"
1344 args[1] = destination
1345 for i, key := range keys {
1346 args[2+i] = key
1347 }
1348 cmd := NewIntCmd(ctx, args...)
1349 _ = c(ctx, cmd)
1350 return cmd
1351}
1352
1353func (c cmdable) SInter(ctx context.Context, keys ...string) *StringSliceCmd {
1354 args := make([]interface{}, 1+len(keys))
1355 args[0] = "sinter"
1356 for i, key := range keys {
1357 args[1+i] = key
1358 }
1359 cmd := NewStringSliceCmd(ctx, args...)
1360 _ = c(ctx, cmd)
1361 return cmd
1362}
1363
1364func (c cmdable) SInterStore(ctx context.Context, destination string, keys ...string) *IntCmd {
1365 args := make([]interface{}, 2+len(keys))
1366 args[0] = "sinterstore"
1367 args[1] = destination
1368 for i, key := range keys {
1369 args[2+i] = key
1370 }
1371 cmd := NewIntCmd(ctx, args...)
1372 _ = c(ctx, cmd)
1373 return cmd
1374}
1375
1376func (c cmdable) SIsMember(ctx context.Context, key string, member interface{}) *BoolCmd {
1377 cmd := NewBoolCmd(ctx, "sismember", key, member)
1378 _ = c(ctx, cmd)
1379 return cmd
1380}
1381
1382// Redis `SMEMBERS key` command output as a slice.
1383func (c cmdable) SMembers(ctx context.Context, key string) *StringSliceCmd {
1384 cmd := NewStringSliceCmd(ctx, "smembers", key)
1385 _ = c(ctx, cmd)
1386 return cmd
1387}
1388
1389// Redis `SMEMBERS key` command output as a map.
1390func (c cmdable) SMembersMap(ctx context.Context, key string) *StringStructMapCmd {
1391 cmd := NewStringStructMapCmd(ctx, "smembers", key)
1392 _ = c(ctx, cmd)
1393 return cmd
1394}
1395
1396func (c cmdable) SMove(ctx context.Context, source, destination string, member interface{}) *BoolCmd {
1397 cmd := NewBoolCmd(ctx, "smove", source, destination, member)
1398 _ = c(ctx, cmd)
1399 return cmd
1400}
1401
1402// Redis `SPOP key` command.
1403func (c cmdable) SPop(ctx context.Context, key string) *StringCmd {
1404 cmd := NewStringCmd(ctx, "spop", key)
1405 _ = c(ctx, cmd)
1406 return cmd
1407}
1408
1409// Redis `SPOP key count` command.
1410func (c cmdable) SPopN(ctx context.Context, key string, count int64) *StringSliceCmd {
1411 cmd := NewStringSliceCmd(ctx, "spop", key, count)
1412 _ = c(ctx, cmd)
1413 return cmd
1414}
1415
1416// Redis `SRANDMEMBER key` command.
1417func (c cmdable) SRandMember(ctx context.Context, key string) *StringCmd {
1418 cmd := NewStringCmd(ctx, "srandmember", key)
1419 _ = c(ctx, cmd)
1420 return cmd
1421}
1422
1423// Redis `SRANDMEMBER key count` command.
1424func (c cmdable) SRandMemberN(ctx context.Context, key string, count int64) *StringSliceCmd {
1425 cmd := NewStringSliceCmd(ctx, "srandmember", key, count)
1426 _ = c(ctx, cmd)
1427 return cmd
1428}
1429
1430func (c cmdable) SRem(ctx context.Context, key string, members ...interface{}) *IntCmd {
1431 args := make([]interface{}, 2, 2+len(members))
1432 args[0] = "srem"
1433 args[1] = key
1434 args = appendArgs(args, members)
1435 cmd := NewIntCmd(ctx, args...)
1436 _ = c(ctx, cmd)
1437 return cmd
1438}
1439
1440func (c cmdable) SUnion(ctx context.Context, keys ...string) *StringSliceCmd {
1441 args := make([]interface{}, 1+len(keys))
1442 args[0] = "sunion"
1443 for i, key := range keys {
1444 args[1+i] = key
1445 }
1446 cmd := NewStringSliceCmd(ctx, args...)
1447 _ = c(ctx, cmd)
1448 return cmd
1449}
1450
1451func (c cmdable) SUnionStore(ctx context.Context, destination string, keys ...string) *IntCmd {
1452 args := make([]interface{}, 2+len(keys))
1453 args[0] = "sunionstore"
1454 args[1] = destination
1455 for i, key := range keys {
1456 args[2+i] = key
1457 }
1458 cmd := NewIntCmd(ctx, args...)
1459 _ = c(ctx, cmd)
1460 return cmd
1461}
1462
1463//------------------------------------------------------------------------------
1464
1465// XAddArgs accepts values in the following formats:
1466// - XAddArgs.Values = []interface{}{"key1", "value1", "key2", "value2"}
1467// - XAddArgs.Values = []string("key1", "value1", "key2", "value2")
1468// - XAddArgs.Values = map[string]interface{}{"key1": "value1", "key2": "value2"}
1469//
1470// Note that map will not preserve the order of key-value pairs.
1471type XAddArgs struct {
1472 Stream string
1473 MaxLen int64 // MAXLEN N
1474 MaxLenApprox int64 // MAXLEN ~ N
1475 ID string
1476 Values interface{}
1477}
1478
1479func (c cmdable) XAdd(ctx context.Context, a *XAddArgs) *StringCmd {
1480 args := make([]interface{}, 0, 8)
1481 args = append(args, "xadd")
1482 args = append(args, a.Stream)
1483 if a.MaxLen > 0 {
1484 args = append(args, "maxlen", a.MaxLen)
1485 } else if a.MaxLenApprox > 0 {
1486 args = append(args, "maxlen", "~", a.MaxLenApprox)
1487 }
1488 if a.ID != "" {
1489 args = append(args, a.ID)
1490 } else {
1491 args = append(args, "*")
1492 }
1493 args = appendArg(args, a.Values)
1494
1495 cmd := NewStringCmd(ctx, args...)
1496 _ = c(ctx, cmd)
1497 return cmd
1498}
1499
1500func (c cmdable) XDel(ctx context.Context, stream string, ids ...string) *IntCmd {
1501 args := []interface{}{"xdel", stream}
1502 for _, id := range ids {
1503 args = append(args, id)
1504 }
1505 cmd := NewIntCmd(ctx, args...)
1506 _ = c(ctx, cmd)
1507 return cmd
1508}
1509
1510func (c cmdable) XLen(ctx context.Context, stream string) *IntCmd {
1511 cmd := NewIntCmd(ctx, "xlen", stream)
1512 _ = c(ctx, cmd)
1513 return cmd
1514}
1515
1516func (c cmdable) XRange(ctx context.Context, stream, start, stop string) *XMessageSliceCmd {
1517 cmd := NewXMessageSliceCmd(ctx, "xrange", stream, start, stop)
1518 _ = c(ctx, cmd)
1519 return cmd
1520}
1521
1522func (c cmdable) XRangeN(ctx context.Context, stream, start, stop string, count int64) *XMessageSliceCmd {
1523 cmd := NewXMessageSliceCmd(ctx, "xrange", stream, start, stop, "count", count)
1524 _ = c(ctx, cmd)
1525 return cmd
1526}
1527
1528func (c cmdable) XRevRange(ctx context.Context, stream, start, stop string) *XMessageSliceCmd {
1529 cmd := NewXMessageSliceCmd(ctx, "xrevrange", stream, start, stop)
1530 _ = c(ctx, cmd)
1531 return cmd
1532}
1533
1534func (c cmdable) XRevRangeN(ctx context.Context, stream, start, stop string, count int64) *XMessageSliceCmd {
1535 cmd := NewXMessageSliceCmd(ctx, "xrevrange", stream, start, stop, "count", count)
1536 _ = c(ctx, cmd)
1537 return cmd
1538}
1539
1540type XReadArgs struct {
1541 Streams []string // list of streams and ids, e.g. stream1 stream2 id1 id2
1542 Count int64
1543 Block time.Duration
1544}
1545
1546func (c cmdable) XRead(ctx context.Context, a *XReadArgs) *XStreamSliceCmd {
1547 args := make([]interface{}, 0, 5+len(a.Streams))
1548 args = append(args, "xread")
1549
1550 keyPos := int8(1)
1551 if a.Count > 0 {
1552 args = append(args, "count")
1553 args = append(args, a.Count)
1554 keyPos += 2
1555 }
1556 if a.Block >= 0 {
1557 args = append(args, "block")
1558 args = append(args, int64(a.Block/time.Millisecond))
1559 keyPos += 2
1560 }
1561 args = append(args, "streams")
1562 keyPos++
1563 for _, s := range a.Streams {
1564 args = append(args, s)
1565 }
1566
1567 cmd := NewXStreamSliceCmd(ctx, args...)
1568 if a.Block >= 0 {
1569 cmd.setReadTimeout(a.Block)
1570 }
1571 cmd.setFirstKeyPos(keyPos)
1572 _ = c(ctx, cmd)
1573 return cmd
1574}
1575
1576func (c cmdable) XReadStreams(ctx context.Context, streams ...string) *XStreamSliceCmd {
1577 return c.XRead(ctx, &XReadArgs{
1578 Streams: streams,
1579 Block: -1,
1580 })
1581}
1582
1583func (c cmdable) XGroupCreate(ctx context.Context, stream, group, start string) *StatusCmd {
1584 cmd := NewStatusCmd(ctx, "xgroup", "create", stream, group, start)
1585 _ = c(ctx, cmd)
1586 return cmd
1587}
1588
1589func (c cmdable) XGroupCreateMkStream(ctx context.Context, stream, group, start string) *StatusCmd {
1590 cmd := NewStatusCmd(ctx, "xgroup", "create", stream, group, start, "mkstream")
1591 _ = c(ctx, cmd)
1592 return cmd
1593}
1594
1595func (c cmdable) XGroupSetID(ctx context.Context, stream, group, start string) *StatusCmd {
1596 cmd := NewStatusCmd(ctx, "xgroup", "setid", stream, group, start)
1597 _ = c(ctx, cmd)
1598 return cmd
1599}
1600
1601func (c cmdable) XGroupDestroy(ctx context.Context, stream, group string) *IntCmd {
1602 cmd := NewIntCmd(ctx, "xgroup", "destroy", stream, group)
1603 _ = c(ctx, cmd)
1604 return cmd
1605}
1606
1607func (c cmdable) XGroupDelConsumer(ctx context.Context, stream, group, consumer string) *IntCmd {
1608 cmd := NewIntCmd(ctx, "xgroup", "delconsumer", stream, group, consumer)
1609 _ = c(ctx, cmd)
1610 return cmd
1611}
1612
1613type XReadGroupArgs struct {
1614 Group string
1615 Consumer string
1616 Streams []string // list of streams and ids, e.g. stream1 stream2 id1 id2
1617 Count int64
1618 Block time.Duration
1619 NoAck bool
1620}
1621
1622func (c cmdable) XReadGroup(ctx context.Context, a *XReadGroupArgs) *XStreamSliceCmd {
1623 args := make([]interface{}, 0, 8+len(a.Streams))
1624 args = append(args, "xreadgroup", "group", a.Group, a.Consumer)
1625
1626 keyPos := int8(1)
1627 if a.Count > 0 {
1628 args = append(args, "count", a.Count)
1629 keyPos += 2
1630 }
1631 if a.Block >= 0 {
1632 args = append(args, "block", int64(a.Block/time.Millisecond))
1633 keyPos += 2
1634 }
1635 if a.NoAck {
1636 args = append(args, "noack")
1637 keyPos++
1638 }
1639 args = append(args, "streams")
1640 keyPos++
1641 for _, s := range a.Streams {
1642 args = append(args, s)
1643 }
1644
1645 cmd := NewXStreamSliceCmd(ctx, args...)
1646 if a.Block >= 0 {
1647 cmd.setReadTimeout(a.Block)
1648 }
1649 cmd.setFirstKeyPos(keyPos)
1650 _ = c(ctx, cmd)
1651 return cmd
1652}
1653
1654func (c cmdable) XAck(ctx context.Context, stream, group string, ids ...string) *IntCmd {
1655 args := []interface{}{"xack", stream, group}
1656 for _, id := range ids {
1657 args = append(args, id)
1658 }
1659 cmd := NewIntCmd(ctx, args...)
1660 _ = c(ctx, cmd)
1661 return cmd
1662}
1663
1664func (c cmdable) XPending(ctx context.Context, stream, group string) *XPendingCmd {
1665 cmd := NewXPendingCmd(ctx, "xpending", stream, group)
1666 _ = c(ctx, cmd)
1667 return cmd
1668}
1669
1670type XPendingExtArgs struct {
1671 Stream string
1672 Group string
1673 Start string
1674 End string
1675 Count int64
1676 Consumer string
1677}
1678
1679func (c cmdable) XPendingExt(ctx context.Context, a *XPendingExtArgs) *XPendingExtCmd {
1680 args := make([]interface{}, 0, 7)
1681 args = append(args, "xpending", a.Stream, a.Group, a.Start, a.End, a.Count)
1682 if a.Consumer != "" {
1683 args = append(args, a.Consumer)
1684 }
1685 cmd := NewXPendingExtCmd(ctx, args...)
1686 _ = c(ctx, cmd)
1687 return cmd
1688}
1689
1690type XClaimArgs struct {
1691 Stream string
1692 Group string
1693 Consumer string
1694 MinIdle time.Duration
1695 Messages []string
1696}
1697
1698func (c cmdable) XClaim(ctx context.Context, a *XClaimArgs) *XMessageSliceCmd {
1699 args := xClaimArgs(a)
1700 cmd := NewXMessageSliceCmd(ctx, args...)
1701 _ = c(ctx, cmd)
1702 return cmd
1703}
1704
1705func (c cmdable) XClaimJustID(ctx context.Context, a *XClaimArgs) *StringSliceCmd {
1706 args := xClaimArgs(a)
1707 args = append(args, "justid")
1708 cmd := NewStringSliceCmd(ctx, args...)
1709 _ = c(ctx, cmd)
1710 return cmd
1711}
1712
1713func xClaimArgs(a *XClaimArgs) []interface{} {
1714 args := make([]interface{}, 0, 4+len(a.Messages))
1715 args = append(args,
1716 "xclaim",
1717 a.Stream,
1718 a.Group, a.Consumer,
1719 int64(a.MinIdle/time.Millisecond))
1720 for _, id := range a.Messages {
1721 args = append(args, id)
1722 }
1723 return args
1724}
1725
1726func (c cmdable) XTrim(ctx context.Context, key string, maxLen int64) *IntCmd {
1727 cmd := NewIntCmd(ctx, "xtrim", key, "maxlen", maxLen)
1728 _ = c(ctx, cmd)
1729 return cmd
1730}
1731
1732func (c cmdable) XTrimApprox(ctx context.Context, key string, maxLen int64) *IntCmd {
1733 cmd := NewIntCmd(ctx, "xtrim", key, "maxlen", "~", maxLen)
1734 _ = c(ctx, cmd)
1735 return cmd
1736}
1737
1738func (c cmdable) XInfoGroups(ctx context.Context, key string) *XInfoGroupsCmd {
1739 cmd := NewXInfoGroupsCmd(ctx, key)
1740 _ = c(ctx, cmd)
1741 return cmd
1742}
1743
1744func (c cmdable) XInfoStream(ctx context.Context, key string) *XInfoStreamCmd {
1745 cmd := NewXInfoStreamCmd(ctx, key)
1746 _ = c(ctx, cmd)
1747 return cmd
1748}
1749
1750//------------------------------------------------------------------------------
1751
1752// Z represents sorted set member.
1753type Z struct {
1754 Score float64
1755 Member interface{}
1756}
1757
1758// ZWithKey represents sorted set member including the name of the key where it was popped.
1759type ZWithKey struct {
1760 Z
1761 Key string
1762}
1763
1764// ZStore is used as an arg to ZInterStore and ZUnionStore.
1765type ZStore struct {
1766 Keys []string
1767 Weights []float64
1768 // Can be SUM, MIN or MAX.
1769 Aggregate string
1770}
1771
1772// Redis `BZPOPMAX key [key ...] timeout` command.
1773func (c cmdable) BZPopMax(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd {
1774 args := make([]interface{}, 1+len(keys)+1)
1775 args[0] = "bzpopmax"
1776 for i, key := range keys {
1777 args[1+i] = key
1778 }
1779 args[len(args)-1] = formatSec(ctx, timeout)
1780 cmd := NewZWithKeyCmd(ctx, args...)
1781 cmd.setReadTimeout(timeout)
1782 _ = c(ctx, cmd)
1783 return cmd
1784}
1785
1786// Redis `BZPOPMIN key [key ...] timeout` command.
1787func (c cmdable) BZPopMin(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd {
1788 args := make([]interface{}, 1+len(keys)+1)
1789 args[0] = "bzpopmin"
1790 for i, key := range keys {
1791 args[1+i] = key
1792 }
1793 args[len(args)-1] = formatSec(ctx, timeout)
1794 cmd := NewZWithKeyCmd(ctx, args...)
1795 cmd.setReadTimeout(timeout)
1796 _ = c(ctx, cmd)
1797 return cmd
1798}
1799
1800func (c cmdable) zAdd(ctx context.Context, a []interface{}, n int, members ...*Z) *IntCmd {
1801 for i, m := range members {
1802 a[n+2*i] = m.Score
1803 a[n+2*i+1] = m.Member
1804 }
1805 cmd := NewIntCmd(ctx, a...)
1806 _ = c(ctx, cmd)
1807 return cmd
1808}
1809
1810// Redis `ZADD key score member [score member ...]` command.
1811func (c cmdable) ZAdd(ctx context.Context, key string, members ...*Z) *IntCmd {
1812 const n = 2
1813 a := make([]interface{}, n+2*len(members))
1814 a[0], a[1] = "zadd", key
1815 return c.zAdd(ctx, a, n, members...)
1816}
1817
1818// Redis `ZADD key NX score member [score member ...]` command.
1819func (c cmdable) ZAddNX(ctx context.Context, key string, members ...*Z) *IntCmd {
1820 const n = 3
1821 a := make([]interface{}, n+2*len(members))
1822 a[0], a[1], a[2] = "zadd", key, "nx"
1823 return c.zAdd(ctx, a, n, members...)
1824}
1825
1826// Redis `ZADD key XX score member [score member ...]` command.
1827func (c cmdable) ZAddXX(ctx context.Context, key string, members ...*Z) *IntCmd {
1828 const n = 3
1829 a := make([]interface{}, n+2*len(members))
1830 a[0], a[1], a[2] = "zadd", key, "xx"
1831 return c.zAdd(ctx, a, n, members...)
1832}
1833
1834// Redis `ZADD key CH score member [score member ...]` command.
1835func (c cmdable) ZAddCh(ctx context.Context, key string, members ...*Z) *IntCmd {
1836 const n = 3
1837 a := make([]interface{}, n+2*len(members))
1838 a[0], a[1], a[2] = "zadd", key, "ch"
1839 return c.zAdd(ctx, a, n, members...)
1840}
1841
1842// Redis `ZADD key NX CH score member [score member ...]` command.
1843func (c cmdable) ZAddNXCh(ctx context.Context, key string, members ...*Z) *IntCmd {
1844 const n = 4
1845 a := make([]interface{}, n+2*len(members))
1846 a[0], a[1], a[2], a[3] = "zadd", key, "nx", "ch"
1847 return c.zAdd(ctx, a, n, members...)
1848}
1849
1850// Redis `ZADD key XX CH score member [score member ...]` command.
1851func (c cmdable) ZAddXXCh(ctx context.Context, key string, members ...*Z) *IntCmd {
1852 const n = 4
1853 a := make([]interface{}, n+2*len(members))
1854 a[0], a[1], a[2], a[3] = "zadd", key, "xx", "ch"
1855 return c.zAdd(ctx, a, n, members...)
1856}
1857
1858func (c cmdable) zIncr(ctx context.Context, a []interface{}, n int, members ...*Z) *FloatCmd {
1859 for i, m := range members {
1860 a[n+2*i] = m.Score
1861 a[n+2*i+1] = m.Member
1862 }
1863 cmd := NewFloatCmd(ctx, a...)
1864 _ = c(ctx, cmd)
1865 return cmd
1866}
1867
1868// Redis `ZADD key INCR score member` command.
1869func (c cmdable) ZIncr(ctx context.Context, key string, member *Z) *FloatCmd {
1870 const n = 3
1871 a := make([]interface{}, n+2)
1872 a[0], a[1], a[2] = "zadd", key, "incr"
1873 return c.zIncr(ctx, a, n, member)
1874}
1875
1876// Redis `ZADD key NX INCR score member` command.
1877func (c cmdable) ZIncrNX(ctx context.Context, key string, member *Z) *FloatCmd {
1878 const n = 4
1879 a := make([]interface{}, n+2)
1880 a[0], a[1], a[2], a[3] = "zadd", key, "incr", "nx"
1881 return c.zIncr(ctx, a, n, member)
1882}
1883
1884// Redis `ZADD key XX INCR score member` command.
1885func (c cmdable) ZIncrXX(ctx context.Context, key string, member *Z) *FloatCmd {
1886 const n = 4
1887 a := make([]interface{}, n+2)
1888 a[0], a[1], a[2], a[3] = "zadd", key, "incr", "xx"
1889 return c.zIncr(ctx, a, n, member)
1890}
1891
1892func (c cmdable) ZCard(ctx context.Context, key string) *IntCmd {
1893 cmd := NewIntCmd(ctx, "zcard", key)
1894 _ = c(ctx, cmd)
1895 return cmd
1896}
1897
1898func (c cmdable) ZCount(ctx context.Context, key, min, max string) *IntCmd {
1899 cmd := NewIntCmd(ctx, "zcount", key, min, max)
1900 _ = c(ctx, cmd)
1901 return cmd
1902}
1903
1904func (c cmdable) ZLexCount(ctx context.Context, key, min, max string) *IntCmd {
1905 cmd := NewIntCmd(ctx, "zlexcount", key, min, max)
1906 _ = c(ctx, cmd)
1907 return cmd
1908}
1909
1910func (c cmdable) ZIncrBy(ctx context.Context, key string, increment float64, member string) *FloatCmd {
1911 cmd := NewFloatCmd(ctx, "zincrby", key, increment, member)
1912 _ = c(ctx, cmd)
1913 return cmd
1914}
1915
1916func (c cmdable) ZInterStore(ctx context.Context, destination string, store *ZStore) *IntCmd {
1917 args := make([]interface{}, 3+len(store.Keys))
1918 args[0] = "zinterstore"
1919 args[1] = destination
1920 args[2] = len(store.Keys)
1921 for i, key := range store.Keys {
1922 args[3+i] = key
1923 }
1924 if len(store.Weights) > 0 {
1925 args = append(args, "weights")
1926 for _, weight := range store.Weights {
1927 args = append(args, weight)
1928 }
1929 }
1930 if store.Aggregate != "" {
1931 args = append(args, "aggregate", store.Aggregate)
1932 }
1933 cmd := NewIntCmd(ctx, args...)
1934 cmd.setFirstKeyPos(3)
1935 _ = c(ctx, cmd)
1936 return cmd
1937}
1938
1939func (c cmdable) ZPopMax(ctx context.Context, key string, count ...int64) *ZSliceCmd {
1940 args := []interface{}{
1941 "zpopmax",
1942 key,
1943 }
1944
1945 switch len(count) {
1946 case 0:
1947 break
1948 case 1:
1949 args = append(args, count[0])
1950 default:
1951 panic("too many arguments")
1952 }
1953
1954 cmd := NewZSliceCmd(ctx, args...)
1955 _ = c(ctx, cmd)
1956 return cmd
1957}
1958
1959func (c cmdable) ZPopMin(ctx context.Context, key string, count ...int64) *ZSliceCmd {
1960 args := []interface{}{
1961 "zpopmin",
1962 key,
1963 }
1964
1965 switch len(count) {
1966 case 0:
1967 break
1968 case 1:
1969 args = append(args, count[0])
1970 default:
1971 panic("too many arguments")
1972 }
1973
1974 cmd := NewZSliceCmd(ctx, args...)
1975 _ = c(ctx, cmd)
1976 return cmd
1977}
1978
1979func (c cmdable) zRange(ctx context.Context, key string, start, stop int64, withScores bool) *StringSliceCmd {
1980 args := []interface{}{
1981 "zrange",
1982 key,
1983 start,
1984 stop,
1985 }
1986 if withScores {
1987 args = append(args, "withscores")
1988 }
1989 cmd := NewStringSliceCmd(ctx, args...)
1990 _ = c(ctx, cmd)
1991 return cmd
1992}
1993
1994func (c cmdable) ZRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd {
1995 return c.zRange(ctx, key, start, stop, false)
1996}
1997
1998func (c cmdable) ZRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd {
1999 cmd := NewZSliceCmd(ctx, "zrange", key, start, stop, "withscores")
2000 _ = c(ctx, cmd)
2001 return cmd
2002}
2003
2004type ZRangeBy struct {
2005 Min, Max string
2006 Offset, Count int64
2007}
2008
2009func (c cmdable) zRangeBy(ctx context.Context, zcmd, key string, opt *ZRangeBy, withScores bool) *StringSliceCmd {
2010 args := []interface{}{zcmd, key, opt.Min, opt.Max}
2011 if withScores {
2012 args = append(args, "withscores")
2013 }
2014 if opt.Offset != 0 || opt.Count != 0 {
2015 args = append(
2016 args,
2017 "limit",
2018 opt.Offset,
2019 opt.Count,
2020 )
2021 }
2022 cmd := NewStringSliceCmd(ctx, args...)
2023 _ = c(ctx, cmd)
2024 return cmd
2025}
2026
2027func (c cmdable) ZRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd {
2028 return c.zRangeBy(ctx, "zrangebyscore", key, opt, false)
2029}
2030
2031func (c cmdable) ZRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd {
2032 return c.zRangeBy(ctx, "zrangebylex", key, opt, false)
2033}
2034
2035func (c cmdable) ZRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd {
2036 args := []interface{}{"zrangebyscore", key, opt.Min, opt.Max, "withscores"}
2037 if opt.Offset != 0 || opt.Count != 0 {
2038 args = append(
2039 args,
2040 "limit",
2041 opt.Offset,
2042 opt.Count,
2043 )
2044 }
2045 cmd := NewZSliceCmd(ctx, args...)
2046 _ = c(ctx, cmd)
2047 return cmd
2048}
2049
2050func (c cmdable) ZRank(ctx context.Context, key, member string) *IntCmd {
2051 cmd := NewIntCmd(ctx, "zrank", key, member)
2052 _ = c(ctx, cmd)
2053 return cmd
2054}
2055
2056func (c cmdable) ZRem(ctx context.Context, key string, members ...interface{}) *IntCmd {
2057 args := make([]interface{}, 2, 2+len(members))
2058 args[0] = "zrem"
2059 args[1] = key
2060 args = appendArgs(args, members)
2061 cmd := NewIntCmd(ctx, args...)
2062 _ = c(ctx, cmd)
2063 return cmd
2064}
2065
2066func (c cmdable) ZRemRangeByRank(ctx context.Context, key string, start, stop int64) *IntCmd {
2067 cmd := NewIntCmd(
2068 ctx,
2069 "zremrangebyrank",
2070 key,
2071 start,
2072 stop,
2073 )
2074 _ = c(ctx, cmd)
2075 return cmd
2076}
2077
2078func (c cmdable) ZRemRangeByScore(ctx context.Context, key, min, max string) *IntCmd {
2079 cmd := NewIntCmd(ctx, "zremrangebyscore", key, min, max)
2080 _ = c(ctx, cmd)
2081 return cmd
2082}
2083
2084func (c cmdable) ZRemRangeByLex(ctx context.Context, key, min, max string) *IntCmd {
2085 cmd := NewIntCmd(ctx, "zremrangebylex", key, min, max)
2086 _ = c(ctx, cmd)
2087 return cmd
2088}
2089
2090func (c cmdable) ZRevRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd {
2091 cmd := NewStringSliceCmd(ctx, "zrevrange", key, start, stop)
2092 _ = c(ctx, cmd)
2093 return cmd
2094}
2095
2096func (c cmdable) ZRevRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd {
2097 cmd := NewZSliceCmd(ctx, "zrevrange", key, start, stop, "withscores")
2098 _ = c(ctx, cmd)
2099 return cmd
2100}
2101
2102func (c cmdable) zRevRangeBy(ctx context.Context, zcmd, key string, opt *ZRangeBy) *StringSliceCmd {
2103 args := []interface{}{zcmd, key, opt.Max, opt.Min}
2104 if opt.Offset != 0 || opt.Count != 0 {
2105 args = append(
2106 args,
2107 "limit",
2108 opt.Offset,
2109 opt.Count,
2110 )
2111 }
2112 cmd := NewStringSliceCmd(ctx, args...)
2113 _ = c(ctx, cmd)
2114 return cmd
2115}
2116
2117func (c cmdable) ZRevRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd {
2118 return c.zRevRangeBy(ctx, "zrevrangebyscore", key, opt)
2119}
2120
2121func (c cmdable) ZRevRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd {
2122 return c.zRevRangeBy(ctx, "zrevrangebylex", key, opt)
2123}
2124
2125func (c cmdable) ZRevRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd {
2126 args := []interface{}{"zrevrangebyscore", key, opt.Max, opt.Min, "withscores"}
2127 if opt.Offset != 0 || opt.Count != 0 {
2128 args = append(
2129 args,
2130 "limit",
2131 opt.Offset,
2132 opt.Count,
2133 )
2134 }
2135 cmd := NewZSliceCmd(ctx, args...)
2136 _ = c(ctx, cmd)
2137 return cmd
2138}
2139
2140func (c cmdable) ZRevRank(ctx context.Context, key, member string) *IntCmd {
2141 cmd := NewIntCmd(ctx, "zrevrank", key, member)
2142 _ = c(ctx, cmd)
2143 return cmd
2144}
2145
2146func (c cmdable) ZScore(ctx context.Context, key, member string) *FloatCmd {
2147 cmd := NewFloatCmd(ctx, "zscore", key, member)
2148 _ = c(ctx, cmd)
2149 return cmd
2150}
2151
2152func (c cmdable) ZUnionStore(ctx context.Context, dest string, store *ZStore) *IntCmd {
2153 args := make([]interface{}, 3+len(store.Keys))
2154 args[0] = "zunionstore"
2155 args[1] = dest
2156 args[2] = len(store.Keys)
2157 for i, key := range store.Keys {
2158 args[3+i] = key
2159 }
2160 if len(store.Weights) > 0 {
2161 args = append(args, "weights")
2162 for _, weight := range store.Weights {
2163 args = append(args, weight)
2164 }
2165 }
2166 if store.Aggregate != "" {
2167 args = append(args, "aggregate", store.Aggregate)
2168 }
2169
2170 cmd := NewIntCmd(ctx, args...)
2171 cmd.setFirstKeyPos(3)
2172 _ = c(ctx, cmd)
2173 return cmd
2174}
2175
2176//------------------------------------------------------------------------------
2177
2178func (c cmdable) PFAdd(ctx context.Context, key string, els ...interface{}) *IntCmd {
2179 args := make([]interface{}, 2, 2+len(els))
2180 args[0] = "pfadd"
2181 args[1] = key
2182 args = appendArgs(args, els)
2183 cmd := NewIntCmd(ctx, args...)
2184 _ = c(ctx, cmd)
2185 return cmd
2186}
2187
2188func (c cmdable) PFCount(ctx context.Context, keys ...string) *IntCmd {
2189 args := make([]interface{}, 1+len(keys))
2190 args[0] = "pfcount"
2191 for i, key := range keys {
2192 args[1+i] = key
2193 }
2194 cmd := NewIntCmd(ctx, args...)
2195 _ = c(ctx, cmd)
2196 return cmd
2197}
2198
2199func (c cmdable) PFMerge(ctx context.Context, dest string, keys ...string) *StatusCmd {
2200 args := make([]interface{}, 2+len(keys))
2201 args[0] = "pfmerge"
2202 args[1] = dest
2203 for i, key := range keys {
2204 args[2+i] = key
2205 }
2206 cmd := NewStatusCmd(ctx, args...)
2207 _ = c(ctx, cmd)
2208 return cmd
2209}
2210
2211//------------------------------------------------------------------------------
2212
2213func (c cmdable) BgRewriteAOF(ctx context.Context) *StatusCmd {
2214 cmd := NewStatusCmd(ctx, "bgrewriteaof")
2215 _ = c(ctx, cmd)
2216 return cmd
2217}
2218
2219func (c cmdable) BgSave(ctx context.Context) *StatusCmd {
2220 cmd := NewStatusCmd(ctx, "bgsave")
2221 _ = c(ctx, cmd)
2222 return cmd
2223}
2224
2225func (c cmdable) ClientKill(ctx context.Context, ipPort string) *StatusCmd {
2226 cmd := NewStatusCmd(ctx, "client", "kill", ipPort)
2227 _ = c(ctx, cmd)
2228 return cmd
2229}
2230
2231// ClientKillByFilter is new style syntax, while the ClientKill is old
2232//
2233// CLIENT KILL <option> [value] ... <option> [value]
2234func (c cmdable) ClientKillByFilter(ctx context.Context, keys ...string) *IntCmd {
2235 args := make([]interface{}, 2+len(keys))
2236 args[0] = "client"
2237 args[1] = "kill"
2238 for i, key := range keys {
2239 args[2+i] = key
2240 }
2241 cmd := NewIntCmd(ctx, args...)
2242 _ = c(ctx, cmd)
2243 return cmd
2244}
2245
2246func (c cmdable) ClientList(ctx context.Context) *StringCmd {
2247 cmd := NewStringCmd(ctx, "client", "list")
2248 _ = c(ctx, cmd)
2249 return cmd
2250}
2251
2252func (c cmdable) ClientPause(ctx context.Context, dur time.Duration) *BoolCmd {
2253 cmd := NewBoolCmd(ctx, "client", "pause", formatMs(ctx, dur))
2254 _ = c(ctx, cmd)
2255 return cmd
2256}
2257
2258func (c cmdable) ClientID(ctx context.Context) *IntCmd {
2259 cmd := NewIntCmd(ctx, "client", "id")
2260 _ = c(ctx, cmd)
2261 return cmd
2262}
2263
2264func (c cmdable) ClientUnblock(ctx context.Context, id int64) *IntCmd {
2265 cmd := NewIntCmd(ctx, "client", "unblock", id)
2266 _ = c(ctx, cmd)
2267 return cmd
2268}
2269
2270func (c cmdable) ClientUnblockWithError(ctx context.Context, id int64) *IntCmd {
2271 cmd := NewIntCmd(ctx, "client", "unblock", id, "error")
2272 _ = c(ctx, cmd)
2273 return cmd
2274}
2275
2276func (c cmdable) ConfigGet(ctx context.Context, parameter string) *SliceCmd {
2277 cmd := NewSliceCmd(ctx, "config", "get", parameter)
2278 _ = c(ctx, cmd)
2279 return cmd
2280}
2281
2282func (c cmdable) ConfigResetStat(ctx context.Context) *StatusCmd {
2283 cmd := NewStatusCmd(ctx, "config", "resetstat")
2284 _ = c(ctx, cmd)
2285 return cmd
2286}
2287
2288func (c cmdable) ConfigSet(ctx context.Context, parameter, value string) *StatusCmd {
2289 cmd := NewStatusCmd(ctx, "config", "set", parameter, value)
2290 _ = c(ctx, cmd)
2291 return cmd
2292}
2293
2294func (c cmdable) ConfigRewrite(ctx context.Context) *StatusCmd {
2295 cmd := NewStatusCmd(ctx, "config", "rewrite")
2296 _ = c(ctx, cmd)
2297 return cmd
2298}
2299
2300func (c cmdable) DBSize(ctx context.Context) *IntCmd {
2301 cmd := NewIntCmd(ctx, "dbsize")
2302 _ = c(ctx, cmd)
2303 return cmd
2304}
2305
2306func (c cmdable) FlushAll(ctx context.Context) *StatusCmd {
2307 cmd := NewStatusCmd(ctx, "flushall")
2308 _ = c(ctx, cmd)
2309 return cmd
2310}
2311
2312func (c cmdable) FlushAllAsync(ctx context.Context) *StatusCmd {
2313 cmd := NewStatusCmd(ctx, "flushall", "async")
2314 _ = c(ctx, cmd)
2315 return cmd
2316}
2317
2318func (c cmdable) FlushDB(ctx context.Context) *StatusCmd {
2319 cmd := NewStatusCmd(ctx, "flushdb")
2320 _ = c(ctx, cmd)
2321 return cmd
2322}
2323
2324func (c cmdable) FlushDBAsync(ctx context.Context) *StatusCmd {
2325 cmd := NewStatusCmd(ctx, "flushdb", "async")
2326 _ = c(ctx, cmd)
2327 return cmd
2328}
2329
2330func (c cmdable) Info(ctx context.Context, section ...string) *StringCmd {
2331 args := []interface{}{"info"}
2332 if len(section) > 0 {
2333 args = append(args, section[0])
2334 }
2335 cmd := NewStringCmd(ctx, args...)
2336 _ = c(ctx, cmd)
2337 return cmd
2338}
2339
2340func (c cmdable) LastSave(ctx context.Context) *IntCmd {
2341 cmd := NewIntCmd(ctx, "lastsave")
2342 _ = c(ctx, cmd)
2343 return cmd
2344}
2345
2346func (c cmdable) Save(ctx context.Context) *StatusCmd {
2347 cmd := NewStatusCmd(ctx, "save")
2348 _ = c(ctx, cmd)
2349 return cmd
2350}
2351
2352func (c cmdable) shutdown(ctx context.Context, modifier string) *StatusCmd {
2353 var args []interface{}
2354 if modifier == "" {
2355 args = []interface{}{"shutdown"}
2356 } else {
2357 args = []interface{}{"shutdown", modifier}
2358 }
2359 cmd := NewStatusCmd(ctx, args...)
2360 _ = c(ctx, cmd)
2361 if err := cmd.Err(); err != nil {
2362 if err == io.EOF {
2363 // Server quit as expected.
2364 cmd.err = nil
2365 }
2366 } else {
2367 // Server did not quit. String reply contains the reason.
2368 cmd.err = errors.New(cmd.val)
2369 cmd.val = ""
2370 }
2371 return cmd
2372}
2373
2374func (c cmdable) Shutdown(ctx context.Context) *StatusCmd {
2375 return c.shutdown(ctx, "")
2376}
2377
2378func (c cmdable) ShutdownSave(ctx context.Context) *StatusCmd {
2379 return c.shutdown(ctx, "save")
2380}
2381
2382func (c cmdable) ShutdownNoSave(ctx context.Context) *StatusCmd {
2383 return c.shutdown(ctx, "nosave")
2384}
2385
2386func (c cmdable) SlaveOf(ctx context.Context, host, port string) *StatusCmd {
2387 cmd := NewStatusCmd(ctx, "slaveof", host, port)
2388 _ = c(ctx, cmd)
2389 return cmd
2390}
2391
2392func (c cmdable) SlowLogGet(ctx context.Context, num int64) *SlowLogCmd {
2393 cmd := NewSlowLogCmd(context.Background(), "slowlog", "get", num)
2394 _ = c(ctx, cmd)
2395 return cmd
2396}
2397
2398func (c cmdable) Sync(ctx context.Context) {
2399 panic("not implemented")
2400}
2401
2402func (c cmdable) Time(ctx context.Context) *TimeCmd {
2403 cmd := NewTimeCmd(ctx, "time")
2404 _ = c(ctx, cmd)
2405 return cmd
2406}
2407
2408func (c cmdable) DebugObject(ctx context.Context, key string) *StringCmd {
2409 cmd := NewStringCmd(ctx, "debug", "object", key)
2410 _ = c(ctx, cmd)
2411 return cmd
2412}
2413
2414func (c cmdable) ReadOnly(ctx context.Context) *StatusCmd {
2415 cmd := NewStatusCmd(ctx, "readonly")
2416 _ = c(ctx, cmd)
2417 return cmd
2418}
2419
2420func (c cmdable) ReadWrite(ctx context.Context) *StatusCmd {
2421 cmd := NewStatusCmd(ctx, "readwrite")
2422 _ = c(ctx, cmd)
2423 return cmd
2424}
2425
2426func (c cmdable) MemoryUsage(ctx context.Context, key string, samples ...int) *IntCmd {
2427 args := []interface{}{"memory", "usage", key}
2428 if len(samples) > 0 {
2429 if len(samples) != 1 {
2430 panic("MemoryUsage expects single sample count")
2431 }
2432 args = append(args, "SAMPLES", samples[0])
2433 }
2434 cmd := NewIntCmd(ctx, args...)
2435 _ = c(ctx, cmd)
2436 return cmd
2437}
2438
2439//------------------------------------------------------------------------------
2440
2441func (c cmdable) Eval(ctx context.Context, script string, keys []string, args ...interface{}) *Cmd {
2442 cmdArgs := make([]interface{}, 3+len(keys), 3+len(keys)+len(args))
2443 cmdArgs[0] = "eval"
2444 cmdArgs[1] = script
2445 cmdArgs[2] = len(keys)
2446 for i, key := range keys {
2447 cmdArgs[3+i] = key
2448 }
2449 cmdArgs = appendArgs(cmdArgs, args)
2450 cmd := NewCmd(ctx, cmdArgs...)
2451 _ = c(ctx, cmd)
2452 return cmd
2453}
2454
2455func (c cmdable) EvalSha(ctx context.Context, sha1 string, keys []string, args ...interface{}) *Cmd {
2456 cmdArgs := make([]interface{}, 3+len(keys), 3+len(keys)+len(args))
2457 cmdArgs[0] = "evalsha"
2458 cmdArgs[1] = sha1
2459 cmdArgs[2] = len(keys)
2460 for i, key := range keys {
2461 cmdArgs[3+i] = key
2462 }
2463 cmdArgs = appendArgs(cmdArgs, args)
2464 cmd := NewCmd(ctx, cmdArgs...)
2465 _ = c(ctx, cmd)
2466 return cmd
2467}
2468
2469func (c cmdable) ScriptExists(ctx context.Context, hashes ...string) *BoolSliceCmd {
2470 args := make([]interface{}, 2+len(hashes))
2471 args[0] = "script"
2472 args[1] = "exists"
2473 for i, hash := range hashes {
2474 args[2+i] = hash
2475 }
2476 cmd := NewBoolSliceCmd(ctx, args...)
2477 _ = c(ctx, cmd)
2478 return cmd
2479}
2480
2481func (c cmdable) ScriptFlush(ctx context.Context) *StatusCmd {
2482 cmd := NewStatusCmd(ctx, "script", "flush")
2483 _ = c(ctx, cmd)
2484 return cmd
2485}
2486
2487func (c cmdable) ScriptKill(ctx context.Context) *StatusCmd {
2488 cmd := NewStatusCmd(ctx, "script", "kill")
2489 _ = c(ctx, cmd)
2490 return cmd
2491}
2492
2493func (c cmdable) ScriptLoad(ctx context.Context, script string) *StringCmd {
2494 cmd := NewStringCmd(ctx, "script", "load", script)
2495 _ = c(ctx, cmd)
2496 return cmd
2497}
2498
2499//------------------------------------------------------------------------------
2500
2501// Publish posts the message to the channel.
2502func (c cmdable) Publish(ctx context.Context, channel string, message interface{}) *IntCmd {
2503 cmd := NewIntCmd(ctx, "publish", channel, message)
2504 _ = c(ctx, cmd)
2505 return cmd
2506}
2507
2508func (c cmdable) PubSubChannels(ctx context.Context, pattern string) *StringSliceCmd {
2509 args := []interface{}{"pubsub", "channels"}
2510 if pattern != "*" {
2511 args = append(args, pattern)
2512 }
2513 cmd := NewStringSliceCmd(ctx, args...)
2514 _ = c(ctx, cmd)
2515 return cmd
2516}
2517
2518func (c cmdable) PubSubNumSub(ctx context.Context, channels ...string) *StringIntMapCmd {
2519 args := make([]interface{}, 2+len(channels))
2520 args[0] = "pubsub"
2521 args[1] = "numsub"
2522 for i, channel := range channels {
2523 args[2+i] = channel
2524 }
2525 cmd := NewStringIntMapCmd(ctx, args...)
2526 _ = c(ctx, cmd)
2527 return cmd
2528}
2529
2530func (c cmdable) PubSubNumPat(ctx context.Context) *IntCmd {
2531 cmd := NewIntCmd(ctx, "pubsub", "numpat")
2532 _ = c(ctx, cmd)
2533 return cmd
2534}
2535
2536//------------------------------------------------------------------------------
2537
2538func (c cmdable) ClusterSlots(ctx context.Context) *ClusterSlotsCmd {
2539 cmd := NewClusterSlotsCmd(ctx, "cluster", "slots")
2540 _ = c(ctx, cmd)
2541 return cmd
2542}
2543
2544func (c cmdable) ClusterNodes(ctx context.Context) *StringCmd {
2545 cmd := NewStringCmd(ctx, "cluster", "nodes")
2546 _ = c(ctx, cmd)
2547 return cmd
2548}
2549
2550func (c cmdable) ClusterMeet(ctx context.Context, host, port string) *StatusCmd {
2551 cmd := NewStatusCmd(ctx, "cluster", "meet", host, port)
2552 _ = c(ctx, cmd)
2553 return cmd
2554}
2555
2556func (c cmdable) ClusterForget(ctx context.Context, nodeID string) *StatusCmd {
2557 cmd := NewStatusCmd(ctx, "cluster", "forget", nodeID)
2558 _ = c(ctx, cmd)
2559 return cmd
2560}
2561
2562func (c cmdable) ClusterReplicate(ctx context.Context, nodeID string) *StatusCmd {
2563 cmd := NewStatusCmd(ctx, "cluster", "replicate", nodeID)
2564 _ = c(ctx, cmd)
2565 return cmd
2566}
2567
2568func (c cmdable) ClusterResetSoft(ctx context.Context) *StatusCmd {
2569 cmd := NewStatusCmd(ctx, "cluster", "reset", "soft")
2570 _ = c(ctx, cmd)
2571 return cmd
2572}
2573
2574func (c cmdable) ClusterResetHard(ctx context.Context) *StatusCmd {
2575 cmd := NewStatusCmd(ctx, "cluster", "reset", "hard")
2576 _ = c(ctx, cmd)
2577 return cmd
2578}
2579
2580func (c cmdable) ClusterInfo(ctx context.Context) *StringCmd {
2581 cmd := NewStringCmd(ctx, "cluster", "info")
2582 _ = c(ctx, cmd)
2583 return cmd
2584}
2585
2586func (c cmdable) ClusterKeySlot(ctx context.Context, key string) *IntCmd {
2587 cmd := NewIntCmd(ctx, "cluster", "keyslot", key)
2588 _ = c(ctx, cmd)
2589 return cmd
2590}
2591
2592func (c cmdable) ClusterGetKeysInSlot(ctx context.Context, slot int, count int) *StringSliceCmd {
2593 cmd := NewStringSliceCmd(ctx, "cluster", "getkeysinslot", slot, count)
2594 _ = c(ctx, cmd)
2595 return cmd
2596}
2597
2598func (c cmdable) ClusterCountFailureReports(ctx context.Context, nodeID string) *IntCmd {
2599 cmd := NewIntCmd(ctx, "cluster", "count-failure-reports", nodeID)
2600 _ = c(ctx, cmd)
2601 return cmd
2602}
2603
2604func (c cmdable) ClusterCountKeysInSlot(ctx context.Context, slot int) *IntCmd {
2605 cmd := NewIntCmd(ctx, "cluster", "countkeysinslot", slot)
2606 _ = c(ctx, cmd)
2607 return cmd
2608}
2609
2610func (c cmdable) ClusterDelSlots(ctx context.Context, slots ...int) *StatusCmd {
2611 args := make([]interface{}, 2+len(slots))
2612 args[0] = "cluster"
2613 args[1] = "delslots"
2614 for i, slot := range slots {
2615 args[2+i] = slot
2616 }
2617 cmd := NewStatusCmd(ctx, args...)
2618 _ = c(ctx, cmd)
2619 return cmd
2620}
2621
2622func (c cmdable) ClusterDelSlotsRange(ctx context.Context, min, max int) *StatusCmd {
2623 size := max - min + 1
2624 slots := make([]int, size)
2625 for i := 0; i < size; i++ {
2626 slots[i] = min + i
2627 }
2628 return c.ClusterDelSlots(ctx, slots...)
2629}
2630
2631func (c cmdable) ClusterSaveConfig(ctx context.Context) *StatusCmd {
2632 cmd := NewStatusCmd(ctx, "cluster", "saveconfig")
2633 _ = c(ctx, cmd)
2634 return cmd
2635}
2636
2637func (c cmdable) ClusterSlaves(ctx context.Context, nodeID string) *StringSliceCmd {
2638 cmd := NewStringSliceCmd(ctx, "cluster", "slaves", nodeID)
2639 _ = c(ctx, cmd)
2640 return cmd
2641}
2642
2643func (c cmdable) ClusterFailover(ctx context.Context) *StatusCmd {
2644 cmd := NewStatusCmd(ctx, "cluster", "failover")
2645 _ = c(ctx, cmd)
2646 return cmd
2647}
2648
2649func (c cmdable) ClusterAddSlots(ctx context.Context, slots ...int) *StatusCmd {
2650 args := make([]interface{}, 2+len(slots))
2651 args[0] = "cluster"
2652 args[1] = "addslots"
2653 for i, num := range slots {
2654 args[2+i] = num
2655 }
2656 cmd := NewStatusCmd(ctx, args...)
2657 _ = c(ctx, cmd)
2658 return cmd
2659}
2660
2661func (c cmdable) ClusterAddSlotsRange(ctx context.Context, min, max int) *StatusCmd {
2662 size := max - min + 1
2663 slots := make([]int, size)
2664 for i := 0; i < size; i++ {
2665 slots[i] = min + i
2666 }
2667 return c.ClusterAddSlots(ctx, slots...)
2668}
2669
2670//------------------------------------------------------------------------------
2671
2672func (c cmdable) GeoAdd(ctx context.Context, key string, geoLocation ...*GeoLocation) *IntCmd {
2673 args := make([]interface{}, 2+3*len(geoLocation))
2674 args[0] = "geoadd"
2675 args[1] = key
2676 for i, eachLoc := range geoLocation {
2677 args[2+3*i] = eachLoc.Longitude
2678 args[2+3*i+1] = eachLoc.Latitude
2679 args[2+3*i+2] = eachLoc.Name
2680 }
2681 cmd := NewIntCmd(ctx, args...)
2682 _ = c(ctx, cmd)
2683 return cmd
2684}
2685
2686// GeoRadius is a read-only GEORADIUS_RO command.
2687func (c cmdable) GeoRadius(
2688 ctx context.Context, key string, longitude, latitude float64, query *GeoRadiusQuery,
2689) *GeoLocationCmd {
2690 cmd := NewGeoLocationCmd(ctx, query, "georadius_ro", key, longitude, latitude)
2691 if query.Store != "" || query.StoreDist != "" {
2692 cmd.SetErr(errors.New("GeoRadius does not support Store or StoreDist"))
2693 return cmd
2694 }
2695 _ = c(ctx, cmd)
2696 return cmd
2697}
2698
2699// GeoRadiusStore is a writing GEORADIUS command.
2700func (c cmdable) GeoRadiusStore(
2701 ctx context.Context, key string, longitude, latitude float64, query *GeoRadiusQuery,
2702) *IntCmd {
2703 args := geoLocationArgs(query, "georadius", key, longitude, latitude)
2704 cmd := NewIntCmd(ctx, args...)
2705 if query.Store == "" && query.StoreDist == "" {
2706 cmd.SetErr(errors.New("GeoRadiusStore requires Store or StoreDist"))
2707 return cmd
2708 }
2709 _ = c(ctx, cmd)
2710 return cmd
2711}
2712
2713// GeoRadius is a read-only GEORADIUSBYMEMBER_RO command.
2714func (c cmdable) GeoRadiusByMember(
2715 ctx context.Context, key, member string, query *GeoRadiusQuery,
2716) *GeoLocationCmd {
2717 cmd := NewGeoLocationCmd(ctx, query, "georadiusbymember_ro", key, member)
2718 if query.Store != "" || query.StoreDist != "" {
2719 cmd.SetErr(errors.New("GeoRadiusByMember does not support Store or StoreDist"))
2720 return cmd
2721 }
2722 _ = c(ctx, cmd)
2723 return cmd
2724}
2725
2726// GeoRadiusByMemberStore is a writing GEORADIUSBYMEMBER command.
2727func (c cmdable) GeoRadiusByMemberStore(
2728 ctx context.Context, key, member string, query *GeoRadiusQuery,
2729) *IntCmd {
2730 args := geoLocationArgs(query, "georadiusbymember", key, member)
2731 cmd := NewIntCmd(ctx, args...)
2732 if query.Store == "" && query.StoreDist == "" {
2733 cmd.SetErr(errors.New("GeoRadiusByMemberStore requires Store or StoreDist"))
2734 return cmd
2735 }
2736 _ = c(ctx, cmd)
2737 return cmd
2738}
2739
2740func (c cmdable) GeoDist(
2741 ctx context.Context, key string, member1, member2, unit string,
2742) *FloatCmd {
2743 if unit == "" {
2744 unit = "km"
2745 }
2746 cmd := NewFloatCmd(ctx, "geodist", key, member1, member2, unit)
2747 _ = c(ctx, cmd)
2748 return cmd
2749}
2750
2751func (c cmdable) GeoHash(ctx context.Context, key string, members ...string) *StringSliceCmd {
2752 args := make([]interface{}, 2+len(members))
2753 args[0] = "geohash"
2754 args[1] = key
2755 for i, member := range members {
2756 args[2+i] = member
2757 }
2758 cmd := NewStringSliceCmd(ctx, args...)
2759 _ = c(ctx, cmd)
2760 return cmd
2761}
2762
2763func (c cmdable) GeoPos(ctx context.Context, key string, members ...string) *GeoPosCmd {
2764 args := make([]interface{}, 2+len(members))
2765 args[0] = "geopos"
2766 args[1] = key
2767 for i, member := range members {
2768 args[2+i] = member
2769 }
2770 cmd := NewGeoPosCmd(ctx, args...)
2771 _ = c(ctx, cmd)
2772 return cmd
2773}