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