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