blob: bbfe089df166db9c1dda980a957a16d9c6f9ae44 [file] [log] [blame]
Naveen Sampath04696f72022-06-13 15:19:14 +05301package 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 a Redis KEEPTTL option to keep existing TTL, it requires your redis-server version >= 6.0,
13// otherwise you will receive an error: (error) ERR syntax error.
14// For example:
15//
16// rdb.Set(ctx, key, value, redis.KeepTTL)
17const KeepTTL = -1
18
19func usePrecise(dur time.Duration) bool {
20 return dur < time.Second || dur%time.Second != 0
21}
22
23func formatMs(ctx context.Context, dur time.Duration) int64 {
24 if dur > 0 && dur < time.Millisecond {
25 internal.Logger.Printf(
26 ctx,
27 "specified duration is %s, but minimal supported value is %s - truncating to 1ms",
28 dur, time.Millisecond,
29 )
30 return 1
31 }
32 return int64(dur / time.Millisecond)
33}
34
35func formatSec(ctx context.Context, dur time.Duration) int64 {
36 if dur > 0 && dur < time.Second {
37 internal.Logger.Printf(
38 ctx,
39 "specified duration is %s, but minimal supported value is %s - truncating to 1s",
40 dur, time.Second,
41 )
42 return 1
43 }
44 return int64(dur / time.Second)
45}
46
47func appendArgs(dst, src []interface{}) []interface{} {
48 if len(src) == 1 {
49 return appendArg(dst, src[0])
50 }
51
52 dst = append(dst, src...)
53 return dst
54}
55
56func appendArg(dst []interface{}, arg interface{}) []interface{} {
57 switch arg := arg.(type) {
58 case []string:
59 for _, s := range arg {
60 dst = append(dst, s)
61 }
62 return dst
63 case []interface{}:
64 dst = append(dst, arg...)
65 return dst
66 case map[string]interface{}:
67 for k, v := range arg {
68 dst = append(dst, k, v)
69 }
70 return dst
71 case map[string]string:
72 for k, v := range arg {
73 dst = append(dst, k, v)
74 }
75 return dst
76 default:
77 return append(dst, arg)
78 }
79}
80
81type Cmdable interface {
82 Pipeline() Pipeliner
83 Pipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error)
84
85 TxPipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error)
86 TxPipeline() Pipeliner
87
88 Command(ctx context.Context) *CommandsInfoCmd
89 ClientGetName(ctx context.Context) *StringCmd
90 Echo(ctx context.Context, message interface{}) *StringCmd
91 Ping(ctx context.Context) *StatusCmd
92 Quit(ctx context.Context) *StatusCmd
93 Del(ctx context.Context, keys ...string) *IntCmd
94 Unlink(ctx context.Context, keys ...string) *IntCmd
95 Dump(ctx context.Context, key string) *StringCmd
96 Exists(ctx context.Context, keys ...string) *IntCmd
97 Expire(ctx context.Context, key string, expiration time.Duration) *BoolCmd
98 ExpireAt(ctx context.Context, key string, tm time.Time) *BoolCmd
99 ExpireNX(ctx context.Context, key string, expiration time.Duration) *BoolCmd
100 ExpireXX(ctx context.Context, key string, expiration time.Duration) *BoolCmd
101 ExpireGT(ctx context.Context, key string, expiration time.Duration) *BoolCmd
102 ExpireLT(ctx context.Context, key string, expiration time.Duration) *BoolCmd
103 Keys(ctx context.Context, pattern string) *StringSliceCmd
104 Migrate(ctx context.Context, host, port, key string, db int, timeout time.Duration) *StatusCmd
105 Move(ctx context.Context, key string, db int) *BoolCmd
106 ObjectRefCount(ctx context.Context, key string) *IntCmd
107 ObjectEncoding(ctx context.Context, key string) *StringCmd
108 ObjectIdleTime(ctx context.Context, key string) *DurationCmd
109 Persist(ctx context.Context, key string) *BoolCmd
110 PExpire(ctx context.Context, key string, expiration time.Duration) *BoolCmd
111 PExpireAt(ctx context.Context, key string, tm time.Time) *BoolCmd
112 PTTL(ctx context.Context, key string) *DurationCmd
113 RandomKey(ctx context.Context) *StringCmd
114 Rename(ctx context.Context, key, newkey string) *StatusCmd
115 RenameNX(ctx context.Context, key, newkey string) *BoolCmd
116 Restore(ctx context.Context, key string, ttl time.Duration, value string) *StatusCmd
117 RestoreReplace(ctx context.Context, key string, ttl time.Duration, value string) *StatusCmd
118 Sort(ctx context.Context, key string, sort *Sort) *StringSliceCmd
119 SortStore(ctx context.Context, key, store string, sort *Sort) *IntCmd
120 SortInterfaces(ctx context.Context, key string, sort *Sort) *SliceCmd
121 Touch(ctx context.Context, keys ...string) *IntCmd
122 TTL(ctx context.Context, key string) *DurationCmd
123 Type(ctx context.Context, key string) *StatusCmd
124 Append(ctx context.Context, key, value string) *IntCmd
125 Decr(ctx context.Context, key string) *IntCmd
126 DecrBy(ctx context.Context, key string, decrement int64) *IntCmd
127 Get(ctx context.Context, key string) *StringCmd
128 GetRange(ctx context.Context, key string, start, end int64) *StringCmd
129 GetSet(ctx context.Context, key string, value interface{}) *StringCmd
130 GetEx(ctx context.Context, key string, expiration time.Duration) *StringCmd
131 GetDel(ctx context.Context, key string) *StringCmd
132 Incr(ctx context.Context, key string) *IntCmd
133 IncrBy(ctx context.Context, key string, value int64) *IntCmd
134 IncrByFloat(ctx context.Context, key string, value float64) *FloatCmd
135 MGet(ctx context.Context, keys ...string) *SliceCmd
136 MSet(ctx context.Context, values ...interface{}) *StatusCmd
137 MSetNX(ctx context.Context, values ...interface{}) *BoolCmd
138 Set(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd
139 SetArgs(ctx context.Context, key string, value interface{}, a SetArgs) *StatusCmd
140 // TODO: rename to SetEx
141 SetEX(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd
142 SetNX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd
143 SetXX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd
144 SetRange(ctx context.Context, key string, offset int64, value string) *IntCmd
145 StrLen(ctx context.Context, key string) *IntCmd
146 Copy(ctx context.Context, sourceKey string, destKey string, db int, replace bool) *IntCmd
147
148 GetBit(ctx context.Context, key string, offset int64) *IntCmd
149 SetBit(ctx context.Context, key string, offset int64, value int) *IntCmd
150 BitCount(ctx context.Context, key string, bitCount *BitCount) *IntCmd
151 BitOpAnd(ctx context.Context, destKey string, keys ...string) *IntCmd
152 BitOpOr(ctx context.Context, destKey string, keys ...string) *IntCmd
153 BitOpXor(ctx context.Context, destKey string, keys ...string) *IntCmd
154 BitOpNot(ctx context.Context, destKey string, key string) *IntCmd
155 BitPos(ctx context.Context, key string, bit int64, pos ...int64) *IntCmd
156 BitField(ctx context.Context, key string, args ...interface{}) *IntSliceCmd
157
158 Scan(ctx context.Context, cursor uint64, match string, count int64) *ScanCmd
159 ScanType(ctx context.Context, cursor uint64, match string, count int64, keyType string) *ScanCmd
160 SScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd
161 HScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd
162 ZScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd
163
164 HDel(ctx context.Context, key string, fields ...string) *IntCmd
165 HExists(ctx context.Context, key, field string) *BoolCmd
166 HGet(ctx context.Context, key, field string) *StringCmd
167 HGetAll(ctx context.Context, key string) *StringStringMapCmd
168 HIncrBy(ctx context.Context, key, field string, incr int64) *IntCmd
169 HIncrByFloat(ctx context.Context, key, field string, incr float64) *FloatCmd
170 HKeys(ctx context.Context, key string) *StringSliceCmd
171 HLen(ctx context.Context, key string) *IntCmd
172 HMGet(ctx context.Context, key string, fields ...string) *SliceCmd
173 HSet(ctx context.Context, key string, values ...interface{}) *IntCmd
174 HMSet(ctx context.Context, key string, values ...interface{}) *BoolCmd
175 HSetNX(ctx context.Context, key, field string, value interface{}) *BoolCmd
176 HVals(ctx context.Context, key string) *StringSliceCmd
177 HRandField(ctx context.Context, key string, count int, withValues bool) *StringSliceCmd
178
179 BLPop(ctx context.Context, timeout time.Duration, keys ...string) *StringSliceCmd
180 BRPop(ctx context.Context, timeout time.Duration, keys ...string) *StringSliceCmd
181 BRPopLPush(ctx context.Context, source, destination string, timeout time.Duration) *StringCmd
182 LIndex(ctx context.Context, key string, index int64) *StringCmd
183 LInsert(ctx context.Context, key, op string, pivot, value interface{}) *IntCmd
184 LInsertBefore(ctx context.Context, key string, pivot, value interface{}) *IntCmd
185 LInsertAfter(ctx context.Context, key string, pivot, value interface{}) *IntCmd
186 LLen(ctx context.Context, key string) *IntCmd
187 LPop(ctx context.Context, key string) *StringCmd
188 LPopCount(ctx context.Context, key string, count int) *StringSliceCmd
189 LPos(ctx context.Context, key string, value string, args LPosArgs) *IntCmd
190 LPosCount(ctx context.Context, key string, value string, count int64, args LPosArgs) *IntSliceCmd
191 LPush(ctx context.Context, key string, values ...interface{}) *IntCmd
192 LPushX(ctx context.Context, key string, values ...interface{}) *IntCmd
193 LRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd
194 LRem(ctx context.Context, key string, count int64, value interface{}) *IntCmd
195 LSet(ctx context.Context, key string, index int64, value interface{}) *StatusCmd
196 LTrim(ctx context.Context, key string, start, stop int64) *StatusCmd
197 RPop(ctx context.Context, key string) *StringCmd
198 RPopCount(ctx context.Context, key string, count int) *StringSliceCmd
199 RPopLPush(ctx context.Context, source, destination string) *StringCmd
200 RPush(ctx context.Context, key string, values ...interface{}) *IntCmd
201 RPushX(ctx context.Context, key string, values ...interface{}) *IntCmd
202 LMove(ctx context.Context, source, destination, srcpos, destpos string) *StringCmd
203 BLMove(ctx context.Context, source, destination, srcpos, destpos string, timeout time.Duration) *StringCmd
204
205 SAdd(ctx context.Context, key string, members ...interface{}) *IntCmd
206 SCard(ctx context.Context, key string) *IntCmd
207 SDiff(ctx context.Context, keys ...string) *StringSliceCmd
208 SDiffStore(ctx context.Context, destination string, keys ...string) *IntCmd
209 SInter(ctx context.Context, keys ...string) *StringSliceCmd
210 SInterStore(ctx context.Context, destination string, keys ...string) *IntCmd
211 SIsMember(ctx context.Context, key string, member interface{}) *BoolCmd
212 SMIsMember(ctx context.Context, key string, members ...interface{}) *BoolSliceCmd
213 SMembers(ctx context.Context, key string) *StringSliceCmd
214 SMembersMap(ctx context.Context, key string) *StringStructMapCmd
215 SMove(ctx context.Context, source, destination string, member interface{}) *BoolCmd
216 SPop(ctx context.Context, key string) *StringCmd
217 SPopN(ctx context.Context, key string, count int64) *StringSliceCmd
218 SRandMember(ctx context.Context, key string) *StringCmd
219 SRandMemberN(ctx context.Context, key string, count int64) *StringSliceCmd
220 SRem(ctx context.Context, key string, members ...interface{}) *IntCmd
221 SUnion(ctx context.Context, keys ...string) *StringSliceCmd
222 SUnionStore(ctx context.Context, destination string, keys ...string) *IntCmd
223
224 XAdd(ctx context.Context, a *XAddArgs) *StringCmd
225 XDel(ctx context.Context, stream string, ids ...string) *IntCmd
226 XLen(ctx context.Context, stream string) *IntCmd
227 XRange(ctx context.Context, stream, start, stop string) *XMessageSliceCmd
228 XRangeN(ctx context.Context, stream, start, stop string, count int64) *XMessageSliceCmd
229 XRevRange(ctx context.Context, stream string, start, stop string) *XMessageSliceCmd
230 XRevRangeN(ctx context.Context, stream string, start, stop string, count int64) *XMessageSliceCmd
231 XRead(ctx context.Context, a *XReadArgs) *XStreamSliceCmd
232 XReadStreams(ctx context.Context, streams ...string) *XStreamSliceCmd
233 XGroupCreate(ctx context.Context, stream, group, start string) *StatusCmd
234 XGroupCreateMkStream(ctx context.Context, stream, group, start string) *StatusCmd
235 XGroupSetID(ctx context.Context, stream, group, start string) *StatusCmd
236 XGroupDestroy(ctx context.Context, stream, group string) *IntCmd
237 XGroupCreateConsumer(ctx context.Context, stream, group, consumer string) *IntCmd
238 XGroupDelConsumer(ctx context.Context, stream, group, consumer string) *IntCmd
239 XReadGroup(ctx context.Context, a *XReadGroupArgs) *XStreamSliceCmd
240 XAck(ctx context.Context, stream, group string, ids ...string) *IntCmd
241 XPending(ctx context.Context, stream, group string) *XPendingCmd
242 XPendingExt(ctx context.Context, a *XPendingExtArgs) *XPendingExtCmd
243 XClaim(ctx context.Context, a *XClaimArgs) *XMessageSliceCmd
244 XClaimJustID(ctx context.Context, a *XClaimArgs) *StringSliceCmd
245 XAutoClaim(ctx context.Context, a *XAutoClaimArgs) *XAutoClaimCmd
246 XAutoClaimJustID(ctx context.Context, a *XAutoClaimArgs) *XAutoClaimJustIDCmd
247
248 // TODO: XTrim and XTrimApprox remove in v9.
249 XTrim(ctx context.Context, key string, maxLen int64) *IntCmd
250 XTrimApprox(ctx context.Context, key string, maxLen int64) *IntCmd
251 XTrimMaxLen(ctx context.Context, key string, maxLen int64) *IntCmd
252 XTrimMaxLenApprox(ctx context.Context, key string, maxLen, limit int64) *IntCmd
253 XTrimMinID(ctx context.Context, key string, minID string) *IntCmd
254 XTrimMinIDApprox(ctx context.Context, key string, minID string, limit int64) *IntCmd
255 XInfoGroups(ctx context.Context, key string) *XInfoGroupsCmd
256 XInfoStream(ctx context.Context, key string) *XInfoStreamCmd
257 XInfoStreamFull(ctx context.Context, key string, count int) *XInfoStreamFullCmd
258 XInfoConsumers(ctx context.Context, key string, group string) *XInfoConsumersCmd
259
260 BZPopMax(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd
261 BZPopMin(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd
262
263 // TODO: remove
264 // ZAddCh
265 // ZIncr
266 // ZAddNXCh
267 // ZAddXXCh
268 // ZIncrNX
269 // ZIncrXX
270 // in v9.
271 // use ZAddArgs and ZAddArgsIncr.
272
273 ZAdd(ctx context.Context, key string, members ...*Z) *IntCmd
274 ZAddNX(ctx context.Context, key string, members ...*Z) *IntCmd
275 ZAddXX(ctx context.Context, key string, members ...*Z) *IntCmd
276 ZAddCh(ctx context.Context, key string, members ...*Z) *IntCmd
277 ZAddNXCh(ctx context.Context, key string, members ...*Z) *IntCmd
278 ZAddXXCh(ctx context.Context, key string, members ...*Z) *IntCmd
279 ZAddArgs(ctx context.Context, key string, args ZAddArgs) *IntCmd
280 ZAddArgsIncr(ctx context.Context, key string, args ZAddArgs) *FloatCmd
281 ZIncr(ctx context.Context, key string, member *Z) *FloatCmd
282 ZIncrNX(ctx context.Context, key string, member *Z) *FloatCmd
283 ZIncrXX(ctx context.Context, key string, member *Z) *FloatCmd
284 ZCard(ctx context.Context, key string) *IntCmd
285 ZCount(ctx context.Context, key, min, max string) *IntCmd
286 ZLexCount(ctx context.Context, key, min, max string) *IntCmd
287 ZIncrBy(ctx context.Context, key string, increment float64, member string) *FloatCmd
288 ZInter(ctx context.Context, store *ZStore) *StringSliceCmd
289 ZInterWithScores(ctx context.Context, store *ZStore) *ZSliceCmd
290 ZInterStore(ctx context.Context, destination string, store *ZStore) *IntCmd
291 ZMScore(ctx context.Context, key string, members ...string) *FloatSliceCmd
292 ZPopMax(ctx context.Context, key string, count ...int64) *ZSliceCmd
293 ZPopMin(ctx context.Context, key string, count ...int64) *ZSliceCmd
294 ZRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd
295 ZRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd
296 ZRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd
297 ZRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd
298 ZRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd
299 ZRangeArgs(ctx context.Context, z ZRangeArgs) *StringSliceCmd
300 ZRangeArgsWithScores(ctx context.Context, z ZRangeArgs) *ZSliceCmd
301 ZRangeStore(ctx context.Context, dst string, z ZRangeArgs) *IntCmd
302 ZRank(ctx context.Context, key, member string) *IntCmd
303 ZRem(ctx context.Context, key string, members ...interface{}) *IntCmd
304 ZRemRangeByRank(ctx context.Context, key string, start, stop int64) *IntCmd
305 ZRemRangeByScore(ctx context.Context, key, min, max string) *IntCmd
306 ZRemRangeByLex(ctx context.Context, key, min, max string) *IntCmd
307 ZRevRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd
308 ZRevRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd
309 ZRevRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd
310 ZRevRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd
311 ZRevRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd
312 ZRevRank(ctx context.Context, key, member string) *IntCmd
313 ZScore(ctx context.Context, key, member string) *FloatCmd
314 ZUnionStore(ctx context.Context, dest string, store *ZStore) *IntCmd
315 ZUnion(ctx context.Context, store ZStore) *StringSliceCmd
316 ZUnionWithScores(ctx context.Context, store ZStore) *ZSliceCmd
317 ZRandMember(ctx context.Context, key string, count int, withScores bool) *StringSliceCmd
318 ZDiff(ctx context.Context, keys ...string) *StringSliceCmd
319 ZDiffWithScores(ctx context.Context, keys ...string) *ZSliceCmd
320 ZDiffStore(ctx context.Context, destination string, keys ...string) *IntCmd
321
322 PFAdd(ctx context.Context, key string, els ...interface{}) *IntCmd
323 PFCount(ctx context.Context, keys ...string) *IntCmd
324 PFMerge(ctx context.Context, dest string, keys ...string) *StatusCmd
325
326 BgRewriteAOF(ctx context.Context) *StatusCmd
327 BgSave(ctx context.Context) *StatusCmd
328 ClientKill(ctx context.Context, ipPort string) *StatusCmd
329 ClientKillByFilter(ctx context.Context, keys ...string) *IntCmd
330 ClientList(ctx context.Context) *StringCmd
331 ClientPause(ctx context.Context, dur time.Duration) *BoolCmd
332 ClientID(ctx context.Context) *IntCmd
333 ConfigGet(ctx context.Context, parameter string) *SliceCmd
334 ConfigResetStat(ctx context.Context) *StatusCmd
335 ConfigSet(ctx context.Context, parameter, value string) *StatusCmd
336 ConfigRewrite(ctx context.Context) *StatusCmd
337 DBSize(ctx context.Context) *IntCmd
338 FlushAll(ctx context.Context) *StatusCmd
339 FlushAllAsync(ctx context.Context) *StatusCmd
340 FlushDB(ctx context.Context) *StatusCmd
341 FlushDBAsync(ctx context.Context) *StatusCmd
342 Info(ctx context.Context, section ...string) *StringCmd
343 LastSave(ctx context.Context) *IntCmd
344 Save(ctx context.Context) *StatusCmd
345 Shutdown(ctx context.Context) *StatusCmd
346 ShutdownSave(ctx context.Context) *StatusCmd
347 ShutdownNoSave(ctx context.Context) *StatusCmd
348 SlaveOf(ctx context.Context, host, port string) *StatusCmd
349 Time(ctx context.Context) *TimeCmd
350 DebugObject(ctx context.Context, key string) *StringCmd
351 ReadOnly(ctx context.Context) *StatusCmd
352 ReadWrite(ctx context.Context) *StatusCmd
353 MemoryUsage(ctx context.Context, key string, samples ...int) *IntCmd
354
355 Eval(ctx context.Context, script string, keys []string, args ...interface{}) *Cmd
356 EvalSha(ctx context.Context, sha1 string, keys []string, args ...interface{}) *Cmd
357 ScriptExists(ctx context.Context, hashes ...string) *BoolSliceCmd
358 ScriptFlush(ctx context.Context) *StatusCmd
359 ScriptKill(ctx context.Context) *StatusCmd
360 ScriptLoad(ctx context.Context, script string) *StringCmd
361
362 Publish(ctx context.Context, channel string, message interface{}) *IntCmd
363 PubSubChannels(ctx context.Context, pattern string) *StringSliceCmd
364 PubSubNumSub(ctx context.Context, channels ...string) *StringIntMapCmd
365 PubSubNumPat(ctx context.Context) *IntCmd
366
367 ClusterSlots(ctx context.Context) *ClusterSlotsCmd
368 ClusterNodes(ctx context.Context) *StringCmd
369 ClusterMeet(ctx context.Context, host, port string) *StatusCmd
370 ClusterForget(ctx context.Context, nodeID string) *StatusCmd
371 ClusterReplicate(ctx context.Context, nodeID string) *StatusCmd
372 ClusterResetSoft(ctx context.Context) *StatusCmd
373 ClusterResetHard(ctx context.Context) *StatusCmd
374 ClusterInfo(ctx context.Context) *StringCmd
375 ClusterKeySlot(ctx context.Context, key string) *IntCmd
376 ClusterGetKeysInSlot(ctx context.Context, slot int, count int) *StringSliceCmd
377 ClusterCountFailureReports(ctx context.Context, nodeID string) *IntCmd
378 ClusterCountKeysInSlot(ctx context.Context, slot int) *IntCmd
379 ClusterDelSlots(ctx context.Context, slots ...int) *StatusCmd
380 ClusterDelSlotsRange(ctx context.Context, min, max int) *StatusCmd
381 ClusterSaveConfig(ctx context.Context) *StatusCmd
382 ClusterSlaves(ctx context.Context, nodeID string) *StringSliceCmd
383 ClusterFailover(ctx context.Context) *StatusCmd
384 ClusterAddSlots(ctx context.Context, slots ...int) *StatusCmd
385 ClusterAddSlotsRange(ctx context.Context, min, max int) *StatusCmd
386
387 GeoAdd(ctx context.Context, key string, geoLocation ...*GeoLocation) *IntCmd
388 GeoPos(ctx context.Context, key string, members ...string) *GeoPosCmd
389 GeoRadius(ctx context.Context, key string, longitude, latitude float64, query *GeoRadiusQuery) *GeoLocationCmd
390 GeoRadiusStore(ctx context.Context, key string, longitude, latitude float64, query *GeoRadiusQuery) *IntCmd
391 GeoRadiusByMember(ctx context.Context, key, member string, query *GeoRadiusQuery) *GeoLocationCmd
392 GeoRadiusByMemberStore(ctx context.Context, key, member string, query *GeoRadiusQuery) *IntCmd
393 GeoSearch(ctx context.Context, key string, q *GeoSearchQuery) *StringSliceCmd
394 GeoSearchLocation(ctx context.Context, key string, q *GeoSearchLocationQuery) *GeoSearchLocationCmd
395 GeoSearchStore(ctx context.Context, key, store string, q *GeoSearchStoreQuery) *IntCmd
396 GeoDist(ctx context.Context, key string, member1, member2, unit string) *FloatCmd
397 GeoHash(ctx context.Context, key string, members ...string) *StringSliceCmd
398}
399
400type StatefulCmdable interface {
401 Cmdable
402 Auth(ctx context.Context, password string) *StatusCmd
403 AuthACL(ctx context.Context, username, password string) *StatusCmd
404 Select(ctx context.Context, index int) *StatusCmd
405 SwapDB(ctx context.Context, index1, index2 int) *StatusCmd
406 ClientSetName(ctx context.Context, name string) *BoolCmd
407}
408
409var (
410 _ Cmdable = (*Client)(nil)
411 _ Cmdable = (*Tx)(nil)
412 _ Cmdable = (*Ring)(nil)
413 _ Cmdable = (*ClusterClient)(nil)
414)
415
416type cmdable func(ctx context.Context, cmd Cmder) error
417
418type statefulCmdable func(ctx context.Context, cmd Cmder) error
419
420//------------------------------------------------------------------------------
421
422func (c statefulCmdable) Auth(ctx context.Context, password string) *StatusCmd {
423 cmd := NewStatusCmd(ctx, "auth", password)
424 _ = c(ctx, cmd)
425 return cmd
426}
427
428// AuthACL Perform an AUTH command, using the given user and pass.
429// Should be used to authenticate the current connection with one of the connections defined in the ACL list
430// when connecting to a Redis 6.0 instance, or greater, that is using the Redis ACL system.
431func (c statefulCmdable) AuthACL(ctx context.Context, username, password string) *StatusCmd {
432 cmd := NewStatusCmd(ctx, "auth", username, password)
433 _ = c(ctx, cmd)
434 return cmd
435}
436
437func (c cmdable) Wait(ctx context.Context, numSlaves int, timeout time.Duration) *IntCmd {
438 cmd := NewIntCmd(ctx, "wait", numSlaves, int(timeout/time.Millisecond))
439 cmd.setReadTimeout(timeout)
440 _ = c(ctx, cmd)
441 return cmd
442}
443
444func (c statefulCmdable) Select(ctx context.Context, index int) *StatusCmd {
445 cmd := NewStatusCmd(ctx, "select", index)
446 _ = c(ctx, cmd)
447 return cmd
448}
449
450func (c statefulCmdable) SwapDB(ctx context.Context, index1, index2 int) *StatusCmd {
451 cmd := NewStatusCmd(ctx, "swapdb", index1, index2)
452 _ = c(ctx, cmd)
453 return cmd
454}
455
456// ClientSetName assigns a name to the connection.
457func (c statefulCmdable) ClientSetName(ctx context.Context, name string) *BoolCmd {
458 cmd := NewBoolCmd(ctx, "client", "setname", name)
459 _ = c(ctx, cmd)
460 return cmd
461}
462
463//------------------------------------------------------------------------------
464
465func (c cmdable) Command(ctx context.Context) *CommandsInfoCmd {
466 cmd := NewCommandsInfoCmd(ctx, "command")
467 _ = c(ctx, cmd)
468 return cmd
469}
470
471// ClientGetName returns the name of the connection.
472func (c cmdable) ClientGetName(ctx context.Context) *StringCmd {
473 cmd := NewStringCmd(ctx, "client", "getname")
474 _ = c(ctx, cmd)
475 return cmd
476}
477
478func (c cmdable) Echo(ctx context.Context, message interface{}) *StringCmd {
479 cmd := NewStringCmd(ctx, "echo", message)
480 _ = c(ctx, cmd)
481 return cmd
482}
483
484func (c cmdable) Ping(ctx context.Context) *StatusCmd {
485 cmd := NewStatusCmd(ctx, "ping")
486 _ = c(ctx, cmd)
487 return cmd
488}
489
490func (c cmdable) Quit(_ context.Context) *StatusCmd {
491 panic("not implemented")
492}
493
494func (c cmdable) Del(ctx context.Context, keys ...string) *IntCmd {
495 args := make([]interface{}, 1+len(keys))
496 args[0] = "del"
497 for i, key := range keys {
498 args[1+i] = key
499 }
500 cmd := NewIntCmd(ctx, args...)
501 _ = c(ctx, cmd)
502 return cmd
503}
504
505func (c cmdable) Unlink(ctx context.Context, keys ...string) *IntCmd {
506 args := make([]interface{}, 1+len(keys))
507 args[0] = "unlink"
508 for i, key := range keys {
509 args[1+i] = key
510 }
511 cmd := NewIntCmd(ctx, args...)
512 _ = c(ctx, cmd)
513 return cmd
514}
515
516func (c cmdable) Dump(ctx context.Context, key string) *StringCmd {
517 cmd := NewStringCmd(ctx, "dump", key)
518 _ = c(ctx, cmd)
519 return cmd
520}
521
522func (c cmdable) Exists(ctx context.Context, keys ...string) *IntCmd {
523 args := make([]interface{}, 1+len(keys))
524 args[0] = "exists"
525 for i, key := range keys {
526 args[1+i] = key
527 }
528 cmd := NewIntCmd(ctx, args...)
529 _ = c(ctx, cmd)
530 return cmd
531}
532
533func (c cmdable) Expire(ctx context.Context, key string, expiration time.Duration) *BoolCmd {
534 return c.expire(ctx, key, expiration, "")
535}
536
537func (c cmdable) ExpireNX(ctx context.Context, key string, expiration time.Duration) *BoolCmd {
538 return c.expire(ctx, key, expiration, "NX")
539}
540
541func (c cmdable) ExpireXX(ctx context.Context, key string, expiration time.Duration) *BoolCmd {
542 return c.expire(ctx, key, expiration, "XX")
543}
544
545func (c cmdable) ExpireGT(ctx context.Context, key string, expiration time.Duration) *BoolCmd {
546 return c.expire(ctx, key, expiration, "GT")
547}
548
549func (c cmdable) ExpireLT(ctx context.Context, key string, expiration time.Duration) *BoolCmd {
550 return c.expire(ctx, key, expiration, "LT")
551}
552
553func (c cmdable) expire(
554 ctx context.Context, key string, expiration time.Duration, mode string,
555) *BoolCmd {
556 args := make([]interface{}, 3, 4)
557 args[0] = "expire"
558 args[1] = key
559 args[2] = formatSec(ctx, expiration)
560 if mode != "" {
561 args = append(args, mode)
562 }
563
564 cmd := NewBoolCmd(ctx, args...)
565 _ = c(ctx, cmd)
566 return cmd
567}
568
569func (c cmdable) ExpireAt(ctx context.Context, key string, tm time.Time) *BoolCmd {
570 cmd := NewBoolCmd(ctx, "expireat", key, tm.Unix())
571 _ = c(ctx, cmd)
572 return cmd
573}
574
575func (c cmdable) Keys(ctx context.Context, pattern string) *StringSliceCmd {
576 cmd := NewStringSliceCmd(ctx, "keys", pattern)
577 _ = c(ctx, cmd)
578 return cmd
579}
580
581func (c cmdable) Migrate(ctx context.Context, host, port, key string, db int, timeout time.Duration) *StatusCmd {
582 cmd := NewStatusCmd(
583 ctx,
584 "migrate",
585 host,
586 port,
587 key,
588 db,
589 formatMs(ctx, timeout),
590 )
591 cmd.setReadTimeout(timeout)
592 _ = c(ctx, cmd)
593 return cmd
594}
595
596func (c cmdable) Move(ctx context.Context, key string, db int) *BoolCmd {
597 cmd := NewBoolCmd(ctx, "move", key, db)
598 _ = c(ctx, cmd)
599 return cmd
600}
601
602func (c cmdable) ObjectRefCount(ctx context.Context, key string) *IntCmd {
603 cmd := NewIntCmd(ctx, "object", "refcount", key)
604 _ = c(ctx, cmd)
605 return cmd
606}
607
608func (c cmdable) ObjectEncoding(ctx context.Context, key string) *StringCmd {
609 cmd := NewStringCmd(ctx, "object", "encoding", key)
610 _ = c(ctx, cmd)
611 return cmd
612}
613
614func (c cmdable) ObjectIdleTime(ctx context.Context, key string) *DurationCmd {
615 cmd := NewDurationCmd(ctx, time.Second, "object", "idletime", key)
616 _ = c(ctx, cmd)
617 return cmd
618}
619
620func (c cmdable) Persist(ctx context.Context, key string) *BoolCmd {
621 cmd := NewBoolCmd(ctx, "persist", key)
622 _ = c(ctx, cmd)
623 return cmd
624}
625
626func (c cmdable) PExpire(ctx context.Context, key string, expiration time.Duration) *BoolCmd {
627 cmd := NewBoolCmd(ctx, "pexpire", key, formatMs(ctx, expiration))
628 _ = c(ctx, cmd)
629 return cmd
630}
631
632func (c cmdable) PExpireAt(ctx context.Context, key string, tm time.Time) *BoolCmd {
633 cmd := NewBoolCmd(
634 ctx,
635 "pexpireat",
636 key,
637 tm.UnixNano()/int64(time.Millisecond),
638 )
639 _ = c(ctx, cmd)
640 return cmd
641}
642
643func (c cmdable) PTTL(ctx context.Context, key string) *DurationCmd {
644 cmd := NewDurationCmd(ctx, time.Millisecond, "pttl", key)
645 _ = c(ctx, cmd)
646 return cmd
647}
648
649func (c cmdable) RandomKey(ctx context.Context) *StringCmd {
650 cmd := NewStringCmd(ctx, "randomkey")
651 _ = c(ctx, cmd)
652 return cmd
653}
654
655func (c cmdable) Rename(ctx context.Context, key, newkey string) *StatusCmd {
656 cmd := NewStatusCmd(ctx, "rename", key, newkey)
657 _ = c(ctx, cmd)
658 return cmd
659}
660
661func (c cmdable) RenameNX(ctx context.Context, key, newkey string) *BoolCmd {
662 cmd := NewBoolCmd(ctx, "renamenx", key, newkey)
663 _ = c(ctx, cmd)
664 return cmd
665}
666
667func (c cmdable) Restore(ctx context.Context, key string, ttl time.Duration, value string) *StatusCmd {
668 cmd := NewStatusCmd(
669 ctx,
670 "restore",
671 key,
672 formatMs(ctx, ttl),
673 value,
674 )
675 _ = c(ctx, cmd)
676 return cmd
677}
678
679func (c cmdable) RestoreReplace(ctx context.Context, key string, ttl time.Duration, value string) *StatusCmd {
680 cmd := NewStatusCmd(
681 ctx,
682 "restore",
683 key,
684 formatMs(ctx, ttl),
685 value,
686 "replace",
687 )
688 _ = c(ctx, cmd)
689 return cmd
690}
691
692type Sort struct {
693 By string
694 Offset, Count int64
695 Get []string
696 Order string
697 Alpha bool
698}
699
700func (sort *Sort) args(key string) []interface{} {
701 args := []interface{}{"sort", key}
702 if sort.By != "" {
703 args = append(args, "by", sort.By)
704 }
705 if sort.Offset != 0 || sort.Count != 0 {
706 args = append(args, "limit", sort.Offset, sort.Count)
707 }
708 for _, get := range sort.Get {
709 args = append(args, "get", get)
710 }
711 if sort.Order != "" {
712 args = append(args, sort.Order)
713 }
714 if sort.Alpha {
715 args = append(args, "alpha")
716 }
717 return args
718}
719
720func (c cmdable) Sort(ctx context.Context, key string, sort *Sort) *StringSliceCmd {
721 cmd := NewStringSliceCmd(ctx, sort.args(key)...)
722 _ = c(ctx, cmd)
723 return cmd
724}
725
726func (c cmdable) SortStore(ctx context.Context, key, store string, sort *Sort) *IntCmd {
727 args := sort.args(key)
728 if store != "" {
729 args = append(args, "store", store)
730 }
731 cmd := NewIntCmd(ctx, args...)
732 _ = c(ctx, cmd)
733 return cmd
734}
735
736func (c cmdable) SortInterfaces(ctx context.Context, key string, sort *Sort) *SliceCmd {
737 cmd := NewSliceCmd(ctx, sort.args(key)...)
738 _ = c(ctx, cmd)
739 return cmd
740}
741
742func (c cmdable) Touch(ctx context.Context, keys ...string) *IntCmd {
743 args := make([]interface{}, len(keys)+1)
744 args[0] = "touch"
745 for i, key := range keys {
746 args[i+1] = key
747 }
748 cmd := NewIntCmd(ctx, args...)
749 _ = c(ctx, cmd)
750 return cmd
751}
752
753func (c cmdable) TTL(ctx context.Context, key string) *DurationCmd {
754 cmd := NewDurationCmd(ctx, time.Second, "ttl", key)
755 _ = c(ctx, cmd)
756 return cmd
757}
758
759func (c cmdable) Type(ctx context.Context, key string) *StatusCmd {
760 cmd := NewStatusCmd(ctx, "type", key)
761 _ = c(ctx, cmd)
762 return cmd
763}
764
765func (c cmdable) Append(ctx context.Context, key, value string) *IntCmd {
766 cmd := NewIntCmd(ctx, "append", key, value)
767 _ = c(ctx, cmd)
768 return cmd
769}
770
771func (c cmdable) Decr(ctx context.Context, key string) *IntCmd {
772 cmd := NewIntCmd(ctx, "decr", key)
773 _ = c(ctx, cmd)
774 return cmd
775}
776
777func (c cmdable) DecrBy(ctx context.Context, key string, decrement int64) *IntCmd {
778 cmd := NewIntCmd(ctx, "decrby", key, decrement)
779 _ = c(ctx, cmd)
780 return cmd
781}
782
783// Get Redis `GET key` command. It returns redis.Nil error when key does not exist.
784func (c cmdable) Get(ctx context.Context, key string) *StringCmd {
785 cmd := NewStringCmd(ctx, "get", key)
786 _ = c(ctx, cmd)
787 return cmd
788}
789
790func (c cmdable) GetRange(ctx context.Context, key string, start, end int64) *StringCmd {
791 cmd := NewStringCmd(ctx, "getrange", key, start, end)
792 _ = c(ctx, cmd)
793 return cmd
794}
795
796func (c cmdable) GetSet(ctx context.Context, key string, value interface{}) *StringCmd {
797 cmd := NewStringCmd(ctx, "getset", key, value)
798 _ = c(ctx, cmd)
799 return cmd
800}
801
802// GetEx An expiration of zero removes the TTL associated with the key (i.e. GETEX key persist).
803// Requires Redis >= 6.2.0.
804func (c cmdable) GetEx(ctx context.Context, key string, expiration time.Duration) *StringCmd {
805 args := make([]interface{}, 0, 4)
806 args = append(args, "getex", key)
807 if expiration > 0 {
808 if usePrecise(expiration) {
809 args = append(args, "px", formatMs(ctx, expiration))
810 } else {
811 args = append(args, "ex", formatSec(ctx, expiration))
812 }
813 } else if expiration == 0 {
814 args = append(args, "persist")
815 }
816
817 cmd := NewStringCmd(ctx, args...)
818 _ = c(ctx, cmd)
819 return cmd
820}
821
822// GetDel redis-server version >= 6.2.0.
823func (c cmdable) GetDel(ctx context.Context, key string) *StringCmd {
824 cmd := NewStringCmd(ctx, "getdel", key)
825 _ = c(ctx, cmd)
826 return cmd
827}
828
829func (c cmdable) Incr(ctx context.Context, key string) *IntCmd {
830 cmd := NewIntCmd(ctx, "incr", key)
831 _ = c(ctx, cmd)
832 return cmd
833}
834
835func (c cmdable) IncrBy(ctx context.Context, key string, value int64) *IntCmd {
836 cmd := NewIntCmd(ctx, "incrby", key, value)
837 _ = c(ctx, cmd)
838 return cmd
839}
840
841func (c cmdable) IncrByFloat(ctx context.Context, key string, value float64) *FloatCmd {
842 cmd := NewFloatCmd(ctx, "incrbyfloat", key, value)
843 _ = c(ctx, cmd)
844 return cmd
845}
846
847func (c cmdable) MGet(ctx context.Context, keys ...string) *SliceCmd {
848 args := make([]interface{}, 1+len(keys))
849 args[0] = "mget"
850 for i, key := range keys {
851 args[1+i] = key
852 }
853 cmd := NewSliceCmd(ctx, args...)
854 _ = c(ctx, cmd)
855 return cmd
856}
857
858// MSet is like Set but accepts multiple values:
859// - MSet("key1", "value1", "key2", "value2")
860// - MSet([]string{"key1", "value1", "key2", "value2"})
861// - MSet(map[string]interface{}{"key1": "value1", "key2": "value2"})
862func (c cmdable) MSet(ctx context.Context, values ...interface{}) *StatusCmd {
863 args := make([]interface{}, 1, 1+len(values))
864 args[0] = "mset"
865 args = appendArgs(args, values)
866 cmd := NewStatusCmd(ctx, args...)
867 _ = c(ctx, cmd)
868 return cmd
869}
870
871// MSetNX is like SetNX but accepts multiple values:
872// - MSetNX("key1", "value1", "key2", "value2")
873// - MSetNX([]string{"key1", "value1", "key2", "value2"})
874// - MSetNX(map[string]interface{}{"key1": "value1", "key2": "value2"})
875func (c cmdable) MSetNX(ctx context.Context, values ...interface{}) *BoolCmd {
876 args := make([]interface{}, 1, 1+len(values))
877 args[0] = "msetnx"
878 args = appendArgs(args, values)
879 cmd := NewBoolCmd(ctx, args...)
880 _ = c(ctx, cmd)
881 return cmd
882}
883
884// Set Redis `SET key value [expiration]` command.
885// Use expiration for `SETEX`-like behavior.
886//
887// Zero expiration means the key has no expiration time.
888// KeepTTL is a Redis KEEPTTL option to keep existing TTL, it requires your redis-server version >= 6.0,
889// otherwise you will receive an error: (error) ERR syntax error.
890func (c cmdable) Set(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd {
891 args := make([]interface{}, 3, 5)
892 args[0] = "set"
893 args[1] = key
894 args[2] = value
895 if expiration > 0 {
896 if usePrecise(expiration) {
897 args = append(args, "px", formatMs(ctx, expiration))
898 } else {
899 args = append(args, "ex", formatSec(ctx, expiration))
900 }
901 } else if expiration == KeepTTL {
902 args = append(args, "keepttl")
903 }
904
905 cmd := NewStatusCmd(ctx, args...)
906 _ = c(ctx, cmd)
907 return cmd
908}
909
910// SetArgs provides arguments for the SetArgs function.
911type SetArgs struct {
912 // Mode can be `NX` or `XX` or empty.
913 Mode string
914
915 // Zero `TTL` or `Expiration` means that the key has no expiration time.
916 TTL time.Duration
917 ExpireAt time.Time
918
919 // When Get is true, the command returns the old value stored at key, or nil when key did not exist.
920 Get bool
921
922 // KeepTTL is a Redis KEEPTTL option to keep existing TTL, it requires your redis-server version >= 6.0,
923 // otherwise you will receive an error: (error) ERR syntax error.
924 KeepTTL bool
925}
926
927// SetArgs supports all the options that the SET command supports.
928// It is the alternative to the Set function when you want
929// to have more control over the options.
930func (c cmdable) SetArgs(ctx context.Context, key string, value interface{}, a SetArgs) *StatusCmd {
931 args := []interface{}{"set", key, value}
932
933 if a.KeepTTL {
934 args = append(args, "keepttl")
935 }
936
937 if !a.ExpireAt.IsZero() {
938 args = append(args, "exat", a.ExpireAt.Unix())
939 }
940 if a.TTL > 0 {
941 if usePrecise(a.TTL) {
942 args = append(args, "px", formatMs(ctx, a.TTL))
943 } else {
944 args = append(args, "ex", formatSec(ctx, a.TTL))
945 }
946 }
947
948 if a.Mode != "" {
949 args = append(args, a.Mode)
950 }
951
952 if a.Get {
953 args = append(args, "get")
954 }
955
956 cmd := NewStatusCmd(ctx, args...)
957 _ = c(ctx, cmd)
958 return cmd
959}
960
961// SetEX Redis `SETEX key expiration value` command.
962func (c cmdable) SetEX(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd {
963 cmd := NewStatusCmd(ctx, "setex", key, formatSec(ctx, expiration), value)
964 _ = c(ctx, cmd)
965 return cmd
966}
967
968// SetNX Redis `SET key value [expiration] NX` command.
969//
970// Zero expiration means the key has no expiration time.
971// KeepTTL is a Redis KEEPTTL option to keep existing TTL, it requires your redis-server version >= 6.0,
972// otherwise you will receive an error: (error) ERR syntax error.
973func (c cmdable) SetNX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd {
974 var cmd *BoolCmd
975 switch expiration {
976 case 0:
977 // Use old `SETNX` to support old Redis versions.
978 cmd = NewBoolCmd(ctx, "setnx", key, value)
979 case KeepTTL:
980 cmd = NewBoolCmd(ctx, "set", key, value, "keepttl", "nx")
981 default:
982 if usePrecise(expiration) {
983 cmd = NewBoolCmd(ctx, "set", key, value, "px", formatMs(ctx, expiration), "nx")
984 } else {
985 cmd = NewBoolCmd(ctx, "set", key, value, "ex", formatSec(ctx, expiration), "nx")
986 }
987 }
988
989 _ = c(ctx, cmd)
990 return cmd
991}
992
993// SetXX Redis `SET key value [expiration] XX` command.
994//
995// Zero expiration means the key has no expiration time.
996// KeepTTL is a Redis KEEPTTL option to keep existing TTL, it requires your redis-server version >= 6.0,
997// otherwise you will receive an error: (error) ERR syntax error.
998func (c cmdable) SetXX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd {
999 var cmd *BoolCmd
1000 switch expiration {
1001 case 0:
1002 cmd = NewBoolCmd(ctx, "set", key, value, "xx")
1003 case KeepTTL:
1004 cmd = NewBoolCmd(ctx, "set", key, value, "keepttl", "xx")
1005 default:
1006 if usePrecise(expiration) {
1007 cmd = NewBoolCmd(ctx, "set", key, value, "px", formatMs(ctx, expiration), "xx")
1008 } else {
1009 cmd = NewBoolCmd(ctx, "set", key, value, "ex", formatSec(ctx, expiration), "xx")
1010 }
1011 }
1012
1013 _ = c(ctx, cmd)
1014 return cmd
1015}
1016
1017func (c cmdable) SetRange(ctx context.Context, key string, offset int64, value string) *IntCmd {
1018 cmd := NewIntCmd(ctx, "setrange", key, offset, value)
1019 _ = c(ctx, cmd)
1020 return cmd
1021}
1022
1023func (c cmdable) StrLen(ctx context.Context, key string) *IntCmd {
1024 cmd := NewIntCmd(ctx, "strlen", key)
1025 _ = c(ctx, cmd)
1026 return cmd
1027}
1028
1029func (c cmdable) Copy(ctx context.Context, sourceKey, destKey string, db int, replace bool) *IntCmd {
1030 args := []interface{}{"copy", sourceKey, destKey, "DB", db}
1031 if replace {
1032 args = append(args, "REPLACE")
1033 }
1034 cmd := NewIntCmd(ctx, args...)
1035 _ = c(ctx, cmd)
1036 return cmd
1037}
1038
1039//------------------------------------------------------------------------------
1040
1041func (c cmdable) GetBit(ctx context.Context, key string, offset int64) *IntCmd {
1042 cmd := NewIntCmd(ctx, "getbit", key, offset)
1043 _ = c(ctx, cmd)
1044 return cmd
1045}
1046
1047func (c cmdable) SetBit(ctx context.Context, key string, offset int64, value int) *IntCmd {
1048 cmd := NewIntCmd(
1049 ctx,
1050 "setbit",
1051 key,
1052 offset,
1053 value,
1054 )
1055 _ = c(ctx, cmd)
1056 return cmd
1057}
1058
1059type BitCount struct {
1060 Start, End int64
1061}
1062
1063func (c cmdable) BitCount(ctx context.Context, key string, bitCount *BitCount) *IntCmd {
1064 args := []interface{}{"bitcount", key}
1065 if bitCount != nil {
1066 args = append(
1067 args,
1068 bitCount.Start,
1069 bitCount.End,
1070 )
1071 }
1072 cmd := NewIntCmd(ctx, args...)
1073 _ = c(ctx, cmd)
1074 return cmd
1075}
1076
1077func (c cmdable) bitOp(ctx context.Context, op, destKey string, keys ...string) *IntCmd {
1078 args := make([]interface{}, 3+len(keys))
1079 args[0] = "bitop"
1080 args[1] = op
1081 args[2] = destKey
1082 for i, key := range keys {
1083 args[3+i] = key
1084 }
1085 cmd := NewIntCmd(ctx, args...)
1086 _ = c(ctx, cmd)
1087 return cmd
1088}
1089
1090func (c cmdable) BitOpAnd(ctx context.Context, destKey string, keys ...string) *IntCmd {
1091 return c.bitOp(ctx, "and", destKey, keys...)
1092}
1093
1094func (c cmdable) BitOpOr(ctx context.Context, destKey string, keys ...string) *IntCmd {
1095 return c.bitOp(ctx, "or", destKey, keys...)
1096}
1097
1098func (c cmdable) BitOpXor(ctx context.Context, destKey string, keys ...string) *IntCmd {
1099 return c.bitOp(ctx, "xor", destKey, keys...)
1100}
1101
1102func (c cmdable) BitOpNot(ctx context.Context, destKey string, key string) *IntCmd {
1103 return c.bitOp(ctx, "not", destKey, key)
1104}
1105
1106func (c cmdable) BitPos(ctx context.Context, key string, bit int64, pos ...int64) *IntCmd {
1107 args := make([]interface{}, 3+len(pos))
1108 args[0] = "bitpos"
1109 args[1] = key
1110 args[2] = bit
1111 switch len(pos) {
1112 case 0:
1113 case 1:
1114 args[3] = pos[0]
1115 case 2:
1116 args[3] = pos[0]
1117 args[4] = pos[1]
1118 default:
1119 panic("too many arguments")
1120 }
1121 cmd := NewIntCmd(ctx, args...)
1122 _ = c(ctx, cmd)
1123 return cmd
1124}
1125
1126func (c cmdable) BitField(ctx context.Context, key string, args ...interface{}) *IntSliceCmd {
1127 a := make([]interface{}, 0, 2+len(args))
1128 a = append(a, "bitfield")
1129 a = append(a, key)
1130 a = append(a, args...)
1131 cmd := NewIntSliceCmd(ctx, a...)
1132 _ = c(ctx, cmd)
1133 return cmd
1134}
1135
1136//------------------------------------------------------------------------------
1137
1138func (c cmdable) Scan(ctx context.Context, cursor uint64, match string, count int64) *ScanCmd {
1139 args := []interface{}{"scan", cursor}
1140 if match != "" {
1141 args = append(args, "match", match)
1142 }
1143 if count > 0 {
1144 args = append(args, "count", count)
1145 }
1146 cmd := NewScanCmd(ctx, c, args...)
1147 _ = c(ctx, cmd)
1148 return cmd
1149}
1150
1151func (c cmdable) ScanType(ctx context.Context, cursor uint64, match string, count int64, keyType string) *ScanCmd {
1152 args := []interface{}{"scan", cursor}
1153 if match != "" {
1154 args = append(args, "match", match)
1155 }
1156 if count > 0 {
1157 args = append(args, "count", count)
1158 }
1159 if keyType != "" {
1160 args = append(args, "type", keyType)
1161 }
1162 cmd := NewScanCmd(ctx, c, args...)
1163 _ = c(ctx, cmd)
1164 return cmd
1165}
1166
1167func (c cmdable) SScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd {
1168 args := []interface{}{"sscan", key, cursor}
1169 if match != "" {
1170 args = append(args, "match", match)
1171 }
1172 if count > 0 {
1173 args = append(args, "count", count)
1174 }
1175 cmd := NewScanCmd(ctx, c, args...)
1176 _ = c(ctx, cmd)
1177 return cmd
1178}
1179
1180func (c cmdable) HScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd {
1181 args := []interface{}{"hscan", key, cursor}
1182 if match != "" {
1183 args = append(args, "match", match)
1184 }
1185 if count > 0 {
1186 args = append(args, "count", count)
1187 }
1188 cmd := NewScanCmd(ctx, c, args...)
1189 _ = c(ctx, cmd)
1190 return cmd
1191}
1192
1193func (c cmdable) ZScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd {
1194 args := []interface{}{"zscan", key, cursor}
1195 if match != "" {
1196 args = append(args, "match", match)
1197 }
1198 if count > 0 {
1199 args = append(args, "count", count)
1200 }
1201 cmd := NewScanCmd(ctx, c, args...)
1202 _ = c(ctx, cmd)
1203 return cmd
1204}
1205
1206//------------------------------------------------------------------------------
1207
1208func (c cmdable) HDel(ctx context.Context, key string, fields ...string) *IntCmd {
1209 args := make([]interface{}, 2+len(fields))
1210 args[0] = "hdel"
1211 args[1] = key
1212 for i, field := range fields {
1213 args[2+i] = field
1214 }
1215 cmd := NewIntCmd(ctx, args...)
1216 _ = c(ctx, cmd)
1217 return cmd
1218}
1219
1220func (c cmdable) HExists(ctx context.Context, key, field string) *BoolCmd {
1221 cmd := NewBoolCmd(ctx, "hexists", key, field)
1222 _ = c(ctx, cmd)
1223 return cmd
1224}
1225
1226func (c cmdable) HGet(ctx context.Context, key, field string) *StringCmd {
1227 cmd := NewStringCmd(ctx, "hget", key, field)
1228 _ = c(ctx, cmd)
1229 return cmd
1230}
1231
1232func (c cmdable) HGetAll(ctx context.Context, key string) *StringStringMapCmd {
1233 cmd := NewStringStringMapCmd(ctx, "hgetall", key)
1234 _ = c(ctx, cmd)
1235 return cmd
1236}
1237
1238func (c cmdable) HIncrBy(ctx context.Context, key, field string, incr int64) *IntCmd {
1239 cmd := NewIntCmd(ctx, "hincrby", key, field, incr)
1240 _ = c(ctx, cmd)
1241 return cmd
1242}
1243
1244func (c cmdable) HIncrByFloat(ctx context.Context, key, field string, incr float64) *FloatCmd {
1245 cmd := NewFloatCmd(ctx, "hincrbyfloat", key, field, incr)
1246 _ = c(ctx, cmd)
1247 return cmd
1248}
1249
1250func (c cmdable) HKeys(ctx context.Context, key string) *StringSliceCmd {
1251 cmd := NewStringSliceCmd(ctx, "hkeys", key)
1252 _ = c(ctx, cmd)
1253 return cmd
1254}
1255
1256func (c cmdable) HLen(ctx context.Context, key string) *IntCmd {
1257 cmd := NewIntCmd(ctx, "hlen", key)
1258 _ = c(ctx, cmd)
1259 return cmd
1260}
1261
1262// HMGet returns the values for the specified fields in the hash stored at key.
1263// It returns an interface{} to distinguish between empty string and nil value.
1264func (c cmdable) HMGet(ctx context.Context, key string, fields ...string) *SliceCmd {
1265 args := make([]interface{}, 2+len(fields))
1266 args[0] = "hmget"
1267 args[1] = key
1268 for i, field := range fields {
1269 args[2+i] = field
1270 }
1271 cmd := NewSliceCmd(ctx, args...)
1272 _ = c(ctx, cmd)
1273 return cmd
1274}
1275
1276// HSet accepts values in following formats:
1277// - HSet("myhash", "key1", "value1", "key2", "value2")
1278// - HSet("myhash", []string{"key1", "value1", "key2", "value2"})
1279// - HSet("myhash", map[string]interface{}{"key1": "value1", "key2": "value2"})
1280//
1281// Note that it requires Redis v4 for multiple field/value pairs support.
1282func (c cmdable) HSet(ctx context.Context, key string, values ...interface{}) *IntCmd {
1283 args := make([]interface{}, 2, 2+len(values))
1284 args[0] = "hset"
1285 args[1] = key
1286 args = appendArgs(args, values)
1287 cmd := NewIntCmd(ctx, args...)
1288 _ = c(ctx, cmd)
1289 return cmd
1290}
1291
1292// HMSet is a deprecated version of HSet left for compatibility with Redis 3.
1293func (c cmdable) HMSet(ctx context.Context, key string, values ...interface{}) *BoolCmd {
1294 args := make([]interface{}, 2, 2+len(values))
1295 args[0] = "hmset"
1296 args[1] = key
1297 args = appendArgs(args, values)
1298 cmd := NewBoolCmd(ctx, args...)
1299 _ = c(ctx, cmd)
1300 return cmd
1301}
1302
1303func (c cmdable) HSetNX(ctx context.Context, key, field string, value interface{}) *BoolCmd {
1304 cmd := NewBoolCmd(ctx, "hsetnx", key, field, value)
1305 _ = c(ctx, cmd)
1306 return cmd
1307}
1308
1309func (c cmdable) HVals(ctx context.Context, key string) *StringSliceCmd {
1310 cmd := NewStringSliceCmd(ctx, "hvals", key)
1311 _ = c(ctx, cmd)
1312 return cmd
1313}
1314
1315// HRandField redis-server version >= 6.2.0.
1316func (c cmdable) HRandField(ctx context.Context, key string, count int, withValues bool) *StringSliceCmd {
1317 args := make([]interface{}, 0, 4)
1318
1319 // Although count=0 is meaningless, redis accepts count=0.
1320 args = append(args, "hrandfield", key, count)
1321 if withValues {
1322 args = append(args, "withvalues")
1323 }
1324
1325 cmd := NewStringSliceCmd(ctx, args...)
1326 _ = c(ctx, cmd)
1327 return cmd
1328}
1329
1330//------------------------------------------------------------------------------
1331
1332func (c cmdable) BLPop(ctx context.Context, timeout time.Duration, keys ...string) *StringSliceCmd {
1333 args := make([]interface{}, 1+len(keys)+1)
1334 args[0] = "blpop"
1335 for i, key := range keys {
1336 args[1+i] = key
1337 }
1338 args[len(args)-1] = formatSec(ctx, timeout)
1339 cmd := NewStringSliceCmd(ctx, args...)
1340 cmd.setReadTimeout(timeout)
1341 _ = c(ctx, cmd)
1342 return cmd
1343}
1344
1345func (c cmdable) BRPop(ctx context.Context, timeout time.Duration, keys ...string) *StringSliceCmd {
1346 args := make([]interface{}, 1+len(keys)+1)
1347 args[0] = "brpop"
1348 for i, key := range keys {
1349 args[1+i] = key
1350 }
1351 args[len(keys)+1] = formatSec(ctx, timeout)
1352 cmd := NewStringSliceCmd(ctx, args...)
1353 cmd.setReadTimeout(timeout)
1354 _ = c(ctx, cmd)
1355 return cmd
1356}
1357
1358func (c cmdable) BRPopLPush(ctx context.Context, source, destination string, timeout time.Duration) *StringCmd {
1359 cmd := NewStringCmd(
1360 ctx,
1361 "brpoplpush",
1362 source,
1363 destination,
1364 formatSec(ctx, timeout),
1365 )
1366 cmd.setReadTimeout(timeout)
1367 _ = c(ctx, cmd)
1368 return cmd
1369}
1370
1371func (c cmdable) LIndex(ctx context.Context, key string, index int64) *StringCmd {
1372 cmd := NewStringCmd(ctx, "lindex", key, index)
1373 _ = c(ctx, cmd)
1374 return cmd
1375}
1376
1377func (c cmdable) LInsert(ctx context.Context, key, op string, pivot, value interface{}) *IntCmd {
1378 cmd := NewIntCmd(ctx, "linsert", key, op, pivot, value)
1379 _ = c(ctx, cmd)
1380 return cmd
1381}
1382
1383func (c cmdable) LInsertBefore(ctx context.Context, key string, pivot, value interface{}) *IntCmd {
1384 cmd := NewIntCmd(ctx, "linsert", key, "before", pivot, value)
1385 _ = c(ctx, cmd)
1386 return cmd
1387}
1388
1389func (c cmdable) LInsertAfter(ctx context.Context, key string, pivot, value interface{}) *IntCmd {
1390 cmd := NewIntCmd(ctx, "linsert", key, "after", pivot, value)
1391 _ = c(ctx, cmd)
1392 return cmd
1393}
1394
1395func (c cmdable) LLen(ctx context.Context, key string) *IntCmd {
1396 cmd := NewIntCmd(ctx, "llen", key)
1397 _ = c(ctx, cmd)
1398 return cmd
1399}
1400
1401func (c cmdable) LPop(ctx context.Context, key string) *StringCmd {
1402 cmd := NewStringCmd(ctx, "lpop", key)
1403 _ = c(ctx, cmd)
1404 return cmd
1405}
1406
1407func (c cmdable) LPopCount(ctx context.Context, key string, count int) *StringSliceCmd {
1408 cmd := NewStringSliceCmd(ctx, "lpop", key, count)
1409 _ = c(ctx, cmd)
1410 return cmd
1411}
1412
1413type LPosArgs struct {
1414 Rank, MaxLen int64
1415}
1416
1417func (c cmdable) LPos(ctx context.Context, key string, value string, a LPosArgs) *IntCmd {
1418 args := []interface{}{"lpos", key, value}
1419 if a.Rank != 0 {
1420 args = append(args, "rank", a.Rank)
1421 }
1422 if a.MaxLen != 0 {
1423 args = append(args, "maxlen", a.MaxLen)
1424 }
1425
1426 cmd := NewIntCmd(ctx, args...)
1427 _ = c(ctx, cmd)
1428 return cmd
1429}
1430
1431func (c cmdable) LPosCount(ctx context.Context, key string, value string, count int64, a LPosArgs) *IntSliceCmd {
1432 args := []interface{}{"lpos", key, value, "count", count}
1433 if a.Rank != 0 {
1434 args = append(args, "rank", a.Rank)
1435 }
1436 if a.MaxLen != 0 {
1437 args = append(args, "maxlen", a.MaxLen)
1438 }
1439 cmd := NewIntSliceCmd(ctx, args...)
1440 _ = c(ctx, cmd)
1441 return cmd
1442}
1443
1444func (c cmdable) LPush(ctx context.Context, key string, values ...interface{}) *IntCmd {
1445 args := make([]interface{}, 2, 2+len(values))
1446 args[0] = "lpush"
1447 args[1] = key
1448 args = appendArgs(args, values)
1449 cmd := NewIntCmd(ctx, args...)
1450 _ = c(ctx, cmd)
1451 return cmd
1452}
1453
1454func (c cmdable) LPushX(ctx context.Context, key string, values ...interface{}) *IntCmd {
1455 args := make([]interface{}, 2, 2+len(values))
1456 args[0] = "lpushx"
1457 args[1] = key
1458 args = appendArgs(args, values)
1459 cmd := NewIntCmd(ctx, args...)
1460 _ = c(ctx, cmd)
1461 return cmd
1462}
1463
1464func (c cmdable) LRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd {
1465 cmd := NewStringSliceCmd(
1466 ctx,
1467 "lrange",
1468 key,
1469 start,
1470 stop,
1471 )
1472 _ = c(ctx, cmd)
1473 return cmd
1474}
1475
1476func (c cmdable) LRem(ctx context.Context, key string, count int64, value interface{}) *IntCmd {
1477 cmd := NewIntCmd(ctx, "lrem", key, count, value)
1478 _ = c(ctx, cmd)
1479 return cmd
1480}
1481
1482func (c cmdable) LSet(ctx context.Context, key string, index int64, value interface{}) *StatusCmd {
1483 cmd := NewStatusCmd(ctx, "lset", key, index, value)
1484 _ = c(ctx, cmd)
1485 return cmd
1486}
1487
1488func (c cmdable) LTrim(ctx context.Context, key string, start, stop int64) *StatusCmd {
1489 cmd := NewStatusCmd(
1490 ctx,
1491 "ltrim",
1492 key,
1493 start,
1494 stop,
1495 )
1496 _ = c(ctx, cmd)
1497 return cmd
1498}
1499
1500func (c cmdable) RPop(ctx context.Context, key string) *StringCmd {
1501 cmd := NewStringCmd(ctx, "rpop", key)
1502 _ = c(ctx, cmd)
1503 return cmd
1504}
1505
1506func (c cmdable) RPopCount(ctx context.Context, key string, count int) *StringSliceCmd {
1507 cmd := NewStringSliceCmd(ctx, "rpop", key, count)
1508 _ = c(ctx, cmd)
1509 return cmd
1510}
1511
1512func (c cmdable) RPopLPush(ctx context.Context, source, destination string) *StringCmd {
1513 cmd := NewStringCmd(ctx, "rpoplpush", source, destination)
1514 _ = c(ctx, cmd)
1515 return cmd
1516}
1517
1518func (c cmdable) RPush(ctx context.Context, key string, values ...interface{}) *IntCmd {
1519 args := make([]interface{}, 2, 2+len(values))
1520 args[0] = "rpush"
1521 args[1] = key
1522 args = appendArgs(args, values)
1523 cmd := NewIntCmd(ctx, args...)
1524 _ = c(ctx, cmd)
1525 return cmd
1526}
1527
1528func (c cmdable) RPushX(ctx context.Context, key string, values ...interface{}) *IntCmd {
1529 args := make([]interface{}, 2, 2+len(values))
1530 args[0] = "rpushx"
1531 args[1] = key
1532 args = appendArgs(args, values)
1533 cmd := NewIntCmd(ctx, args...)
1534 _ = c(ctx, cmd)
1535 return cmd
1536}
1537
1538func (c cmdable) LMove(ctx context.Context, source, destination, srcpos, destpos string) *StringCmd {
1539 cmd := NewStringCmd(ctx, "lmove", source, destination, srcpos, destpos)
1540 _ = c(ctx, cmd)
1541 return cmd
1542}
1543
1544func (c cmdable) BLMove(
1545 ctx context.Context, source, destination, srcpos, destpos string, timeout time.Duration,
1546) *StringCmd {
1547 cmd := NewStringCmd(ctx, "blmove", source, destination, srcpos, destpos, formatSec(ctx, timeout))
1548 cmd.setReadTimeout(timeout)
1549 _ = c(ctx, cmd)
1550 return cmd
1551}
1552
1553//------------------------------------------------------------------------------
1554
1555func (c cmdable) SAdd(ctx context.Context, key string, members ...interface{}) *IntCmd {
1556 args := make([]interface{}, 2, 2+len(members))
1557 args[0] = "sadd"
1558 args[1] = key
1559 args = appendArgs(args, members)
1560 cmd := NewIntCmd(ctx, args...)
1561 _ = c(ctx, cmd)
1562 return cmd
1563}
1564
1565func (c cmdable) SCard(ctx context.Context, key string) *IntCmd {
1566 cmd := NewIntCmd(ctx, "scard", key)
1567 _ = c(ctx, cmd)
1568 return cmd
1569}
1570
1571func (c cmdable) SDiff(ctx context.Context, keys ...string) *StringSliceCmd {
1572 args := make([]interface{}, 1+len(keys))
1573 args[0] = "sdiff"
1574 for i, key := range keys {
1575 args[1+i] = key
1576 }
1577 cmd := NewStringSliceCmd(ctx, args...)
1578 _ = c(ctx, cmd)
1579 return cmd
1580}
1581
1582func (c cmdable) SDiffStore(ctx context.Context, destination string, keys ...string) *IntCmd {
1583 args := make([]interface{}, 2+len(keys))
1584 args[0] = "sdiffstore"
1585 args[1] = destination
1586 for i, key := range keys {
1587 args[2+i] = key
1588 }
1589 cmd := NewIntCmd(ctx, args...)
1590 _ = c(ctx, cmd)
1591 return cmd
1592}
1593
1594func (c cmdable) SInter(ctx context.Context, keys ...string) *StringSliceCmd {
1595 args := make([]interface{}, 1+len(keys))
1596 args[0] = "sinter"
1597 for i, key := range keys {
1598 args[1+i] = key
1599 }
1600 cmd := NewStringSliceCmd(ctx, args...)
1601 _ = c(ctx, cmd)
1602 return cmd
1603}
1604
1605func (c cmdable) SInterStore(ctx context.Context, destination string, keys ...string) *IntCmd {
1606 args := make([]interface{}, 2+len(keys))
1607 args[0] = "sinterstore"
1608 args[1] = destination
1609 for i, key := range keys {
1610 args[2+i] = key
1611 }
1612 cmd := NewIntCmd(ctx, args...)
1613 _ = c(ctx, cmd)
1614 return cmd
1615}
1616
1617func (c cmdable) SIsMember(ctx context.Context, key string, member interface{}) *BoolCmd {
1618 cmd := NewBoolCmd(ctx, "sismember", key, member)
1619 _ = c(ctx, cmd)
1620 return cmd
1621}
1622
1623// SMIsMember Redis `SMISMEMBER key member [member ...]` command.
1624func (c cmdable) SMIsMember(ctx context.Context, key string, members ...interface{}) *BoolSliceCmd {
1625 args := make([]interface{}, 2, 2+len(members))
1626 args[0] = "smismember"
1627 args[1] = key
1628 args = appendArgs(args, members)
1629 cmd := NewBoolSliceCmd(ctx, args...)
1630 _ = c(ctx, cmd)
1631 return cmd
1632}
1633
1634// SMembers Redis `SMEMBERS key` command output as a slice.
1635func (c cmdable) SMembers(ctx context.Context, key string) *StringSliceCmd {
1636 cmd := NewStringSliceCmd(ctx, "smembers", key)
1637 _ = c(ctx, cmd)
1638 return cmd
1639}
1640
1641// SMembersMap Redis `SMEMBERS key` command output as a map.
1642func (c cmdable) SMembersMap(ctx context.Context, key string) *StringStructMapCmd {
1643 cmd := NewStringStructMapCmd(ctx, "smembers", key)
1644 _ = c(ctx, cmd)
1645 return cmd
1646}
1647
1648func (c cmdable) SMove(ctx context.Context, source, destination string, member interface{}) *BoolCmd {
1649 cmd := NewBoolCmd(ctx, "smove", source, destination, member)
1650 _ = c(ctx, cmd)
1651 return cmd
1652}
1653
1654// SPop Redis `SPOP key` command.
1655func (c cmdable) SPop(ctx context.Context, key string) *StringCmd {
1656 cmd := NewStringCmd(ctx, "spop", key)
1657 _ = c(ctx, cmd)
1658 return cmd
1659}
1660
1661// SPopN Redis `SPOP key count` command.
1662func (c cmdable) SPopN(ctx context.Context, key string, count int64) *StringSliceCmd {
1663 cmd := NewStringSliceCmd(ctx, "spop", key, count)
1664 _ = c(ctx, cmd)
1665 return cmd
1666}
1667
1668// SRandMember Redis `SRANDMEMBER key` command.
1669func (c cmdable) SRandMember(ctx context.Context, key string) *StringCmd {
1670 cmd := NewStringCmd(ctx, "srandmember", key)
1671 _ = c(ctx, cmd)
1672 return cmd
1673}
1674
1675// SRandMemberN Redis `SRANDMEMBER key count` command.
1676func (c cmdable) SRandMemberN(ctx context.Context, key string, count int64) *StringSliceCmd {
1677 cmd := NewStringSliceCmd(ctx, "srandmember", key, count)
1678 _ = c(ctx, cmd)
1679 return cmd
1680}
1681
1682func (c cmdable) SRem(ctx context.Context, key string, members ...interface{}) *IntCmd {
1683 args := make([]interface{}, 2, 2+len(members))
1684 args[0] = "srem"
1685 args[1] = key
1686 args = appendArgs(args, members)
1687 cmd := NewIntCmd(ctx, args...)
1688 _ = c(ctx, cmd)
1689 return cmd
1690}
1691
1692func (c cmdable) SUnion(ctx context.Context, keys ...string) *StringSliceCmd {
1693 args := make([]interface{}, 1+len(keys))
1694 args[0] = "sunion"
1695 for i, key := range keys {
1696 args[1+i] = key
1697 }
1698 cmd := NewStringSliceCmd(ctx, args...)
1699 _ = c(ctx, cmd)
1700 return cmd
1701}
1702
1703func (c cmdable) SUnionStore(ctx context.Context, destination string, keys ...string) *IntCmd {
1704 args := make([]interface{}, 2+len(keys))
1705 args[0] = "sunionstore"
1706 args[1] = destination
1707 for i, key := range keys {
1708 args[2+i] = key
1709 }
1710 cmd := NewIntCmd(ctx, args...)
1711 _ = c(ctx, cmd)
1712 return cmd
1713}
1714
1715//------------------------------------------------------------------------------
1716
1717// XAddArgs accepts values in the following formats:
1718// - XAddArgs.Values = []interface{}{"key1", "value1", "key2", "value2"}
1719// - XAddArgs.Values = []string("key1", "value1", "key2", "value2")
1720// - XAddArgs.Values = map[string]interface{}{"key1": "value1", "key2": "value2"}
1721//
1722// Note that map will not preserve the order of key-value pairs.
1723// MaxLen/MaxLenApprox and MinID are in conflict, only one of them can be used.
1724type XAddArgs struct {
1725 Stream string
1726 NoMkStream bool
1727 MaxLen int64 // MAXLEN N
1728
1729 // Deprecated: use MaxLen+Approx, remove in v9.
1730 MaxLenApprox int64 // MAXLEN ~ N
1731
1732 MinID string
1733 // Approx causes MaxLen and MinID to use "~" matcher (instead of "=").
1734 Approx bool
1735 Limit int64
1736 ID string
1737 Values interface{}
1738}
1739
1740// XAdd a.Limit has a bug, please confirm it and use it.
1741// issue: https://github.com/redis/redis/issues/9046
1742func (c cmdable) XAdd(ctx context.Context, a *XAddArgs) *StringCmd {
1743 args := make([]interface{}, 0, 11)
1744 args = append(args, "xadd", a.Stream)
1745 if a.NoMkStream {
1746 args = append(args, "nomkstream")
1747 }
1748 switch {
1749 case a.MaxLen > 0:
1750 if a.Approx {
1751 args = append(args, "maxlen", "~", a.MaxLen)
1752 } else {
1753 args = append(args, "maxlen", a.MaxLen)
1754 }
1755 case a.MaxLenApprox > 0:
1756 // TODO remove in v9.
1757 args = append(args, "maxlen", "~", a.MaxLenApprox)
1758 case a.MinID != "":
1759 if a.Approx {
1760 args = append(args, "minid", "~", a.MinID)
1761 } else {
1762 args = append(args, "minid", a.MinID)
1763 }
1764 }
1765 if a.Limit > 0 {
1766 args = append(args, "limit", a.Limit)
1767 }
1768 if a.ID != "" {
1769 args = append(args, a.ID)
1770 } else {
1771 args = append(args, "*")
1772 }
1773 args = appendArg(args, a.Values)
1774
1775 cmd := NewStringCmd(ctx, args...)
1776 _ = c(ctx, cmd)
1777 return cmd
1778}
1779
1780func (c cmdable) XDel(ctx context.Context, stream string, ids ...string) *IntCmd {
1781 args := []interface{}{"xdel", stream}
1782 for _, id := range ids {
1783 args = append(args, id)
1784 }
1785 cmd := NewIntCmd(ctx, args...)
1786 _ = c(ctx, cmd)
1787 return cmd
1788}
1789
1790func (c cmdable) XLen(ctx context.Context, stream string) *IntCmd {
1791 cmd := NewIntCmd(ctx, "xlen", stream)
1792 _ = c(ctx, cmd)
1793 return cmd
1794}
1795
1796func (c cmdable) XRange(ctx context.Context, stream, start, stop string) *XMessageSliceCmd {
1797 cmd := NewXMessageSliceCmd(ctx, "xrange", stream, start, stop)
1798 _ = c(ctx, cmd)
1799 return cmd
1800}
1801
1802func (c cmdable) XRangeN(ctx context.Context, stream, start, stop string, count int64) *XMessageSliceCmd {
1803 cmd := NewXMessageSliceCmd(ctx, "xrange", stream, start, stop, "count", count)
1804 _ = c(ctx, cmd)
1805 return cmd
1806}
1807
1808func (c cmdable) XRevRange(ctx context.Context, stream, start, stop string) *XMessageSliceCmd {
1809 cmd := NewXMessageSliceCmd(ctx, "xrevrange", stream, start, stop)
1810 _ = c(ctx, cmd)
1811 return cmd
1812}
1813
1814func (c cmdable) XRevRangeN(ctx context.Context, stream, start, stop string, count int64) *XMessageSliceCmd {
1815 cmd := NewXMessageSliceCmd(ctx, "xrevrange", stream, start, stop, "count", count)
1816 _ = c(ctx, cmd)
1817 return cmd
1818}
1819
1820type XReadArgs struct {
1821 Streams []string // list of streams and ids, e.g. stream1 stream2 id1 id2
1822 Count int64
1823 Block time.Duration
1824}
1825
1826func (c cmdable) XRead(ctx context.Context, a *XReadArgs) *XStreamSliceCmd {
1827 args := make([]interface{}, 0, 6+len(a.Streams))
1828 args = append(args, "xread")
1829
1830 keyPos := int8(1)
1831 if a.Count > 0 {
1832 args = append(args, "count")
1833 args = append(args, a.Count)
1834 keyPos += 2
1835 }
1836 if a.Block >= 0 {
1837 args = append(args, "block")
1838 args = append(args, int64(a.Block/time.Millisecond))
1839 keyPos += 2
1840 }
1841 args = append(args, "streams")
1842 keyPos++
1843 for _, s := range a.Streams {
1844 args = append(args, s)
1845 }
1846
1847 cmd := NewXStreamSliceCmd(ctx, args...)
1848 if a.Block >= 0 {
1849 cmd.setReadTimeout(a.Block)
1850 }
1851 cmd.SetFirstKeyPos(keyPos)
1852 _ = c(ctx, cmd)
1853 return cmd
1854}
1855
1856func (c cmdable) XReadStreams(ctx context.Context, streams ...string) *XStreamSliceCmd {
1857 return c.XRead(ctx, &XReadArgs{
1858 Streams: streams,
1859 Block: -1,
1860 })
1861}
1862
1863func (c cmdable) XGroupCreate(ctx context.Context, stream, group, start string) *StatusCmd {
1864 cmd := NewStatusCmd(ctx, "xgroup", "create", stream, group, start)
1865 _ = c(ctx, cmd)
1866 return cmd
1867}
1868
1869func (c cmdable) XGroupCreateMkStream(ctx context.Context, stream, group, start string) *StatusCmd {
1870 cmd := NewStatusCmd(ctx, "xgroup", "create", stream, group, start, "mkstream")
1871 _ = c(ctx, cmd)
1872 return cmd
1873}
1874
1875func (c cmdable) XGroupSetID(ctx context.Context, stream, group, start string) *StatusCmd {
1876 cmd := NewStatusCmd(ctx, "xgroup", "setid", stream, group, start)
1877 _ = c(ctx, cmd)
1878 return cmd
1879}
1880
1881func (c cmdable) XGroupDestroy(ctx context.Context, stream, group string) *IntCmd {
1882 cmd := NewIntCmd(ctx, "xgroup", "destroy", stream, group)
1883 _ = c(ctx, cmd)
1884 return cmd
1885}
1886
1887func (c cmdable) XGroupCreateConsumer(ctx context.Context, stream, group, consumer string) *IntCmd {
1888 cmd := NewIntCmd(ctx, "xgroup", "createconsumer", stream, group, consumer)
1889 _ = c(ctx, cmd)
1890 return cmd
1891}
1892
1893func (c cmdable) XGroupDelConsumer(ctx context.Context, stream, group, consumer string) *IntCmd {
1894 cmd := NewIntCmd(ctx, "xgroup", "delconsumer", stream, group, consumer)
1895 _ = c(ctx, cmd)
1896 return cmd
1897}
1898
1899type XReadGroupArgs struct {
1900 Group string
1901 Consumer string
1902 Streams []string // list of streams and ids, e.g. stream1 stream2 id1 id2
1903 Count int64
1904 Block time.Duration
1905 NoAck bool
1906}
1907
1908func (c cmdable) XReadGroup(ctx context.Context, a *XReadGroupArgs) *XStreamSliceCmd {
1909 args := make([]interface{}, 0, 10+len(a.Streams))
1910 args = append(args, "xreadgroup", "group", a.Group, a.Consumer)
1911
1912 keyPos := int8(4)
1913 if a.Count > 0 {
1914 args = append(args, "count", a.Count)
1915 keyPos += 2
1916 }
1917 if a.Block >= 0 {
1918 args = append(args, "block", int64(a.Block/time.Millisecond))
1919 keyPos += 2
1920 }
1921 if a.NoAck {
1922 args = append(args, "noack")
1923 keyPos++
1924 }
1925 args = append(args, "streams")
1926 keyPos++
1927 for _, s := range a.Streams {
1928 args = append(args, s)
1929 }
1930
1931 cmd := NewXStreamSliceCmd(ctx, args...)
1932 if a.Block >= 0 {
1933 cmd.setReadTimeout(a.Block)
1934 }
1935 cmd.SetFirstKeyPos(keyPos)
1936 _ = c(ctx, cmd)
1937 return cmd
1938}
1939
1940func (c cmdable) XAck(ctx context.Context, stream, group string, ids ...string) *IntCmd {
1941 args := []interface{}{"xack", stream, group}
1942 for _, id := range ids {
1943 args = append(args, id)
1944 }
1945 cmd := NewIntCmd(ctx, args...)
1946 _ = c(ctx, cmd)
1947 return cmd
1948}
1949
1950func (c cmdable) XPending(ctx context.Context, stream, group string) *XPendingCmd {
1951 cmd := NewXPendingCmd(ctx, "xpending", stream, group)
1952 _ = c(ctx, cmd)
1953 return cmd
1954}
1955
1956type XPendingExtArgs struct {
1957 Stream string
1958 Group string
1959 Idle time.Duration
1960 Start string
1961 End string
1962 Count int64
1963 Consumer string
1964}
1965
1966func (c cmdable) XPendingExt(ctx context.Context, a *XPendingExtArgs) *XPendingExtCmd {
1967 args := make([]interface{}, 0, 9)
1968 args = append(args, "xpending", a.Stream, a.Group)
1969 if a.Idle != 0 {
1970 args = append(args, "idle", formatMs(ctx, a.Idle))
1971 }
1972 args = append(args, a.Start, a.End, a.Count)
1973 if a.Consumer != "" {
1974 args = append(args, a.Consumer)
1975 }
1976 cmd := NewXPendingExtCmd(ctx, args...)
1977 _ = c(ctx, cmd)
1978 return cmd
1979}
1980
1981type XAutoClaimArgs struct {
1982 Stream string
1983 Group string
1984 MinIdle time.Duration
1985 Start string
1986 Count int64
1987 Consumer string
1988}
1989
1990func (c cmdable) XAutoClaim(ctx context.Context, a *XAutoClaimArgs) *XAutoClaimCmd {
1991 args := xAutoClaimArgs(ctx, a)
1992 cmd := NewXAutoClaimCmd(ctx, args...)
1993 _ = c(ctx, cmd)
1994 return cmd
1995}
1996
1997func (c cmdable) XAutoClaimJustID(ctx context.Context, a *XAutoClaimArgs) *XAutoClaimJustIDCmd {
1998 args := xAutoClaimArgs(ctx, a)
1999 args = append(args, "justid")
2000 cmd := NewXAutoClaimJustIDCmd(ctx, args...)
2001 _ = c(ctx, cmd)
2002 return cmd
2003}
2004
2005func xAutoClaimArgs(ctx context.Context, a *XAutoClaimArgs) []interface{} {
2006 args := make([]interface{}, 0, 8)
2007 args = append(args, "xautoclaim", a.Stream, a.Group, a.Consumer, formatMs(ctx, a.MinIdle), a.Start)
2008 if a.Count > 0 {
2009 args = append(args, "count", a.Count)
2010 }
2011 return args
2012}
2013
2014type XClaimArgs struct {
2015 Stream string
2016 Group string
2017 Consumer string
2018 MinIdle time.Duration
2019 Messages []string
2020}
2021
2022func (c cmdable) XClaim(ctx context.Context, a *XClaimArgs) *XMessageSliceCmd {
2023 args := xClaimArgs(a)
2024 cmd := NewXMessageSliceCmd(ctx, args...)
2025 _ = c(ctx, cmd)
2026 return cmd
2027}
2028
2029func (c cmdable) XClaimJustID(ctx context.Context, a *XClaimArgs) *StringSliceCmd {
2030 args := xClaimArgs(a)
2031 args = append(args, "justid")
2032 cmd := NewStringSliceCmd(ctx, args...)
2033 _ = c(ctx, cmd)
2034 return cmd
2035}
2036
2037func xClaimArgs(a *XClaimArgs) []interface{} {
2038 args := make([]interface{}, 0, 5+len(a.Messages))
2039 args = append(args,
2040 "xclaim",
2041 a.Stream,
2042 a.Group, a.Consumer,
2043 int64(a.MinIdle/time.Millisecond))
2044 for _, id := range a.Messages {
2045 args = append(args, id)
2046 }
2047 return args
2048}
2049
2050// xTrim If approx is true, add the "~" parameter, otherwise it is the default "=" (redis default).
2051// example:
2052// XTRIM key MAXLEN/MINID threshold LIMIT limit.
2053// XTRIM key MAXLEN/MINID ~ threshold LIMIT limit.
2054// The redis-server version is lower than 6.2, please set limit to 0.
2055func (c cmdable) xTrim(
2056 ctx context.Context, key, strategy string,
2057 approx bool, threshold interface{}, limit int64,
2058) *IntCmd {
2059 args := make([]interface{}, 0, 7)
2060 args = append(args, "xtrim", key, strategy)
2061 if approx {
2062 args = append(args, "~")
2063 }
2064 args = append(args, threshold)
2065 if limit > 0 {
2066 args = append(args, "limit", limit)
2067 }
2068 cmd := NewIntCmd(ctx, args...)
2069 _ = c(ctx, cmd)
2070 return cmd
2071}
2072
2073// Deprecated: use XTrimMaxLen, remove in v9.
2074func (c cmdable) XTrim(ctx context.Context, key string, maxLen int64) *IntCmd {
2075 return c.xTrim(ctx, key, "maxlen", false, maxLen, 0)
2076}
2077
2078// Deprecated: use XTrimMaxLenApprox, remove in v9.
2079func (c cmdable) XTrimApprox(ctx context.Context, key string, maxLen int64) *IntCmd {
2080 return c.xTrim(ctx, key, "maxlen", true, maxLen, 0)
2081}
2082
2083// XTrimMaxLen No `~` rules are used, `limit` cannot be used.
2084// cmd: XTRIM key MAXLEN maxLen
2085func (c cmdable) XTrimMaxLen(ctx context.Context, key string, maxLen int64) *IntCmd {
2086 return c.xTrim(ctx, key, "maxlen", false, maxLen, 0)
2087}
2088
2089// XTrimMaxLenApprox LIMIT has a bug, please confirm it and use it.
2090// issue: https://github.com/redis/redis/issues/9046
2091// cmd: XTRIM key MAXLEN ~ maxLen LIMIT limit
2092func (c cmdable) XTrimMaxLenApprox(ctx context.Context, key string, maxLen, limit int64) *IntCmd {
2093 return c.xTrim(ctx, key, "maxlen", true, maxLen, limit)
2094}
2095
2096// XTrimMinID No `~` rules are used, `limit` cannot be used.
2097// cmd: XTRIM key MINID minID
2098func (c cmdable) XTrimMinID(ctx context.Context, key string, minID string) *IntCmd {
2099 return c.xTrim(ctx, key, "minid", false, minID, 0)
2100}
2101
2102// XTrimMinIDApprox LIMIT has a bug, please confirm it and use it.
2103// issue: https://github.com/redis/redis/issues/9046
2104// cmd: XTRIM key MINID ~ minID LIMIT limit
2105func (c cmdable) XTrimMinIDApprox(ctx context.Context, key string, minID string, limit int64) *IntCmd {
2106 return c.xTrim(ctx, key, "minid", true, minID, limit)
2107}
2108
2109func (c cmdable) XInfoConsumers(ctx context.Context, key string, group string) *XInfoConsumersCmd {
2110 cmd := NewXInfoConsumersCmd(ctx, key, group)
2111 _ = c(ctx, cmd)
2112 return cmd
2113}
2114
2115func (c cmdable) XInfoGroups(ctx context.Context, key string) *XInfoGroupsCmd {
2116 cmd := NewXInfoGroupsCmd(ctx, key)
2117 _ = c(ctx, cmd)
2118 return cmd
2119}
2120
2121func (c cmdable) XInfoStream(ctx context.Context, key string) *XInfoStreamCmd {
2122 cmd := NewXInfoStreamCmd(ctx, key)
2123 _ = c(ctx, cmd)
2124 return cmd
2125}
2126
2127// XInfoStreamFull XINFO STREAM FULL [COUNT count]
2128// redis-server >= 6.0.
2129func (c cmdable) XInfoStreamFull(ctx context.Context, key string, count int) *XInfoStreamFullCmd {
2130 args := make([]interface{}, 0, 6)
2131 args = append(args, "xinfo", "stream", key, "full")
2132 if count > 0 {
2133 args = append(args, "count", count)
2134 }
2135 cmd := NewXInfoStreamFullCmd(ctx, args...)
2136 _ = c(ctx, cmd)
2137 return cmd
2138}
2139
2140//------------------------------------------------------------------------------
2141
2142// Z represents sorted set member.
2143type Z struct {
2144 Score float64
2145 Member interface{}
2146}
2147
2148// ZWithKey represents sorted set member including the name of the key where it was popped.
2149type ZWithKey struct {
2150 Z
2151 Key string
2152}
2153
2154// ZStore is used as an arg to ZInter/ZInterStore and ZUnion/ZUnionStore.
2155type ZStore struct {
2156 Keys []string
2157 Weights []float64
2158 // Can be SUM, MIN or MAX.
2159 Aggregate string
2160}
2161
2162func (z ZStore) len() (n int) {
2163 n = len(z.Keys)
2164 if len(z.Weights) > 0 {
2165 n += 1 + len(z.Weights)
2166 }
2167 if z.Aggregate != "" {
2168 n += 2
2169 }
2170 return n
2171}
2172
2173func (z ZStore) appendArgs(args []interface{}) []interface{} {
2174 for _, key := range z.Keys {
2175 args = append(args, key)
2176 }
2177 if len(z.Weights) > 0 {
2178 args = append(args, "weights")
2179 for _, weights := range z.Weights {
2180 args = append(args, weights)
2181 }
2182 }
2183 if z.Aggregate != "" {
2184 args = append(args, "aggregate", z.Aggregate)
2185 }
2186 return args
2187}
2188
2189// BZPopMax Redis `BZPOPMAX key [key ...] timeout` command.
2190func (c cmdable) BZPopMax(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd {
2191 args := make([]interface{}, 1+len(keys)+1)
2192 args[0] = "bzpopmax"
2193 for i, key := range keys {
2194 args[1+i] = key
2195 }
2196 args[len(args)-1] = formatSec(ctx, timeout)
2197 cmd := NewZWithKeyCmd(ctx, args...)
2198 cmd.setReadTimeout(timeout)
2199 _ = c(ctx, cmd)
2200 return cmd
2201}
2202
2203// BZPopMin Redis `BZPOPMIN key [key ...] timeout` command.
2204func (c cmdable) BZPopMin(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd {
2205 args := make([]interface{}, 1+len(keys)+1)
2206 args[0] = "bzpopmin"
2207 for i, key := range keys {
2208 args[1+i] = key
2209 }
2210 args[len(args)-1] = formatSec(ctx, timeout)
2211 cmd := NewZWithKeyCmd(ctx, args...)
2212 cmd.setReadTimeout(timeout)
2213 _ = c(ctx, cmd)
2214 return cmd
2215}
2216
2217// ZAddArgs WARN: The GT, LT and NX options are mutually exclusive.
2218type ZAddArgs struct {
2219 NX bool
2220 XX bool
2221 LT bool
2222 GT bool
2223 Ch bool
2224 Members []Z
2225}
2226
2227func (c cmdable) zAddArgs(key string, args ZAddArgs, incr bool) []interface{} {
2228 a := make([]interface{}, 0, 6+2*len(args.Members))
2229 a = append(a, "zadd", key)
2230
2231 // The GT, LT and NX options are mutually exclusive.
2232 if args.NX {
2233 a = append(a, "nx")
2234 } else {
2235 if args.XX {
2236 a = append(a, "xx")
2237 }
2238 if args.GT {
2239 a = append(a, "gt")
2240 } else if args.LT {
2241 a = append(a, "lt")
2242 }
2243 }
2244 if args.Ch {
2245 a = append(a, "ch")
2246 }
2247 if incr {
2248 a = append(a, "incr")
2249 }
2250 for _, m := range args.Members {
2251 a = append(a, m.Score)
2252 a = append(a, m.Member)
2253 }
2254 return a
2255}
2256
2257func (c cmdable) ZAddArgs(ctx context.Context, key string, args ZAddArgs) *IntCmd {
2258 cmd := NewIntCmd(ctx, c.zAddArgs(key, args, false)...)
2259 _ = c(ctx, cmd)
2260 return cmd
2261}
2262
2263func (c cmdable) ZAddArgsIncr(ctx context.Context, key string, args ZAddArgs) *FloatCmd {
2264 cmd := NewFloatCmd(ctx, c.zAddArgs(key, args, true)...)
2265 _ = c(ctx, cmd)
2266 return cmd
2267}
2268
2269// TODO: Compatible with v8 api, will be removed in v9.
2270func (c cmdable) zAdd(ctx context.Context, key string, args ZAddArgs, members ...*Z) *IntCmd {
2271 args.Members = make([]Z, len(members))
2272 for i, m := range members {
2273 args.Members[i] = *m
2274 }
2275 cmd := NewIntCmd(ctx, c.zAddArgs(key, args, false)...)
2276 _ = c(ctx, cmd)
2277 return cmd
2278}
2279
2280// ZAdd Redis `ZADD key score member [score member ...]` command.
2281func (c cmdable) ZAdd(ctx context.Context, key string, members ...*Z) *IntCmd {
2282 return c.zAdd(ctx, key, ZAddArgs{}, members...)
2283}
2284
2285// ZAddNX Redis `ZADD key NX score member [score member ...]` command.
2286func (c cmdable) ZAddNX(ctx context.Context, key string, members ...*Z) *IntCmd {
2287 return c.zAdd(ctx, key, ZAddArgs{
2288 NX: true,
2289 }, members...)
2290}
2291
2292// ZAddXX Redis `ZADD key XX score member [score member ...]` command.
2293func (c cmdable) ZAddXX(ctx context.Context, key string, members ...*Z) *IntCmd {
2294 return c.zAdd(ctx, key, ZAddArgs{
2295 XX: true,
2296 }, members...)
2297}
2298
2299// ZAddCh Redis `ZADD key CH score member [score member ...]` command.
2300// Deprecated: Use
2301// client.ZAddArgs(ctx, ZAddArgs{
2302// Ch: true,
2303// Members: []Z,
2304// })
2305// remove in v9.
2306func (c cmdable) ZAddCh(ctx context.Context, key string, members ...*Z) *IntCmd {
2307 return c.zAdd(ctx, key, ZAddArgs{
2308 Ch: true,
2309 }, members...)
2310}
2311
2312// ZAddNXCh Redis `ZADD key NX CH score member [score member ...]` command.
2313// Deprecated: Use
2314// client.ZAddArgs(ctx, ZAddArgs{
2315// NX: true,
2316// Ch: true,
2317// Members: []Z,
2318// })
2319// remove in v9.
2320func (c cmdable) ZAddNXCh(ctx context.Context, key string, members ...*Z) *IntCmd {
2321 return c.zAdd(ctx, key, ZAddArgs{
2322 NX: true,
2323 Ch: true,
2324 }, members...)
2325}
2326
2327// ZAddXXCh Redis `ZADD key XX CH score member [score member ...]` command.
2328// Deprecated: Use
2329// client.ZAddArgs(ctx, ZAddArgs{
2330// XX: true,
2331// Ch: true,
2332// Members: []Z,
2333// })
2334// remove in v9.
2335func (c cmdable) ZAddXXCh(ctx context.Context, key string, members ...*Z) *IntCmd {
2336 return c.zAdd(ctx, key, ZAddArgs{
2337 XX: true,
2338 Ch: true,
2339 }, members...)
2340}
2341
2342// ZIncr Redis `ZADD key INCR score member` command.
2343// Deprecated: Use
2344// client.ZAddArgsIncr(ctx, ZAddArgs{
2345// Members: []Z,
2346// })
2347// remove in v9.
2348func (c cmdable) ZIncr(ctx context.Context, key string, member *Z) *FloatCmd {
2349 return c.ZAddArgsIncr(ctx, key, ZAddArgs{
2350 Members: []Z{*member},
2351 })
2352}
2353
2354// ZIncrNX Redis `ZADD key NX INCR score member` command.
2355// Deprecated: Use
2356// client.ZAddArgsIncr(ctx, ZAddArgs{
2357// NX: true,
2358// Members: []Z,
2359// })
2360// remove in v9.
2361func (c cmdable) ZIncrNX(ctx context.Context, key string, member *Z) *FloatCmd {
2362 return c.ZAddArgsIncr(ctx, key, ZAddArgs{
2363 NX: true,
2364 Members: []Z{*member},
2365 })
2366}
2367
2368// ZIncrXX Redis `ZADD key XX INCR score member` command.
2369// Deprecated: Use
2370// client.ZAddArgsIncr(ctx, ZAddArgs{
2371// XX: true,
2372// Members: []Z,
2373// })
2374// remove in v9.
2375func (c cmdable) ZIncrXX(ctx context.Context, key string, member *Z) *FloatCmd {
2376 return c.ZAddArgsIncr(ctx, key, ZAddArgs{
2377 XX: true,
2378 Members: []Z{*member},
2379 })
2380}
2381
2382func (c cmdable) ZCard(ctx context.Context, key string) *IntCmd {
2383 cmd := NewIntCmd(ctx, "zcard", key)
2384 _ = c(ctx, cmd)
2385 return cmd
2386}
2387
2388func (c cmdable) ZCount(ctx context.Context, key, min, max string) *IntCmd {
2389 cmd := NewIntCmd(ctx, "zcount", key, min, max)
2390 _ = c(ctx, cmd)
2391 return cmd
2392}
2393
2394func (c cmdable) ZLexCount(ctx context.Context, key, min, max string) *IntCmd {
2395 cmd := NewIntCmd(ctx, "zlexcount", key, min, max)
2396 _ = c(ctx, cmd)
2397 return cmd
2398}
2399
2400func (c cmdable) ZIncrBy(ctx context.Context, key string, increment float64, member string) *FloatCmd {
2401 cmd := NewFloatCmd(ctx, "zincrby", key, increment, member)
2402 _ = c(ctx, cmd)
2403 return cmd
2404}
2405
2406func (c cmdable) ZInterStore(ctx context.Context, destination string, store *ZStore) *IntCmd {
2407 args := make([]interface{}, 0, 3+store.len())
2408 args = append(args, "zinterstore", destination, len(store.Keys))
2409 args = store.appendArgs(args)
2410 cmd := NewIntCmd(ctx, args...)
2411 cmd.SetFirstKeyPos(3)
2412 _ = c(ctx, cmd)
2413 return cmd
2414}
2415
2416func (c cmdable) ZInter(ctx context.Context, store *ZStore) *StringSliceCmd {
2417 args := make([]interface{}, 0, 2+store.len())
2418 args = append(args, "zinter", len(store.Keys))
2419 args = store.appendArgs(args)
2420 cmd := NewStringSliceCmd(ctx, args...)
2421 cmd.SetFirstKeyPos(2)
2422 _ = c(ctx, cmd)
2423 return cmd
2424}
2425
2426func (c cmdable) ZInterWithScores(ctx context.Context, store *ZStore) *ZSliceCmd {
2427 args := make([]interface{}, 0, 3+store.len())
2428 args = append(args, "zinter", len(store.Keys))
2429 args = store.appendArgs(args)
2430 args = append(args, "withscores")
2431 cmd := NewZSliceCmd(ctx, args...)
2432 cmd.SetFirstKeyPos(2)
2433 _ = c(ctx, cmd)
2434 return cmd
2435}
2436
2437func (c cmdable) ZMScore(ctx context.Context, key string, members ...string) *FloatSliceCmd {
2438 args := make([]interface{}, 2+len(members))
2439 args[0] = "zmscore"
2440 args[1] = key
2441 for i, member := range members {
2442 args[2+i] = member
2443 }
2444 cmd := NewFloatSliceCmd(ctx, args...)
2445 _ = c(ctx, cmd)
2446 return cmd
2447}
2448
2449func (c cmdable) ZPopMax(ctx context.Context, key string, count ...int64) *ZSliceCmd {
2450 args := []interface{}{
2451 "zpopmax",
2452 key,
2453 }
2454
2455 switch len(count) {
2456 case 0:
2457 break
2458 case 1:
2459 args = append(args, count[0])
2460 default:
2461 panic("too many arguments")
2462 }
2463
2464 cmd := NewZSliceCmd(ctx, args...)
2465 _ = c(ctx, cmd)
2466 return cmd
2467}
2468
2469func (c cmdable) ZPopMin(ctx context.Context, key string, count ...int64) *ZSliceCmd {
2470 args := []interface{}{
2471 "zpopmin",
2472 key,
2473 }
2474
2475 switch len(count) {
2476 case 0:
2477 break
2478 case 1:
2479 args = append(args, count[0])
2480 default:
2481 panic("too many arguments")
2482 }
2483
2484 cmd := NewZSliceCmd(ctx, args...)
2485 _ = c(ctx, cmd)
2486 return cmd
2487}
2488
2489// ZRangeArgs is all the options of the ZRange command.
2490// In version> 6.2.0, you can replace the(cmd):
2491// ZREVRANGE,
2492// ZRANGEBYSCORE,
2493// ZREVRANGEBYSCORE,
2494// ZRANGEBYLEX,
2495// ZREVRANGEBYLEX.
2496// Please pay attention to your redis-server version.
2497//
2498// Rev, ByScore, ByLex and Offset+Count options require redis-server 6.2.0 and higher.
2499type ZRangeArgs struct {
2500 Key string
2501
2502 // When the ByScore option is provided, the open interval(exclusive) can be set.
2503 // By default, the score intervals specified by <Start> and <Stop> are closed (inclusive).
2504 // It is similar to the deprecated(6.2.0+) ZRangeByScore command.
2505 // For example:
2506 // ZRangeArgs{
2507 // Key: "example-key",
2508 // Start: "(3",
2509 // Stop: 8,
2510 // ByScore: true,
2511 // }
2512 // cmd: "ZRange example-key (3 8 ByScore" (3 < score <= 8).
2513 //
2514 // For the ByLex option, it is similar to the deprecated(6.2.0+) ZRangeByLex command.
2515 // You can set the <Start> and <Stop> options as follows:
2516 // ZRangeArgs{
2517 // Key: "example-key",
2518 // Start: "[abc",
2519 // Stop: "(def",
2520 // ByLex: true,
2521 // }
2522 // cmd: "ZRange example-key [abc (def ByLex"
2523 //
2524 // For normal cases (ByScore==false && ByLex==false), <Start> and <Stop> should be set to the index range (int).
2525 // You can read the documentation for more information: https://redis.io/commands/zrange
2526 Start interface{}
2527 Stop interface{}
2528
2529 // The ByScore and ByLex options are mutually exclusive.
2530 ByScore bool
2531 ByLex bool
2532
2533 Rev bool
2534
2535 // limit offset count.
2536 Offset int64
2537 Count int64
2538}
2539
2540func (z ZRangeArgs) appendArgs(args []interface{}) []interface{} {
2541 // For Rev+ByScore/ByLex, we need to adjust the position of <Start> and <Stop>.
2542 if z.Rev && (z.ByScore || z.ByLex) {
2543 args = append(args, z.Key, z.Stop, z.Start)
2544 } else {
2545 args = append(args, z.Key, z.Start, z.Stop)
2546 }
2547
2548 if z.ByScore {
2549 args = append(args, "byscore")
2550 } else if z.ByLex {
2551 args = append(args, "bylex")
2552 }
2553 if z.Rev {
2554 args = append(args, "rev")
2555 }
2556 if z.Offset != 0 || z.Count != 0 {
2557 args = append(args, "limit", z.Offset, z.Count)
2558 }
2559 return args
2560}
2561
2562func (c cmdable) ZRangeArgs(ctx context.Context, z ZRangeArgs) *StringSliceCmd {
2563 args := make([]interface{}, 0, 9)
2564 args = append(args, "zrange")
2565 args = z.appendArgs(args)
2566 cmd := NewStringSliceCmd(ctx, args...)
2567 _ = c(ctx, cmd)
2568 return cmd
2569}
2570
2571func (c cmdable) ZRangeArgsWithScores(ctx context.Context, z ZRangeArgs) *ZSliceCmd {
2572 args := make([]interface{}, 0, 10)
2573 args = append(args, "zrange")
2574 args = z.appendArgs(args)
2575 args = append(args, "withscores")
2576 cmd := NewZSliceCmd(ctx, args...)
2577 _ = c(ctx, cmd)
2578 return cmd
2579}
2580
2581func (c cmdable) ZRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd {
2582 return c.ZRangeArgs(ctx, ZRangeArgs{
2583 Key: key,
2584 Start: start,
2585 Stop: stop,
2586 })
2587}
2588
2589func (c cmdable) ZRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd {
2590 return c.ZRangeArgsWithScores(ctx, ZRangeArgs{
2591 Key: key,
2592 Start: start,
2593 Stop: stop,
2594 })
2595}
2596
2597type ZRangeBy struct {
2598 Min, Max string
2599 Offset, Count int64
2600}
2601
2602func (c cmdable) zRangeBy(ctx context.Context, zcmd, key string, opt *ZRangeBy, withScores bool) *StringSliceCmd {
2603 args := []interface{}{zcmd, key, opt.Min, opt.Max}
2604 if withScores {
2605 args = append(args, "withscores")
2606 }
2607 if opt.Offset != 0 || opt.Count != 0 {
2608 args = append(
2609 args,
2610 "limit",
2611 opt.Offset,
2612 opt.Count,
2613 )
2614 }
2615 cmd := NewStringSliceCmd(ctx, args...)
2616 _ = c(ctx, cmd)
2617 return cmd
2618}
2619
2620func (c cmdable) ZRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd {
2621 return c.zRangeBy(ctx, "zrangebyscore", key, opt, false)
2622}
2623
2624func (c cmdable) ZRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd {
2625 return c.zRangeBy(ctx, "zrangebylex", key, opt, false)
2626}
2627
2628func (c cmdable) ZRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd {
2629 args := []interface{}{"zrangebyscore", key, opt.Min, opt.Max, "withscores"}
2630 if opt.Offset != 0 || opt.Count != 0 {
2631 args = append(
2632 args,
2633 "limit",
2634 opt.Offset,
2635 opt.Count,
2636 )
2637 }
2638 cmd := NewZSliceCmd(ctx, args...)
2639 _ = c(ctx, cmd)
2640 return cmd
2641}
2642
2643func (c cmdable) ZRangeStore(ctx context.Context, dst string, z ZRangeArgs) *IntCmd {
2644 args := make([]interface{}, 0, 10)
2645 args = append(args, "zrangestore", dst)
2646 args = z.appendArgs(args)
2647 cmd := NewIntCmd(ctx, args...)
2648 _ = c(ctx, cmd)
2649 return cmd
2650}
2651
2652func (c cmdable) ZRank(ctx context.Context, key, member string) *IntCmd {
2653 cmd := NewIntCmd(ctx, "zrank", key, member)
2654 _ = c(ctx, cmd)
2655 return cmd
2656}
2657
2658func (c cmdable) ZRem(ctx context.Context, key string, members ...interface{}) *IntCmd {
2659 args := make([]interface{}, 2, 2+len(members))
2660 args[0] = "zrem"
2661 args[1] = key
2662 args = appendArgs(args, members)
2663 cmd := NewIntCmd(ctx, args...)
2664 _ = c(ctx, cmd)
2665 return cmd
2666}
2667
2668func (c cmdable) ZRemRangeByRank(ctx context.Context, key string, start, stop int64) *IntCmd {
2669 cmd := NewIntCmd(
2670 ctx,
2671 "zremrangebyrank",
2672 key,
2673 start,
2674 stop,
2675 )
2676 _ = c(ctx, cmd)
2677 return cmd
2678}
2679
2680func (c cmdable) ZRemRangeByScore(ctx context.Context, key, min, max string) *IntCmd {
2681 cmd := NewIntCmd(ctx, "zremrangebyscore", key, min, max)
2682 _ = c(ctx, cmd)
2683 return cmd
2684}
2685
2686func (c cmdable) ZRemRangeByLex(ctx context.Context, key, min, max string) *IntCmd {
2687 cmd := NewIntCmd(ctx, "zremrangebylex", key, min, max)
2688 _ = c(ctx, cmd)
2689 return cmd
2690}
2691
2692func (c cmdable) ZRevRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd {
2693 cmd := NewStringSliceCmd(ctx, "zrevrange", key, start, stop)
2694 _ = c(ctx, cmd)
2695 return cmd
2696}
2697
2698func (c cmdable) ZRevRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd {
2699 cmd := NewZSliceCmd(ctx, "zrevrange", key, start, stop, "withscores")
2700 _ = c(ctx, cmd)
2701 return cmd
2702}
2703
2704func (c cmdable) zRevRangeBy(ctx context.Context, zcmd, key string, opt *ZRangeBy) *StringSliceCmd {
2705 args := []interface{}{zcmd, key, opt.Max, opt.Min}
2706 if opt.Offset != 0 || opt.Count != 0 {
2707 args = append(
2708 args,
2709 "limit",
2710 opt.Offset,
2711 opt.Count,
2712 )
2713 }
2714 cmd := NewStringSliceCmd(ctx, args...)
2715 _ = c(ctx, cmd)
2716 return cmd
2717}
2718
2719func (c cmdable) ZRevRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd {
2720 return c.zRevRangeBy(ctx, "zrevrangebyscore", key, opt)
2721}
2722
2723func (c cmdable) ZRevRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd {
2724 return c.zRevRangeBy(ctx, "zrevrangebylex", key, opt)
2725}
2726
2727func (c cmdable) ZRevRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd {
2728 args := []interface{}{"zrevrangebyscore", key, opt.Max, opt.Min, "withscores"}
2729 if opt.Offset != 0 || opt.Count != 0 {
2730 args = append(
2731 args,
2732 "limit",
2733 opt.Offset,
2734 opt.Count,
2735 )
2736 }
2737 cmd := NewZSliceCmd(ctx, args...)
2738 _ = c(ctx, cmd)
2739 return cmd
2740}
2741
2742func (c cmdable) ZRevRank(ctx context.Context, key, member string) *IntCmd {
2743 cmd := NewIntCmd(ctx, "zrevrank", key, member)
2744 _ = c(ctx, cmd)
2745 return cmd
2746}
2747
2748func (c cmdable) ZScore(ctx context.Context, key, member string) *FloatCmd {
2749 cmd := NewFloatCmd(ctx, "zscore", key, member)
2750 _ = c(ctx, cmd)
2751 return cmd
2752}
2753
2754func (c cmdable) ZUnion(ctx context.Context, store ZStore) *StringSliceCmd {
2755 args := make([]interface{}, 0, 2+store.len())
2756 args = append(args, "zunion", len(store.Keys))
2757 args = store.appendArgs(args)
2758 cmd := NewStringSliceCmd(ctx, args...)
2759 cmd.SetFirstKeyPos(2)
2760 _ = c(ctx, cmd)
2761 return cmd
2762}
2763
2764func (c cmdable) ZUnionWithScores(ctx context.Context, store ZStore) *ZSliceCmd {
2765 args := make([]interface{}, 0, 3+store.len())
2766 args = append(args, "zunion", len(store.Keys))
2767 args = store.appendArgs(args)
2768 args = append(args, "withscores")
2769 cmd := NewZSliceCmd(ctx, args...)
2770 cmd.SetFirstKeyPos(2)
2771 _ = c(ctx, cmd)
2772 return cmd
2773}
2774
2775func (c cmdable) ZUnionStore(ctx context.Context, dest string, store *ZStore) *IntCmd {
2776 args := make([]interface{}, 0, 3+store.len())
2777 args = append(args, "zunionstore", dest, len(store.Keys))
2778 args = store.appendArgs(args)
2779 cmd := NewIntCmd(ctx, args...)
2780 cmd.SetFirstKeyPos(3)
2781 _ = c(ctx, cmd)
2782 return cmd
2783}
2784
2785// ZRandMember redis-server version >= 6.2.0.
2786func (c cmdable) ZRandMember(ctx context.Context, key string, count int, withScores bool) *StringSliceCmd {
2787 args := make([]interface{}, 0, 4)
2788
2789 // Although count=0 is meaningless, redis accepts count=0.
2790 args = append(args, "zrandmember", key, count)
2791 if withScores {
2792 args = append(args, "withscores")
2793 }
2794
2795 cmd := NewStringSliceCmd(ctx, args...)
2796 _ = c(ctx, cmd)
2797 return cmd
2798}
2799
2800// ZDiff redis-server version >= 6.2.0.
2801func (c cmdable) ZDiff(ctx context.Context, keys ...string) *StringSliceCmd {
2802 args := make([]interface{}, 2+len(keys))
2803 args[0] = "zdiff"
2804 args[1] = len(keys)
2805 for i, key := range keys {
2806 args[i+2] = key
2807 }
2808
2809 cmd := NewStringSliceCmd(ctx, args...)
2810 cmd.SetFirstKeyPos(2)
2811 _ = c(ctx, cmd)
2812 return cmd
2813}
2814
2815// ZDiffWithScores redis-server version >= 6.2.0.
2816func (c cmdable) ZDiffWithScores(ctx context.Context, keys ...string) *ZSliceCmd {
2817 args := make([]interface{}, 3+len(keys))
2818 args[0] = "zdiff"
2819 args[1] = len(keys)
2820 for i, key := range keys {
2821 args[i+2] = key
2822 }
2823 args[len(keys)+2] = "withscores"
2824
2825 cmd := NewZSliceCmd(ctx, args...)
2826 cmd.SetFirstKeyPos(2)
2827 _ = c(ctx, cmd)
2828 return cmd
2829}
2830
2831// ZDiffStore redis-server version >=6.2.0.
2832func (c cmdable) ZDiffStore(ctx context.Context, destination string, keys ...string) *IntCmd {
2833 args := make([]interface{}, 0, 3+len(keys))
2834 args = append(args, "zdiffstore", destination, len(keys))
2835 for _, key := range keys {
2836 args = append(args, key)
2837 }
2838 cmd := NewIntCmd(ctx, args...)
2839 _ = c(ctx, cmd)
2840 return cmd
2841}
2842
2843//------------------------------------------------------------------------------
2844
2845func (c cmdable) PFAdd(ctx context.Context, key string, els ...interface{}) *IntCmd {
2846 args := make([]interface{}, 2, 2+len(els))
2847 args[0] = "pfadd"
2848 args[1] = key
2849 args = appendArgs(args, els)
2850 cmd := NewIntCmd(ctx, args...)
2851 _ = c(ctx, cmd)
2852 return cmd
2853}
2854
2855func (c cmdable) PFCount(ctx context.Context, keys ...string) *IntCmd {
2856 args := make([]interface{}, 1+len(keys))
2857 args[0] = "pfcount"
2858 for i, key := range keys {
2859 args[1+i] = key
2860 }
2861 cmd := NewIntCmd(ctx, args...)
2862 _ = c(ctx, cmd)
2863 return cmd
2864}
2865
2866func (c cmdable) PFMerge(ctx context.Context, dest string, keys ...string) *StatusCmd {
2867 args := make([]interface{}, 2+len(keys))
2868 args[0] = "pfmerge"
2869 args[1] = dest
2870 for i, key := range keys {
2871 args[2+i] = key
2872 }
2873 cmd := NewStatusCmd(ctx, args...)
2874 _ = c(ctx, cmd)
2875 return cmd
2876}
2877
2878//------------------------------------------------------------------------------
2879
2880func (c cmdable) BgRewriteAOF(ctx context.Context) *StatusCmd {
2881 cmd := NewStatusCmd(ctx, "bgrewriteaof")
2882 _ = c(ctx, cmd)
2883 return cmd
2884}
2885
2886func (c cmdable) BgSave(ctx context.Context) *StatusCmd {
2887 cmd := NewStatusCmd(ctx, "bgsave")
2888 _ = c(ctx, cmd)
2889 return cmd
2890}
2891
2892func (c cmdable) ClientKill(ctx context.Context, ipPort string) *StatusCmd {
2893 cmd := NewStatusCmd(ctx, "client", "kill", ipPort)
2894 _ = c(ctx, cmd)
2895 return cmd
2896}
2897
2898// ClientKillByFilter is new style syntax, while the ClientKill is old
2899//
2900// CLIENT KILL <option> [value] ... <option> [value]
2901func (c cmdable) ClientKillByFilter(ctx context.Context, keys ...string) *IntCmd {
2902 args := make([]interface{}, 2+len(keys))
2903 args[0] = "client"
2904 args[1] = "kill"
2905 for i, key := range keys {
2906 args[2+i] = key
2907 }
2908 cmd := NewIntCmd(ctx, args...)
2909 _ = c(ctx, cmd)
2910 return cmd
2911}
2912
2913func (c cmdable) ClientList(ctx context.Context) *StringCmd {
2914 cmd := NewStringCmd(ctx, "client", "list")
2915 _ = c(ctx, cmd)
2916 return cmd
2917}
2918
2919func (c cmdable) ClientPause(ctx context.Context, dur time.Duration) *BoolCmd {
2920 cmd := NewBoolCmd(ctx, "client", "pause", formatMs(ctx, dur))
2921 _ = c(ctx, cmd)
2922 return cmd
2923}
2924
2925func (c cmdable) ClientID(ctx context.Context) *IntCmd {
2926 cmd := NewIntCmd(ctx, "client", "id")
2927 _ = c(ctx, cmd)
2928 return cmd
2929}
2930
2931func (c cmdable) ClientUnblock(ctx context.Context, id int64) *IntCmd {
2932 cmd := NewIntCmd(ctx, "client", "unblock", id)
2933 _ = c(ctx, cmd)
2934 return cmd
2935}
2936
2937func (c cmdable) ClientUnblockWithError(ctx context.Context, id int64) *IntCmd {
2938 cmd := NewIntCmd(ctx, "client", "unblock", id, "error")
2939 _ = c(ctx, cmd)
2940 return cmd
2941}
2942
2943func (c cmdable) ConfigGet(ctx context.Context, parameter string) *SliceCmd {
2944 cmd := NewSliceCmd(ctx, "config", "get", parameter)
2945 _ = c(ctx, cmd)
2946 return cmd
2947}
2948
2949func (c cmdable) ConfigResetStat(ctx context.Context) *StatusCmd {
2950 cmd := NewStatusCmd(ctx, "config", "resetstat")
2951 _ = c(ctx, cmd)
2952 return cmd
2953}
2954
2955func (c cmdable) ConfigSet(ctx context.Context, parameter, value string) *StatusCmd {
2956 cmd := NewStatusCmd(ctx, "config", "set", parameter, value)
2957 _ = c(ctx, cmd)
2958 return cmd
2959}
2960
2961func (c cmdable) ConfigRewrite(ctx context.Context) *StatusCmd {
2962 cmd := NewStatusCmd(ctx, "config", "rewrite")
2963 _ = c(ctx, cmd)
2964 return cmd
2965}
2966
2967func (c cmdable) DBSize(ctx context.Context) *IntCmd {
2968 cmd := NewIntCmd(ctx, "dbsize")
2969 _ = c(ctx, cmd)
2970 return cmd
2971}
2972
2973func (c cmdable) FlushAll(ctx context.Context) *StatusCmd {
2974 cmd := NewStatusCmd(ctx, "flushall")
2975 _ = c(ctx, cmd)
2976 return cmd
2977}
2978
2979func (c cmdable) FlushAllAsync(ctx context.Context) *StatusCmd {
2980 cmd := NewStatusCmd(ctx, "flushall", "async")
2981 _ = c(ctx, cmd)
2982 return cmd
2983}
2984
2985func (c cmdable) FlushDB(ctx context.Context) *StatusCmd {
2986 cmd := NewStatusCmd(ctx, "flushdb")
2987 _ = c(ctx, cmd)
2988 return cmd
2989}
2990
2991func (c cmdable) FlushDBAsync(ctx context.Context) *StatusCmd {
2992 cmd := NewStatusCmd(ctx, "flushdb", "async")
2993 _ = c(ctx, cmd)
2994 return cmd
2995}
2996
2997func (c cmdable) Info(ctx context.Context, section ...string) *StringCmd {
2998 args := []interface{}{"info"}
2999 if len(section) > 0 {
3000 args = append(args, section[0])
3001 }
3002 cmd := NewStringCmd(ctx, args...)
3003 _ = c(ctx, cmd)
3004 return cmd
3005}
3006
3007func (c cmdable) LastSave(ctx context.Context) *IntCmd {
3008 cmd := NewIntCmd(ctx, "lastsave")
3009 _ = c(ctx, cmd)
3010 return cmd
3011}
3012
3013func (c cmdable) Save(ctx context.Context) *StatusCmd {
3014 cmd := NewStatusCmd(ctx, "save")
3015 _ = c(ctx, cmd)
3016 return cmd
3017}
3018
3019func (c cmdable) shutdown(ctx context.Context, modifier string) *StatusCmd {
3020 var args []interface{}
3021 if modifier == "" {
3022 args = []interface{}{"shutdown"}
3023 } else {
3024 args = []interface{}{"shutdown", modifier}
3025 }
3026 cmd := NewStatusCmd(ctx, args...)
3027 _ = c(ctx, cmd)
3028 if err := cmd.Err(); err != nil {
3029 if err == io.EOF {
3030 // Server quit as expected.
3031 cmd.err = nil
3032 }
3033 } else {
3034 // Server did not quit. String reply contains the reason.
3035 cmd.err = errors.New(cmd.val)
3036 cmd.val = ""
3037 }
3038 return cmd
3039}
3040
3041func (c cmdable) Shutdown(ctx context.Context) *StatusCmd {
3042 return c.shutdown(ctx, "")
3043}
3044
3045func (c cmdable) ShutdownSave(ctx context.Context) *StatusCmd {
3046 return c.shutdown(ctx, "save")
3047}
3048
3049func (c cmdable) ShutdownNoSave(ctx context.Context) *StatusCmd {
3050 return c.shutdown(ctx, "nosave")
3051}
3052
3053func (c cmdable) SlaveOf(ctx context.Context, host, port string) *StatusCmd {
3054 cmd := NewStatusCmd(ctx, "slaveof", host, port)
3055 _ = c(ctx, cmd)
3056 return cmd
3057}
3058
3059func (c cmdable) SlowLogGet(ctx context.Context, num int64) *SlowLogCmd {
3060 cmd := NewSlowLogCmd(context.Background(), "slowlog", "get", num)
3061 _ = c(ctx, cmd)
3062 return cmd
3063}
3064
3065func (c cmdable) Sync(_ context.Context) {
3066 panic("not implemented")
3067}
3068
3069func (c cmdable) Time(ctx context.Context) *TimeCmd {
3070 cmd := NewTimeCmd(ctx, "time")
3071 _ = c(ctx, cmd)
3072 return cmd
3073}
3074
3075func (c cmdable) DebugObject(ctx context.Context, key string) *StringCmd {
3076 cmd := NewStringCmd(ctx, "debug", "object", key)
3077 _ = c(ctx, cmd)
3078 return cmd
3079}
3080
3081func (c cmdable) ReadOnly(ctx context.Context) *StatusCmd {
3082 cmd := NewStatusCmd(ctx, "readonly")
3083 _ = c(ctx, cmd)
3084 return cmd
3085}
3086
3087func (c cmdable) ReadWrite(ctx context.Context) *StatusCmd {
3088 cmd := NewStatusCmd(ctx, "readwrite")
3089 _ = c(ctx, cmd)
3090 return cmd
3091}
3092
3093func (c cmdable) MemoryUsage(ctx context.Context, key string, samples ...int) *IntCmd {
3094 args := []interface{}{"memory", "usage", key}
3095 if len(samples) > 0 {
3096 if len(samples) != 1 {
3097 panic("MemoryUsage expects single sample count")
3098 }
3099 args = append(args, "SAMPLES", samples[0])
3100 }
3101 cmd := NewIntCmd(ctx, args...)
3102 cmd.SetFirstKeyPos(2)
3103 _ = c(ctx, cmd)
3104 return cmd
3105}
3106
3107//------------------------------------------------------------------------------
3108
3109func (c cmdable) Eval(ctx context.Context, script string, keys []string, args ...interface{}) *Cmd {
3110 cmdArgs := make([]interface{}, 3+len(keys), 3+len(keys)+len(args))
3111 cmdArgs[0] = "eval"
3112 cmdArgs[1] = script
3113 cmdArgs[2] = len(keys)
3114 for i, key := range keys {
3115 cmdArgs[3+i] = key
3116 }
3117 cmdArgs = appendArgs(cmdArgs, args)
3118 cmd := NewCmd(ctx, cmdArgs...)
3119 cmd.SetFirstKeyPos(3)
3120 _ = c(ctx, cmd)
3121 return cmd
3122}
3123
3124func (c cmdable) EvalSha(ctx context.Context, sha1 string, keys []string, args ...interface{}) *Cmd {
3125 cmdArgs := make([]interface{}, 3+len(keys), 3+len(keys)+len(args))
3126 cmdArgs[0] = "evalsha"
3127 cmdArgs[1] = sha1
3128 cmdArgs[2] = len(keys)
3129 for i, key := range keys {
3130 cmdArgs[3+i] = key
3131 }
3132 cmdArgs = appendArgs(cmdArgs, args)
3133 cmd := NewCmd(ctx, cmdArgs...)
3134 cmd.SetFirstKeyPos(3)
3135 _ = c(ctx, cmd)
3136 return cmd
3137}
3138
3139func (c cmdable) ScriptExists(ctx context.Context, hashes ...string) *BoolSliceCmd {
3140 args := make([]interface{}, 2+len(hashes))
3141 args[0] = "script"
3142 args[1] = "exists"
3143 for i, hash := range hashes {
3144 args[2+i] = hash
3145 }
3146 cmd := NewBoolSliceCmd(ctx, args...)
3147 _ = c(ctx, cmd)
3148 return cmd
3149}
3150
3151func (c cmdable) ScriptFlush(ctx context.Context) *StatusCmd {
3152 cmd := NewStatusCmd(ctx, "script", "flush")
3153 _ = c(ctx, cmd)
3154 return cmd
3155}
3156
3157func (c cmdable) ScriptKill(ctx context.Context) *StatusCmd {
3158 cmd := NewStatusCmd(ctx, "script", "kill")
3159 _ = c(ctx, cmd)
3160 return cmd
3161}
3162
3163func (c cmdable) ScriptLoad(ctx context.Context, script string) *StringCmd {
3164 cmd := NewStringCmd(ctx, "script", "load", script)
3165 _ = c(ctx, cmd)
3166 return cmd
3167}
3168
3169//------------------------------------------------------------------------------
3170
3171// Publish posts the message to the channel.
3172func (c cmdable) Publish(ctx context.Context, channel string, message interface{}) *IntCmd {
3173 cmd := NewIntCmd(ctx, "publish", channel, message)
3174 _ = c(ctx, cmd)
3175 return cmd
3176}
3177
3178func (c cmdable) PubSubChannels(ctx context.Context, pattern string) *StringSliceCmd {
3179 args := []interface{}{"pubsub", "channels"}
3180 if pattern != "*" {
3181 args = append(args, pattern)
3182 }
3183 cmd := NewStringSliceCmd(ctx, args...)
3184 _ = c(ctx, cmd)
3185 return cmd
3186}
3187
3188func (c cmdable) PubSubNumSub(ctx context.Context, channels ...string) *StringIntMapCmd {
3189 args := make([]interface{}, 2+len(channels))
3190 args[0] = "pubsub"
3191 args[1] = "numsub"
3192 for i, channel := range channels {
3193 args[2+i] = channel
3194 }
3195 cmd := NewStringIntMapCmd(ctx, args...)
3196 _ = c(ctx, cmd)
3197 return cmd
3198}
3199
3200func (c cmdable) PubSubNumPat(ctx context.Context) *IntCmd {
3201 cmd := NewIntCmd(ctx, "pubsub", "numpat")
3202 _ = c(ctx, cmd)
3203 return cmd
3204}
3205
3206//------------------------------------------------------------------------------
3207
3208func (c cmdable) ClusterSlots(ctx context.Context) *ClusterSlotsCmd {
3209 cmd := NewClusterSlotsCmd(ctx, "cluster", "slots")
3210 _ = c(ctx, cmd)
3211 return cmd
3212}
3213
3214func (c cmdable) ClusterNodes(ctx context.Context) *StringCmd {
3215 cmd := NewStringCmd(ctx, "cluster", "nodes")
3216 _ = c(ctx, cmd)
3217 return cmd
3218}
3219
3220func (c cmdable) ClusterMeet(ctx context.Context, host, port string) *StatusCmd {
3221 cmd := NewStatusCmd(ctx, "cluster", "meet", host, port)
3222 _ = c(ctx, cmd)
3223 return cmd
3224}
3225
3226func (c cmdable) ClusterForget(ctx context.Context, nodeID string) *StatusCmd {
3227 cmd := NewStatusCmd(ctx, "cluster", "forget", nodeID)
3228 _ = c(ctx, cmd)
3229 return cmd
3230}
3231
3232func (c cmdable) ClusterReplicate(ctx context.Context, nodeID string) *StatusCmd {
3233 cmd := NewStatusCmd(ctx, "cluster", "replicate", nodeID)
3234 _ = c(ctx, cmd)
3235 return cmd
3236}
3237
3238func (c cmdable) ClusterResetSoft(ctx context.Context) *StatusCmd {
3239 cmd := NewStatusCmd(ctx, "cluster", "reset", "soft")
3240 _ = c(ctx, cmd)
3241 return cmd
3242}
3243
3244func (c cmdable) ClusterResetHard(ctx context.Context) *StatusCmd {
3245 cmd := NewStatusCmd(ctx, "cluster", "reset", "hard")
3246 _ = c(ctx, cmd)
3247 return cmd
3248}
3249
3250func (c cmdable) ClusterInfo(ctx context.Context) *StringCmd {
3251 cmd := NewStringCmd(ctx, "cluster", "info")
3252 _ = c(ctx, cmd)
3253 return cmd
3254}
3255
3256func (c cmdable) ClusterKeySlot(ctx context.Context, key string) *IntCmd {
3257 cmd := NewIntCmd(ctx, "cluster", "keyslot", key)
3258 _ = c(ctx, cmd)
3259 return cmd
3260}
3261
3262func (c cmdable) ClusterGetKeysInSlot(ctx context.Context, slot int, count int) *StringSliceCmd {
3263 cmd := NewStringSliceCmd(ctx, "cluster", "getkeysinslot", slot, count)
3264 _ = c(ctx, cmd)
3265 return cmd
3266}
3267
3268func (c cmdable) ClusterCountFailureReports(ctx context.Context, nodeID string) *IntCmd {
3269 cmd := NewIntCmd(ctx, "cluster", "count-failure-reports", nodeID)
3270 _ = c(ctx, cmd)
3271 return cmd
3272}
3273
3274func (c cmdable) ClusterCountKeysInSlot(ctx context.Context, slot int) *IntCmd {
3275 cmd := NewIntCmd(ctx, "cluster", "countkeysinslot", slot)
3276 _ = c(ctx, cmd)
3277 return cmd
3278}
3279
3280func (c cmdable) ClusterDelSlots(ctx context.Context, slots ...int) *StatusCmd {
3281 args := make([]interface{}, 2+len(slots))
3282 args[0] = "cluster"
3283 args[1] = "delslots"
3284 for i, slot := range slots {
3285 args[2+i] = slot
3286 }
3287 cmd := NewStatusCmd(ctx, args...)
3288 _ = c(ctx, cmd)
3289 return cmd
3290}
3291
3292func (c cmdable) ClusterDelSlotsRange(ctx context.Context, min, max int) *StatusCmd {
3293 size := max - min + 1
3294 slots := make([]int, size)
3295 for i := 0; i < size; i++ {
3296 slots[i] = min + i
3297 }
3298 return c.ClusterDelSlots(ctx, slots...)
3299}
3300
3301func (c cmdable) ClusterSaveConfig(ctx context.Context) *StatusCmd {
3302 cmd := NewStatusCmd(ctx, "cluster", "saveconfig")
3303 _ = c(ctx, cmd)
3304 return cmd
3305}
3306
3307func (c cmdable) ClusterSlaves(ctx context.Context, nodeID string) *StringSliceCmd {
3308 cmd := NewStringSliceCmd(ctx, "cluster", "slaves", nodeID)
3309 _ = c(ctx, cmd)
3310 return cmd
3311}
3312
3313func (c cmdable) ClusterFailover(ctx context.Context) *StatusCmd {
3314 cmd := NewStatusCmd(ctx, "cluster", "failover")
3315 _ = c(ctx, cmd)
3316 return cmd
3317}
3318
3319func (c cmdable) ClusterAddSlots(ctx context.Context, slots ...int) *StatusCmd {
3320 args := make([]interface{}, 2+len(slots))
3321 args[0] = "cluster"
3322 args[1] = "addslots"
3323 for i, num := range slots {
3324 args[2+i] = num
3325 }
3326 cmd := NewStatusCmd(ctx, args...)
3327 _ = c(ctx, cmd)
3328 return cmd
3329}
3330
3331func (c cmdable) ClusterAddSlotsRange(ctx context.Context, min, max int) *StatusCmd {
3332 size := max - min + 1
3333 slots := make([]int, size)
3334 for i := 0; i < size; i++ {
3335 slots[i] = min + i
3336 }
3337 return c.ClusterAddSlots(ctx, slots...)
3338}
3339
3340//------------------------------------------------------------------------------
3341
3342func (c cmdable) GeoAdd(ctx context.Context, key string, geoLocation ...*GeoLocation) *IntCmd {
3343 args := make([]interface{}, 2+3*len(geoLocation))
3344 args[0] = "geoadd"
3345 args[1] = key
3346 for i, eachLoc := range geoLocation {
3347 args[2+3*i] = eachLoc.Longitude
3348 args[2+3*i+1] = eachLoc.Latitude
3349 args[2+3*i+2] = eachLoc.Name
3350 }
3351 cmd := NewIntCmd(ctx, args...)
3352 _ = c(ctx, cmd)
3353 return cmd
3354}
3355
3356// GeoRadius is a read-only GEORADIUS_RO command.
3357func (c cmdable) GeoRadius(
3358 ctx context.Context, key string, longitude, latitude float64, query *GeoRadiusQuery,
3359) *GeoLocationCmd {
3360 cmd := NewGeoLocationCmd(ctx, query, "georadius_ro", key, longitude, latitude)
3361 if query.Store != "" || query.StoreDist != "" {
3362 cmd.SetErr(errors.New("GeoRadius does not support Store or StoreDist"))
3363 return cmd
3364 }
3365 _ = c(ctx, cmd)
3366 return cmd
3367}
3368
3369// GeoRadiusStore is a writing GEORADIUS command.
3370func (c cmdable) GeoRadiusStore(
3371 ctx context.Context, key string, longitude, latitude float64, query *GeoRadiusQuery,
3372) *IntCmd {
3373 args := geoLocationArgs(query, "georadius", key, longitude, latitude)
3374 cmd := NewIntCmd(ctx, args...)
3375 if query.Store == "" && query.StoreDist == "" {
3376 cmd.SetErr(errors.New("GeoRadiusStore requires Store or StoreDist"))
3377 return cmd
3378 }
3379 _ = c(ctx, cmd)
3380 return cmd
3381}
3382
3383// GeoRadiusByMember is a read-only GEORADIUSBYMEMBER_RO command.
3384func (c cmdable) GeoRadiusByMember(
3385 ctx context.Context, key, member string, query *GeoRadiusQuery,
3386) *GeoLocationCmd {
3387 cmd := NewGeoLocationCmd(ctx, query, "georadiusbymember_ro", key, member)
3388 if query.Store != "" || query.StoreDist != "" {
3389 cmd.SetErr(errors.New("GeoRadiusByMember does not support Store or StoreDist"))
3390 return cmd
3391 }
3392 _ = c(ctx, cmd)
3393 return cmd
3394}
3395
3396// GeoRadiusByMemberStore is a writing GEORADIUSBYMEMBER command.
3397func (c cmdable) GeoRadiusByMemberStore(
3398 ctx context.Context, key, member string, query *GeoRadiusQuery,
3399) *IntCmd {
3400 args := geoLocationArgs(query, "georadiusbymember", key, member)
3401 cmd := NewIntCmd(ctx, args...)
3402 if query.Store == "" && query.StoreDist == "" {
3403 cmd.SetErr(errors.New("GeoRadiusByMemberStore requires Store or StoreDist"))
3404 return cmd
3405 }
3406 _ = c(ctx, cmd)
3407 return cmd
3408}
3409
3410func (c cmdable) GeoSearch(ctx context.Context, key string, q *GeoSearchQuery) *StringSliceCmd {
3411 args := make([]interface{}, 0, 13)
3412 args = append(args, "geosearch", key)
3413 args = geoSearchArgs(q, args)
3414 cmd := NewStringSliceCmd(ctx, args...)
3415 _ = c(ctx, cmd)
3416 return cmd
3417}
3418
3419func (c cmdable) GeoSearchLocation(
3420 ctx context.Context, key string, q *GeoSearchLocationQuery,
3421) *GeoSearchLocationCmd {
3422 args := make([]interface{}, 0, 16)
3423 args = append(args, "geosearch", key)
3424 args = geoSearchLocationArgs(q, args)
3425 cmd := NewGeoSearchLocationCmd(ctx, q, args...)
3426 _ = c(ctx, cmd)
3427 return cmd
3428}
3429
3430func (c cmdable) GeoSearchStore(ctx context.Context, key, store string, q *GeoSearchStoreQuery) *IntCmd {
3431 args := make([]interface{}, 0, 15)
3432 args = append(args, "geosearchstore", store, key)
3433 args = geoSearchArgs(&q.GeoSearchQuery, args)
3434 if q.StoreDist {
3435 args = append(args, "storedist")
3436 }
3437 cmd := NewIntCmd(ctx, args...)
3438 _ = c(ctx, cmd)
3439 return cmd
3440}
3441
3442func (c cmdable) GeoDist(
3443 ctx context.Context, key string, member1, member2, unit string,
3444) *FloatCmd {
3445 if unit == "" {
3446 unit = "km"
3447 }
3448 cmd := NewFloatCmd(ctx, "geodist", key, member1, member2, unit)
3449 _ = c(ctx, cmd)
3450 return cmd
3451}
3452
3453func (c cmdable) GeoHash(ctx context.Context, key string, members ...string) *StringSliceCmd {
3454 args := make([]interface{}, 2+len(members))
3455 args[0] = "geohash"
3456 args[1] = key
3457 for i, member := range members {
3458 args[2+i] = member
3459 }
3460 cmd := NewStringSliceCmd(ctx, args...)
3461 _ = c(ctx, cmd)
3462 return cmd
3463}
3464
3465func (c cmdable) GeoPos(ctx context.Context, key string, members ...string) *GeoPosCmd {
3466 args := make([]interface{}, 2+len(members))
3467 args[0] = "geopos"
3468 args[1] = key
3469 for i, member := range members {
3470 args[2+i] = member
3471 }
3472 cmd := NewGeoPosCmd(ctx, args...)
3473 _ = c(ctx, cmd)
3474 return cmd
3475}