blob: 4bb12a85be43837c5b4c93666161f57842ed2c4b [file] [log] [blame]
Naveen Sampath04696f72022-06-13 15:19:14 +05301package redis
2
3import (
4 "context"
5 "fmt"
6 "net"
7 "strconv"
8 "time"
9
10 "github.com/go-redis/redis/v8/internal"
11 "github.com/go-redis/redis/v8/internal/hscan"
12 "github.com/go-redis/redis/v8/internal/proto"
13 "github.com/go-redis/redis/v8/internal/util"
14)
15
16type Cmder interface {
17 Name() string
18 FullName() string
19 Args() []interface{}
20 String() string
21 stringArg(int) string
22 firstKeyPos() int8
23 SetFirstKeyPos(int8)
24
25 readTimeout() *time.Duration
26 readReply(rd *proto.Reader) error
27
28 SetErr(error)
29 Err() error
30}
31
32func setCmdsErr(cmds []Cmder, e error) {
33 for _, cmd := range cmds {
34 if cmd.Err() == nil {
35 cmd.SetErr(e)
36 }
37 }
38}
39
40func cmdsFirstErr(cmds []Cmder) error {
41 for _, cmd := range cmds {
42 if err := cmd.Err(); err != nil {
43 return err
44 }
45 }
46 return nil
47}
48
49func writeCmds(wr *proto.Writer, cmds []Cmder) error {
50 for _, cmd := range cmds {
51 if err := writeCmd(wr, cmd); err != nil {
52 return err
53 }
54 }
55 return nil
56}
57
58func writeCmd(wr *proto.Writer, cmd Cmder) error {
59 return wr.WriteArgs(cmd.Args())
60}
61
62func cmdFirstKeyPos(cmd Cmder, info *CommandInfo) int {
63 if pos := cmd.firstKeyPos(); pos != 0 {
64 return int(pos)
65 }
66
67 switch cmd.Name() {
68 case "eval", "evalsha":
69 if cmd.stringArg(2) != "0" {
70 return 3
71 }
72
73 return 0
74 case "publish":
75 return 1
76 case "memory":
77 // https://github.com/redis/redis/issues/7493
78 if cmd.stringArg(1) == "usage" {
79 return 2
80 }
81 }
82
83 if info != nil {
84 return int(info.FirstKeyPos)
85 }
86 return 0
87}
88
89func cmdString(cmd Cmder, val interface{}) string {
90 b := make([]byte, 0, 64)
91
92 for i, arg := range cmd.Args() {
93 if i > 0 {
94 b = append(b, ' ')
95 }
96 b = internal.AppendArg(b, arg)
97 }
98
99 if err := cmd.Err(); err != nil {
100 b = append(b, ": "...)
101 b = append(b, err.Error()...)
102 } else if val != nil {
103 b = append(b, ": "...)
104 b = internal.AppendArg(b, val)
105 }
106
107 return internal.String(b)
108}
109
110//------------------------------------------------------------------------------
111
112type baseCmd struct {
113 ctx context.Context
114 args []interface{}
115 err error
116 keyPos int8
117
118 _readTimeout *time.Duration
119}
120
121var _ Cmder = (*Cmd)(nil)
122
123func (cmd *baseCmd) Name() string {
124 if len(cmd.args) == 0 {
125 return ""
126 }
127 // Cmd name must be lower cased.
128 return internal.ToLower(cmd.stringArg(0))
129}
130
131func (cmd *baseCmd) FullName() string {
132 switch name := cmd.Name(); name {
133 case "cluster", "command":
134 if len(cmd.args) == 1 {
135 return name
136 }
137 if s2, ok := cmd.args[1].(string); ok {
138 return name + " " + s2
139 }
140 return name
141 default:
142 return name
143 }
144}
145
146func (cmd *baseCmd) Args() []interface{} {
147 return cmd.args
148}
149
150func (cmd *baseCmd) stringArg(pos int) string {
151 if pos < 0 || pos >= len(cmd.args) {
152 return ""
153 }
154 arg := cmd.args[pos]
155 switch v := arg.(type) {
156 case string:
157 return v
158 default:
159 // TODO: consider using appendArg
160 return fmt.Sprint(v)
161 }
162}
163
164func (cmd *baseCmd) firstKeyPos() int8 {
165 return cmd.keyPos
166}
167
168func (cmd *baseCmd) SetFirstKeyPos(keyPos int8) {
169 cmd.keyPos = keyPos
170}
171
172func (cmd *baseCmd) SetErr(e error) {
173 cmd.err = e
174}
175
176func (cmd *baseCmd) Err() error {
177 return cmd.err
178}
179
180func (cmd *baseCmd) readTimeout() *time.Duration {
181 return cmd._readTimeout
182}
183
184func (cmd *baseCmd) setReadTimeout(d time.Duration) {
185 cmd._readTimeout = &d
186}
187
188//------------------------------------------------------------------------------
189
190type Cmd struct {
191 baseCmd
192
193 val interface{}
194}
195
196func NewCmd(ctx context.Context, args ...interface{}) *Cmd {
197 return &Cmd{
198 baseCmd: baseCmd{
199 ctx: ctx,
200 args: args,
201 },
202 }
203}
204
205func (cmd *Cmd) String() string {
206 return cmdString(cmd, cmd.val)
207}
208
209func (cmd *Cmd) SetVal(val interface{}) {
210 cmd.val = val
211}
212
213func (cmd *Cmd) Val() interface{} {
214 return cmd.val
215}
216
217func (cmd *Cmd) Result() (interface{}, error) {
218 return cmd.val, cmd.err
219}
220
221func (cmd *Cmd) Text() (string, error) {
222 if cmd.err != nil {
223 return "", cmd.err
224 }
225 return toString(cmd.val)
226}
227
228func toString(val interface{}) (string, error) {
229 switch val := val.(type) {
230 case string:
231 return val, nil
232 default:
233 err := fmt.Errorf("redis: unexpected type=%T for String", val)
234 return "", err
235 }
236}
237
238func (cmd *Cmd) Int() (int, error) {
239 if cmd.err != nil {
240 return 0, cmd.err
241 }
242 switch val := cmd.val.(type) {
243 case int64:
244 return int(val), nil
245 case string:
246 return strconv.Atoi(val)
247 default:
248 err := fmt.Errorf("redis: unexpected type=%T for Int", val)
249 return 0, err
250 }
251}
252
253func (cmd *Cmd) Int64() (int64, error) {
254 if cmd.err != nil {
255 return 0, cmd.err
256 }
257 return toInt64(cmd.val)
258}
259
260func toInt64(val interface{}) (int64, error) {
261 switch val := val.(type) {
262 case int64:
263 return val, nil
264 case string:
265 return strconv.ParseInt(val, 10, 64)
266 default:
267 err := fmt.Errorf("redis: unexpected type=%T for Int64", val)
268 return 0, err
269 }
270}
271
272func (cmd *Cmd) Uint64() (uint64, error) {
273 if cmd.err != nil {
274 return 0, cmd.err
275 }
276 return toUint64(cmd.val)
277}
278
279func toUint64(val interface{}) (uint64, error) {
280 switch val := val.(type) {
281 case int64:
282 return uint64(val), nil
283 case string:
284 return strconv.ParseUint(val, 10, 64)
285 default:
286 err := fmt.Errorf("redis: unexpected type=%T for Uint64", val)
287 return 0, err
288 }
289}
290
291func (cmd *Cmd) Float32() (float32, error) {
292 if cmd.err != nil {
293 return 0, cmd.err
294 }
295 return toFloat32(cmd.val)
296}
297
298func toFloat32(val interface{}) (float32, error) {
299 switch val := val.(type) {
300 case int64:
301 return float32(val), nil
302 case string:
303 f, err := strconv.ParseFloat(val, 32)
304 if err != nil {
305 return 0, err
306 }
307 return float32(f), nil
308 default:
309 err := fmt.Errorf("redis: unexpected type=%T for Float32", val)
310 return 0, err
311 }
312}
313
314func (cmd *Cmd) Float64() (float64, error) {
315 if cmd.err != nil {
316 return 0, cmd.err
317 }
318 return toFloat64(cmd.val)
319}
320
321func toFloat64(val interface{}) (float64, error) {
322 switch val := val.(type) {
323 case int64:
324 return float64(val), nil
325 case string:
326 return strconv.ParseFloat(val, 64)
327 default:
328 err := fmt.Errorf("redis: unexpected type=%T for Float64", val)
329 return 0, err
330 }
331}
332
333func (cmd *Cmd) Bool() (bool, error) {
334 if cmd.err != nil {
335 return false, cmd.err
336 }
337 return toBool(cmd.val)
338}
339
340func toBool(val interface{}) (bool, error) {
341 switch val := val.(type) {
342 case int64:
343 return val != 0, nil
344 case string:
345 return strconv.ParseBool(val)
346 default:
347 err := fmt.Errorf("redis: unexpected type=%T for Bool", val)
348 return false, err
349 }
350}
351
352func (cmd *Cmd) Slice() ([]interface{}, error) {
353 if cmd.err != nil {
354 return nil, cmd.err
355 }
356 switch val := cmd.val.(type) {
357 case []interface{}:
358 return val, nil
359 default:
360 return nil, fmt.Errorf("redis: unexpected type=%T for Slice", val)
361 }
362}
363
364func (cmd *Cmd) StringSlice() ([]string, error) {
365 slice, err := cmd.Slice()
366 if err != nil {
367 return nil, err
368 }
369
370 ss := make([]string, len(slice))
371 for i, iface := range slice {
372 val, err := toString(iface)
373 if err != nil {
374 return nil, err
375 }
376 ss[i] = val
377 }
378 return ss, nil
379}
380
381func (cmd *Cmd) Int64Slice() ([]int64, error) {
382 slice, err := cmd.Slice()
383 if err != nil {
384 return nil, err
385 }
386
387 nums := make([]int64, len(slice))
388 for i, iface := range slice {
389 val, err := toInt64(iface)
390 if err != nil {
391 return nil, err
392 }
393 nums[i] = val
394 }
395 return nums, nil
396}
397
398func (cmd *Cmd) Uint64Slice() ([]uint64, error) {
399 slice, err := cmd.Slice()
400 if err != nil {
401 return nil, err
402 }
403
404 nums := make([]uint64, len(slice))
405 for i, iface := range slice {
406 val, err := toUint64(iface)
407 if err != nil {
408 return nil, err
409 }
410 nums[i] = val
411 }
412 return nums, nil
413}
414
415func (cmd *Cmd) Float32Slice() ([]float32, error) {
416 slice, err := cmd.Slice()
417 if err != nil {
418 return nil, err
419 }
420
421 floats := make([]float32, len(slice))
422 for i, iface := range slice {
423 val, err := toFloat32(iface)
424 if err != nil {
425 return nil, err
426 }
427 floats[i] = val
428 }
429 return floats, nil
430}
431
432func (cmd *Cmd) Float64Slice() ([]float64, error) {
433 slice, err := cmd.Slice()
434 if err != nil {
435 return nil, err
436 }
437
438 floats := make([]float64, len(slice))
439 for i, iface := range slice {
440 val, err := toFloat64(iface)
441 if err != nil {
442 return nil, err
443 }
444 floats[i] = val
445 }
446 return floats, nil
447}
448
449func (cmd *Cmd) BoolSlice() ([]bool, error) {
450 slice, err := cmd.Slice()
451 if err != nil {
452 return nil, err
453 }
454
455 bools := make([]bool, len(slice))
456 for i, iface := range slice {
457 val, err := toBool(iface)
458 if err != nil {
459 return nil, err
460 }
461 bools[i] = val
462 }
463 return bools, nil
464}
465
466func (cmd *Cmd) readReply(rd *proto.Reader) (err error) {
467 cmd.val, err = rd.ReadReply(sliceParser)
468 return err
469}
470
471// sliceParser implements proto.MultiBulkParse.
472func sliceParser(rd *proto.Reader, n int64) (interface{}, error) {
473 vals := make([]interface{}, n)
474 for i := 0; i < len(vals); i++ {
475 v, err := rd.ReadReply(sliceParser)
476 if err != nil {
477 if err == Nil {
478 vals[i] = nil
479 continue
480 }
481 if err, ok := err.(proto.RedisError); ok {
482 vals[i] = err
483 continue
484 }
485 return nil, err
486 }
487 vals[i] = v
488 }
489 return vals, nil
490}
491
492//------------------------------------------------------------------------------
493
494type SliceCmd struct {
495 baseCmd
496
497 val []interface{}
498}
499
500var _ Cmder = (*SliceCmd)(nil)
501
502func NewSliceCmd(ctx context.Context, args ...interface{}) *SliceCmd {
503 return &SliceCmd{
504 baseCmd: baseCmd{
505 ctx: ctx,
506 args: args,
507 },
508 }
509}
510
511func (cmd *SliceCmd) SetVal(val []interface{}) {
512 cmd.val = val
513}
514
515func (cmd *SliceCmd) Val() []interface{} {
516 return cmd.val
517}
518
519func (cmd *SliceCmd) Result() ([]interface{}, error) {
520 return cmd.val, cmd.err
521}
522
523func (cmd *SliceCmd) String() string {
524 return cmdString(cmd, cmd.val)
525}
526
527// Scan scans the results from the map into a destination struct. The map keys
528// are matched in the Redis struct fields by the `redis:"field"` tag.
529func (cmd *SliceCmd) Scan(dst interface{}) error {
530 if cmd.err != nil {
531 return cmd.err
532 }
533
534 // Pass the list of keys and values.
535 // Skip the first two args for: HMGET key
536 var args []interface{}
537 if cmd.args[0] == "hmget" {
538 args = cmd.args[2:]
539 } else {
540 // Otherwise, it's: MGET field field ...
541 args = cmd.args[1:]
542 }
543
544 return hscan.Scan(dst, args, cmd.val)
545}
546
547func (cmd *SliceCmd) readReply(rd *proto.Reader) error {
548 v, err := rd.ReadArrayReply(sliceParser)
549 if err != nil {
550 return err
551 }
552 cmd.val = v.([]interface{})
553 return nil
554}
555
556//------------------------------------------------------------------------------
557
558type StatusCmd struct {
559 baseCmd
560
561 val string
562}
563
564var _ Cmder = (*StatusCmd)(nil)
565
566func NewStatusCmd(ctx context.Context, args ...interface{}) *StatusCmd {
567 return &StatusCmd{
568 baseCmd: baseCmd{
569 ctx: ctx,
570 args: args,
571 },
572 }
573}
574
575func (cmd *StatusCmd) SetVal(val string) {
576 cmd.val = val
577}
578
579func (cmd *StatusCmd) Val() string {
580 return cmd.val
581}
582
583func (cmd *StatusCmd) Result() (string, error) {
584 return cmd.val, cmd.err
585}
586
587func (cmd *StatusCmd) String() string {
588 return cmdString(cmd, cmd.val)
589}
590
591func (cmd *StatusCmd) readReply(rd *proto.Reader) (err error) {
592 cmd.val, err = rd.ReadString()
593 return err
594}
595
596//------------------------------------------------------------------------------
597
598type IntCmd struct {
599 baseCmd
600
601 val int64
602}
603
604var _ Cmder = (*IntCmd)(nil)
605
606func NewIntCmd(ctx context.Context, args ...interface{}) *IntCmd {
607 return &IntCmd{
608 baseCmd: baseCmd{
609 ctx: ctx,
610 args: args,
611 },
612 }
613}
614
615func (cmd *IntCmd) SetVal(val int64) {
616 cmd.val = val
617}
618
619func (cmd *IntCmd) Val() int64 {
620 return cmd.val
621}
622
623func (cmd *IntCmd) Result() (int64, error) {
624 return cmd.val, cmd.err
625}
626
627func (cmd *IntCmd) Uint64() (uint64, error) {
628 return uint64(cmd.val), cmd.err
629}
630
631func (cmd *IntCmd) String() string {
632 return cmdString(cmd, cmd.val)
633}
634
635func (cmd *IntCmd) readReply(rd *proto.Reader) (err error) {
636 cmd.val, err = rd.ReadIntReply()
637 return err
638}
639
640//------------------------------------------------------------------------------
641
642type IntSliceCmd struct {
643 baseCmd
644
645 val []int64
646}
647
648var _ Cmder = (*IntSliceCmd)(nil)
649
650func NewIntSliceCmd(ctx context.Context, args ...interface{}) *IntSliceCmd {
651 return &IntSliceCmd{
652 baseCmd: baseCmd{
653 ctx: ctx,
654 args: args,
655 },
656 }
657}
658
659func (cmd *IntSliceCmd) SetVal(val []int64) {
660 cmd.val = val
661}
662
663func (cmd *IntSliceCmd) Val() []int64 {
664 return cmd.val
665}
666
667func (cmd *IntSliceCmd) Result() ([]int64, error) {
668 return cmd.val, cmd.err
669}
670
671func (cmd *IntSliceCmd) String() string {
672 return cmdString(cmd, cmd.val)
673}
674
675func (cmd *IntSliceCmd) readReply(rd *proto.Reader) error {
676 _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
677 cmd.val = make([]int64, n)
678 for i := 0; i < len(cmd.val); i++ {
679 num, err := rd.ReadIntReply()
680 if err != nil {
681 return nil, err
682 }
683 cmd.val[i] = num
684 }
685 return nil, nil
686 })
687 return err
688}
689
690//------------------------------------------------------------------------------
691
692type DurationCmd struct {
693 baseCmd
694
695 val time.Duration
696 precision time.Duration
697}
698
699var _ Cmder = (*DurationCmd)(nil)
700
701func NewDurationCmd(ctx context.Context, precision time.Duration, args ...interface{}) *DurationCmd {
702 return &DurationCmd{
703 baseCmd: baseCmd{
704 ctx: ctx,
705 args: args,
706 },
707 precision: precision,
708 }
709}
710
711func (cmd *DurationCmd) SetVal(val time.Duration) {
712 cmd.val = val
713}
714
715func (cmd *DurationCmd) Val() time.Duration {
716 return cmd.val
717}
718
719func (cmd *DurationCmd) Result() (time.Duration, error) {
720 return cmd.val, cmd.err
721}
722
723func (cmd *DurationCmd) String() string {
724 return cmdString(cmd, cmd.val)
725}
726
727func (cmd *DurationCmd) readReply(rd *proto.Reader) error {
728 n, err := rd.ReadIntReply()
729 if err != nil {
730 return err
731 }
732 switch n {
733 // -2 if the key does not exist
734 // -1 if the key exists but has no associated expire
735 case -2, -1:
736 cmd.val = time.Duration(n)
737 default:
738 cmd.val = time.Duration(n) * cmd.precision
739 }
740 return nil
741}
742
743//------------------------------------------------------------------------------
744
745type TimeCmd struct {
746 baseCmd
747
748 val time.Time
749}
750
751var _ Cmder = (*TimeCmd)(nil)
752
753func NewTimeCmd(ctx context.Context, args ...interface{}) *TimeCmd {
754 return &TimeCmd{
755 baseCmd: baseCmd{
756 ctx: ctx,
757 args: args,
758 },
759 }
760}
761
762func (cmd *TimeCmd) SetVal(val time.Time) {
763 cmd.val = val
764}
765
766func (cmd *TimeCmd) Val() time.Time {
767 return cmd.val
768}
769
770func (cmd *TimeCmd) Result() (time.Time, error) {
771 return cmd.val, cmd.err
772}
773
774func (cmd *TimeCmd) String() string {
775 return cmdString(cmd, cmd.val)
776}
777
778func (cmd *TimeCmd) readReply(rd *proto.Reader) error {
779 _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
780 if n != 2 {
781 return nil, fmt.Errorf("got %d elements, expected 2", n)
782 }
783
784 sec, err := rd.ReadInt()
785 if err != nil {
786 return nil, err
787 }
788
789 microsec, err := rd.ReadInt()
790 if err != nil {
791 return nil, err
792 }
793
794 cmd.val = time.Unix(sec, microsec*1000)
795 return nil, nil
796 })
797 return err
798}
799
800//------------------------------------------------------------------------------
801
802type BoolCmd struct {
803 baseCmd
804
805 val bool
806}
807
808var _ Cmder = (*BoolCmd)(nil)
809
810func NewBoolCmd(ctx context.Context, args ...interface{}) *BoolCmd {
811 return &BoolCmd{
812 baseCmd: baseCmd{
813 ctx: ctx,
814 args: args,
815 },
816 }
817}
818
819func (cmd *BoolCmd) SetVal(val bool) {
820 cmd.val = val
821}
822
823func (cmd *BoolCmd) Val() bool {
824 return cmd.val
825}
826
827func (cmd *BoolCmd) Result() (bool, error) {
828 return cmd.val, cmd.err
829}
830
831func (cmd *BoolCmd) String() string {
832 return cmdString(cmd, cmd.val)
833}
834
835func (cmd *BoolCmd) readReply(rd *proto.Reader) error {
836 v, err := rd.ReadReply(nil)
837 // `SET key value NX` returns nil when key already exists. But
838 // `SETNX key value` returns bool (0/1). So convert nil to bool.
839 if err == Nil {
840 cmd.val = false
841 return nil
842 }
843 if err != nil {
844 return err
845 }
846 switch v := v.(type) {
847 case int64:
848 cmd.val = v == 1
849 return nil
850 case string:
851 cmd.val = v == "OK"
852 return nil
853 default:
854 return fmt.Errorf("got %T, wanted int64 or string", v)
855 }
856}
857
858//------------------------------------------------------------------------------
859
860type StringCmd struct {
861 baseCmd
862
863 val string
864}
865
866var _ Cmder = (*StringCmd)(nil)
867
868func NewStringCmd(ctx context.Context, args ...interface{}) *StringCmd {
869 return &StringCmd{
870 baseCmd: baseCmd{
871 ctx: ctx,
872 args: args,
873 },
874 }
875}
876
877func (cmd *StringCmd) SetVal(val string) {
878 cmd.val = val
879}
880
881func (cmd *StringCmd) Val() string {
882 return cmd.val
883}
884
885func (cmd *StringCmd) Result() (string, error) {
886 return cmd.Val(), cmd.err
887}
888
889func (cmd *StringCmd) Bytes() ([]byte, error) {
890 return util.StringToBytes(cmd.val), cmd.err
891}
892
893func (cmd *StringCmd) Bool() (bool, error) {
894 if cmd.err != nil {
895 return false, cmd.err
896 }
897 return strconv.ParseBool(cmd.val)
898}
899
900func (cmd *StringCmd) Int() (int, error) {
901 if cmd.err != nil {
902 return 0, cmd.err
903 }
904 return strconv.Atoi(cmd.Val())
905}
906
907func (cmd *StringCmd) Int64() (int64, error) {
908 if cmd.err != nil {
909 return 0, cmd.err
910 }
911 return strconv.ParseInt(cmd.Val(), 10, 64)
912}
913
914func (cmd *StringCmd) Uint64() (uint64, error) {
915 if cmd.err != nil {
916 return 0, cmd.err
917 }
918 return strconv.ParseUint(cmd.Val(), 10, 64)
919}
920
921func (cmd *StringCmd) Float32() (float32, error) {
922 if cmd.err != nil {
923 return 0, cmd.err
924 }
925 f, err := strconv.ParseFloat(cmd.Val(), 32)
926 if err != nil {
927 return 0, err
928 }
929 return float32(f), nil
930}
931
932func (cmd *StringCmd) Float64() (float64, error) {
933 if cmd.err != nil {
934 return 0, cmd.err
935 }
936 return strconv.ParseFloat(cmd.Val(), 64)
937}
938
939func (cmd *StringCmd) Time() (time.Time, error) {
940 if cmd.err != nil {
941 return time.Time{}, cmd.err
942 }
943 return time.Parse(time.RFC3339Nano, cmd.Val())
944}
945
946func (cmd *StringCmd) Scan(val interface{}) error {
947 if cmd.err != nil {
948 return cmd.err
949 }
950 return proto.Scan([]byte(cmd.val), val)
951}
952
953func (cmd *StringCmd) String() string {
954 return cmdString(cmd, cmd.val)
955}
956
957func (cmd *StringCmd) readReply(rd *proto.Reader) (err error) {
958 cmd.val, err = rd.ReadString()
959 return err
960}
961
962//------------------------------------------------------------------------------
963
964type FloatCmd struct {
965 baseCmd
966
967 val float64
968}
969
970var _ Cmder = (*FloatCmd)(nil)
971
972func NewFloatCmd(ctx context.Context, args ...interface{}) *FloatCmd {
973 return &FloatCmd{
974 baseCmd: baseCmd{
975 ctx: ctx,
976 args: args,
977 },
978 }
979}
980
981func (cmd *FloatCmd) SetVal(val float64) {
982 cmd.val = val
983}
984
985func (cmd *FloatCmd) Val() float64 {
986 return cmd.val
987}
988
989func (cmd *FloatCmd) Result() (float64, error) {
990 return cmd.Val(), cmd.Err()
991}
992
993func (cmd *FloatCmd) String() string {
994 return cmdString(cmd, cmd.val)
995}
996
997func (cmd *FloatCmd) readReply(rd *proto.Reader) (err error) {
998 cmd.val, err = rd.ReadFloatReply()
999 return err
1000}
1001
1002//------------------------------------------------------------------------------
1003
1004type FloatSliceCmd struct {
1005 baseCmd
1006
1007 val []float64
1008}
1009
1010var _ Cmder = (*FloatSliceCmd)(nil)
1011
1012func NewFloatSliceCmd(ctx context.Context, args ...interface{}) *FloatSliceCmd {
1013 return &FloatSliceCmd{
1014 baseCmd: baseCmd{
1015 ctx: ctx,
1016 args: args,
1017 },
1018 }
1019}
1020
1021func (cmd *FloatSliceCmd) SetVal(val []float64) {
1022 cmd.val = val
1023}
1024
1025func (cmd *FloatSliceCmd) Val() []float64 {
1026 return cmd.val
1027}
1028
1029func (cmd *FloatSliceCmd) Result() ([]float64, error) {
1030 return cmd.val, cmd.err
1031}
1032
1033func (cmd *FloatSliceCmd) String() string {
1034 return cmdString(cmd, cmd.val)
1035}
1036
1037func (cmd *FloatSliceCmd) readReply(rd *proto.Reader) error {
1038 _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
1039 cmd.val = make([]float64, n)
1040 for i := 0; i < len(cmd.val); i++ {
1041 switch num, err := rd.ReadFloatReply(); {
1042 case err == Nil:
1043 cmd.val[i] = 0
1044 case err != nil:
1045 return nil, err
1046 default:
1047 cmd.val[i] = num
1048 }
1049 }
1050 return nil, nil
1051 })
1052 return err
1053}
1054
1055//------------------------------------------------------------------------------
1056
1057type StringSliceCmd struct {
1058 baseCmd
1059
1060 val []string
1061}
1062
1063var _ Cmder = (*StringSliceCmd)(nil)
1064
1065func NewStringSliceCmd(ctx context.Context, args ...interface{}) *StringSliceCmd {
1066 return &StringSliceCmd{
1067 baseCmd: baseCmd{
1068 ctx: ctx,
1069 args: args,
1070 },
1071 }
1072}
1073
1074func (cmd *StringSliceCmd) SetVal(val []string) {
1075 cmd.val = val
1076}
1077
1078func (cmd *StringSliceCmd) Val() []string {
1079 return cmd.val
1080}
1081
1082func (cmd *StringSliceCmd) Result() ([]string, error) {
1083 return cmd.Val(), cmd.Err()
1084}
1085
1086func (cmd *StringSliceCmd) String() string {
1087 return cmdString(cmd, cmd.val)
1088}
1089
1090func (cmd *StringSliceCmd) ScanSlice(container interface{}) error {
1091 return proto.ScanSlice(cmd.Val(), container)
1092}
1093
1094func (cmd *StringSliceCmd) readReply(rd *proto.Reader) error {
1095 _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
1096 cmd.val = make([]string, n)
1097 for i := 0; i < len(cmd.val); i++ {
1098 switch s, err := rd.ReadString(); {
1099 case err == Nil:
1100 cmd.val[i] = ""
1101 case err != nil:
1102 return nil, err
1103 default:
1104 cmd.val[i] = s
1105 }
1106 }
1107 return nil, nil
1108 })
1109 return err
1110}
1111
1112//------------------------------------------------------------------------------
1113
1114type BoolSliceCmd struct {
1115 baseCmd
1116
1117 val []bool
1118}
1119
1120var _ Cmder = (*BoolSliceCmd)(nil)
1121
1122func NewBoolSliceCmd(ctx context.Context, args ...interface{}) *BoolSliceCmd {
1123 return &BoolSliceCmd{
1124 baseCmd: baseCmd{
1125 ctx: ctx,
1126 args: args,
1127 },
1128 }
1129}
1130
1131func (cmd *BoolSliceCmd) SetVal(val []bool) {
1132 cmd.val = val
1133}
1134
1135func (cmd *BoolSliceCmd) Val() []bool {
1136 return cmd.val
1137}
1138
1139func (cmd *BoolSliceCmd) Result() ([]bool, error) {
1140 return cmd.val, cmd.err
1141}
1142
1143func (cmd *BoolSliceCmd) String() string {
1144 return cmdString(cmd, cmd.val)
1145}
1146
1147func (cmd *BoolSliceCmd) readReply(rd *proto.Reader) error {
1148 _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
1149 cmd.val = make([]bool, n)
1150 for i := 0; i < len(cmd.val); i++ {
1151 n, err := rd.ReadIntReply()
1152 if err != nil {
1153 return nil, err
1154 }
1155 cmd.val[i] = n == 1
1156 }
1157 return nil, nil
1158 })
1159 return err
1160}
1161
1162//------------------------------------------------------------------------------
1163
1164type StringStringMapCmd struct {
1165 baseCmd
1166
1167 val map[string]string
1168}
1169
1170var _ Cmder = (*StringStringMapCmd)(nil)
1171
1172func NewStringStringMapCmd(ctx context.Context, args ...interface{}) *StringStringMapCmd {
1173 return &StringStringMapCmd{
1174 baseCmd: baseCmd{
1175 ctx: ctx,
1176 args: args,
1177 },
1178 }
1179}
1180
1181func (cmd *StringStringMapCmd) SetVal(val map[string]string) {
1182 cmd.val = val
1183}
1184
1185func (cmd *StringStringMapCmd) Val() map[string]string {
1186 return cmd.val
1187}
1188
1189func (cmd *StringStringMapCmd) Result() (map[string]string, error) {
1190 return cmd.val, cmd.err
1191}
1192
1193func (cmd *StringStringMapCmd) String() string {
1194 return cmdString(cmd, cmd.val)
1195}
1196
1197// Scan scans the results from the map into a destination struct. The map keys
1198// are matched in the Redis struct fields by the `redis:"field"` tag.
1199func (cmd *StringStringMapCmd) Scan(dest interface{}) error {
1200 if cmd.err != nil {
1201 return cmd.err
1202 }
1203
1204 strct, err := hscan.Struct(dest)
1205 if err != nil {
1206 return err
1207 }
1208
1209 for k, v := range cmd.val {
1210 if err := strct.Scan(k, v); err != nil {
1211 return err
1212 }
1213 }
1214
1215 return nil
1216}
1217
1218func (cmd *StringStringMapCmd) readReply(rd *proto.Reader) error {
1219 _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
1220 cmd.val = make(map[string]string, n/2)
1221 for i := int64(0); i < n; i += 2 {
1222 key, err := rd.ReadString()
1223 if err != nil {
1224 return nil, err
1225 }
1226
1227 value, err := rd.ReadString()
1228 if err != nil {
1229 return nil, err
1230 }
1231
1232 cmd.val[key] = value
1233 }
1234 return nil, nil
1235 })
1236 return err
1237}
1238
1239//------------------------------------------------------------------------------
1240
1241type StringIntMapCmd struct {
1242 baseCmd
1243
1244 val map[string]int64
1245}
1246
1247var _ Cmder = (*StringIntMapCmd)(nil)
1248
1249func NewStringIntMapCmd(ctx context.Context, args ...interface{}) *StringIntMapCmd {
1250 return &StringIntMapCmd{
1251 baseCmd: baseCmd{
1252 ctx: ctx,
1253 args: args,
1254 },
1255 }
1256}
1257
1258func (cmd *StringIntMapCmd) SetVal(val map[string]int64) {
1259 cmd.val = val
1260}
1261
1262func (cmd *StringIntMapCmd) Val() map[string]int64 {
1263 return cmd.val
1264}
1265
1266func (cmd *StringIntMapCmd) Result() (map[string]int64, error) {
1267 return cmd.val, cmd.err
1268}
1269
1270func (cmd *StringIntMapCmd) String() string {
1271 return cmdString(cmd, cmd.val)
1272}
1273
1274func (cmd *StringIntMapCmd) readReply(rd *proto.Reader) error {
1275 _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
1276 cmd.val = make(map[string]int64, n/2)
1277 for i := int64(0); i < n; i += 2 {
1278 key, err := rd.ReadString()
1279 if err != nil {
1280 return nil, err
1281 }
1282
1283 n, err := rd.ReadIntReply()
1284 if err != nil {
1285 return nil, err
1286 }
1287
1288 cmd.val[key] = n
1289 }
1290 return nil, nil
1291 })
1292 return err
1293}
1294
1295//------------------------------------------------------------------------------
1296
1297type StringStructMapCmd struct {
1298 baseCmd
1299
1300 val map[string]struct{}
1301}
1302
1303var _ Cmder = (*StringStructMapCmd)(nil)
1304
1305func NewStringStructMapCmd(ctx context.Context, args ...interface{}) *StringStructMapCmd {
1306 return &StringStructMapCmd{
1307 baseCmd: baseCmd{
1308 ctx: ctx,
1309 args: args,
1310 },
1311 }
1312}
1313
1314func (cmd *StringStructMapCmd) SetVal(val map[string]struct{}) {
1315 cmd.val = val
1316}
1317
1318func (cmd *StringStructMapCmd) Val() map[string]struct{} {
1319 return cmd.val
1320}
1321
1322func (cmd *StringStructMapCmd) Result() (map[string]struct{}, error) {
1323 return cmd.val, cmd.err
1324}
1325
1326func (cmd *StringStructMapCmd) String() string {
1327 return cmdString(cmd, cmd.val)
1328}
1329
1330func (cmd *StringStructMapCmd) readReply(rd *proto.Reader) error {
1331 _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
1332 cmd.val = make(map[string]struct{}, n)
1333 for i := int64(0); i < n; i++ {
1334 key, err := rd.ReadString()
1335 if err != nil {
1336 return nil, err
1337 }
1338 cmd.val[key] = struct{}{}
1339 }
1340 return nil, nil
1341 })
1342 return err
1343}
1344
1345//------------------------------------------------------------------------------
1346
1347type XMessage struct {
1348 ID string
1349 Values map[string]interface{}
1350}
1351
1352type XMessageSliceCmd struct {
1353 baseCmd
1354
1355 val []XMessage
1356}
1357
1358var _ Cmder = (*XMessageSliceCmd)(nil)
1359
1360func NewXMessageSliceCmd(ctx context.Context, args ...interface{}) *XMessageSliceCmd {
1361 return &XMessageSliceCmd{
1362 baseCmd: baseCmd{
1363 ctx: ctx,
1364 args: args,
1365 },
1366 }
1367}
1368
1369func (cmd *XMessageSliceCmd) SetVal(val []XMessage) {
1370 cmd.val = val
1371}
1372
1373func (cmd *XMessageSliceCmd) Val() []XMessage {
1374 return cmd.val
1375}
1376
1377func (cmd *XMessageSliceCmd) Result() ([]XMessage, error) {
1378 return cmd.val, cmd.err
1379}
1380
1381func (cmd *XMessageSliceCmd) String() string {
1382 return cmdString(cmd, cmd.val)
1383}
1384
1385func (cmd *XMessageSliceCmd) readReply(rd *proto.Reader) error {
1386 var err error
1387 cmd.val, err = readXMessageSlice(rd)
1388 return err
1389}
1390
1391func readXMessageSlice(rd *proto.Reader) ([]XMessage, error) {
1392 n, err := rd.ReadArrayLen()
1393 if err != nil {
1394 return nil, err
1395 }
1396
1397 msgs := make([]XMessage, n)
1398 for i := 0; i < n; i++ {
1399 var err error
1400 msgs[i], err = readXMessage(rd)
1401 if err != nil {
1402 return nil, err
1403 }
1404 }
1405 return msgs, nil
1406}
1407
1408func readXMessage(rd *proto.Reader) (XMessage, error) {
1409 n, err := rd.ReadArrayLen()
1410 if err != nil {
1411 return XMessage{}, err
1412 }
1413 if n != 2 {
1414 return XMessage{}, fmt.Errorf("got %d, wanted 2", n)
1415 }
1416
1417 id, err := rd.ReadString()
1418 if err != nil {
1419 return XMessage{}, err
1420 }
1421
1422 var values map[string]interface{}
1423
1424 v, err := rd.ReadArrayReply(stringInterfaceMapParser)
1425 if err != nil {
1426 if err != proto.Nil {
1427 return XMessage{}, err
1428 }
1429 } else {
1430 values = v.(map[string]interface{})
1431 }
1432
1433 return XMessage{
1434 ID: id,
1435 Values: values,
1436 }, nil
1437}
1438
1439// stringInterfaceMapParser implements proto.MultiBulkParse.
1440func stringInterfaceMapParser(rd *proto.Reader, n int64) (interface{}, error) {
1441 m := make(map[string]interface{}, n/2)
1442 for i := int64(0); i < n; i += 2 {
1443 key, err := rd.ReadString()
1444 if err != nil {
1445 return nil, err
1446 }
1447
1448 value, err := rd.ReadString()
1449 if err != nil {
1450 return nil, err
1451 }
1452
1453 m[key] = value
1454 }
1455 return m, nil
1456}
1457
1458//------------------------------------------------------------------------------
1459
1460type XStream struct {
1461 Stream string
1462 Messages []XMessage
1463}
1464
1465type XStreamSliceCmd struct {
1466 baseCmd
1467
1468 val []XStream
1469}
1470
1471var _ Cmder = (*XStreamSliceCmd)(nil)
1472
1473func NewXStreamSliceCmd(ctx context.Context, args ...interface{}) *XStreamSliceCmd {
1474 return &XStreamSliceCmd{
1475 baseCmd: baseCmd{
1476 ctx: ctx,
1477 args: args,
1478 },
1479 }
1480}
1481
1482func (cmd *XStreamSliceCmd) SetVal(val []XStream) {
1483 cmd.val = val
1484}
1485
1486func (cmd *XStreamSliceCmd) Val() []XStream {
1487 return cmd.val
1488}
1489
1490func (cmd *XStreamSliceCmd) Result() ([]XStream, error) {
1491 return cmd.val, cmd.err
1492}
1493
1494func (cmd *XStreamSliceCmd) String() string {
1495 return cmdString(cmd, cmd.val)
1496}
1497
1498func (cmd *XStreamSliceCmd) readReply(rd *proto.Reader) error {
1499 _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
1500 cmd.val = make([]XStream, n)
1501 for i := 0; i < len(cmd.val); i++ {
1502 i := i
1503 _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
1504 if n != 2 {
1505 return nil, fmt.Errorf("got %d, wanted 2", n)
1506 }
1507
1508 stream, err := rd.ReadString()
1509 if err != nil {
1510 return nil, err
1511 }
1512
1513 msgs, err := readXMessageSlice(rd)
1514 if err != nil {
1515 return nil, err
1516 }
1517
1518 cmd.val[i] = XStream{
1519 Stream: stream,
1520 Messages: msgs,
1521 }
1522 return nil, nil
1523 })
1524 if err != nil {
1525 return nil, err
1526 }
1527 }
1528 return nil, nil
1529 })
1530 return err
1531}
1532
1533//------------------------------------------------------------------------------
1534
1535type XPending struct {
1536 Count int64
1537 Lower string
1538 Higher string
1539 Consumers map[string]int64
1540}
1541
1542type XPendingCmd struct {
1543 baseCmd
1544 val *XPending
1545}
1546
1547var _ Cmder = (*XPendingCmd)(nil)
1548
1549func NewXPendingCmd(ctx context.Context, args ...interface{}) *XPendingCmd {
1550 return &XPendingCmd{
1551 baseCmd: baseCmd{
1552 ctx: ctx,
1553 args: args,
1554 },
1555 }
1556}
1557
1558func (cmd *XPendingCmd) SetVal(val *XPending) {
1559 cmd.val = val
1560}
1561
1562func (cmd *XPendingCmd) Val() *XPending {
1563 return cmd.val
1564}
1565
1566func (cmd *XPendingCmd) Result() (*XPending, error) {
1567 return cmd.val, cmd.err
1568}
1569
1570func (cmd *XPendingCmd) String() string {
1571 return cmdString(cmd, cmd.val)
1572}
1573
1574func (cmd *XPendingCmd) readReply(rd *proto.Reader) error {
1575 _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
1576 if n != 4 {
1577 return nil, fmt.Errorf("got %d, wanted 4", n)
1578 }
1579
1580 count, err := rd.ReadIntReply()
1581 if err != nil {
1582 return nil, err
1583 }
1584
1585 lower, err := rd.ReadString()
1586 if err != nil && err != Nil {
1587 return nil, err
1588 }
1589
1590 higher, err := rd.ReadString()
1591 if err != nil && err != Nil {
1592 return nil, err
1593 }
1594
1595 cmd.val = &XPending{
1596 Count: count,
1597 Lower: lower,
1598 Higher: higher,
1599 }
1600 _, err = rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
1601 for i := int64(0); i < n; i++ {
1602 _, err = rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
1603 if n != 2 {
1604 return nil, fmt.Errorf("got %d, wanted 2", n)
1605 }
1606
1607 consumerName, err := rd.ReadString()
1608 if err != nil {
1609 return nil, err
1610 }
1611
1612 consumerPending, err := rd.ReadInt()
1613 if err != nil {
1614 return nil, err
1615 }
1616
1617 if cmd.val.Consumers == nil {
1618 cmd.val.Consumers = make(map[string]int64)
1619 }
1620 cmd.val.Consumers[consumerName] = consumerPending
1621
1622 return nil, nil
1623 })
1624 if err != nil {
1625 return nil, err
1626 }
1627 }
1628 return nil, nil
1629 })
1630 if err != nil && err != Nil {
1631 return nil, err
1632 }
1633
1634 return nil, nil
1635 })
1636 return err
1637}
1638
1639//------------------------------------------------------------------------------
1640
1641type XPendingExt struct {
1642 ID string
1643 Consumer string
1644 Idle time.Duration
1645 RetryCount int64
1646}
1647
1648type XPendingExtCmd struct {
1649 baseCmd
1650 val []XPendingExt
1651}
1652
1653var _ Cmder = (*XPendingExtCmd)(nil)
1654
1655func NewXPendingExtCmd(ctx context.Context, args ...interface{}) *XPendingExtCmd {
1656 return &XPendingExtCmd{
1657 baseCmd: baseCmd{
1658 ctx: ctx,
1659 args: args,
1660 },
1661 }
1662}
1663
1664func (cmd *XPendingExtCmd) SetVal(val []XPendingExt) {
1665 cmd.val = val
1666}
1667
1668func (cmd *XPendingExtCmd) Val() []XPendingExt {
1669 return cmd.val
1670}
1671
1672func (cmd *XPendingExtCmd) Result() ([]XPendingExt, error) {
1673 return cmd.val, cmd.err
1674}
1675
1676func (cmd *XPendingExtCmd) String() string {
1677 return cmdString(cmd, cmd.val)
1678}
1679
1680func (cmd *XPendingExtCmd) readReply(rd *proto.Reader) error {
1681 _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
1682 cmd.val = make([]XPendingExt, 0, n)
1683 for i := int64(0); i < n; i++ {
1684 _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
1685 if n != 4 {
1686 return nil, fmt.Errorf("got %d, wanted 4", n)
1687 }
1688
1689 id, err := rd.ReadString()
1690 if err != nil {
1691 return nil, err
1692 }
1693
1694 consumer, err := rd.ReadString()
1695 if err != nil && err != Nil {
1696 return nil, err
1697 }
1698
1699 idle, err := rd.ReadIntReply()
1700 if err != nil && err != Nil {
1701 return nil, err
1702 }
1703
1704 retryCount, err := rd.ReadIntReply()
1705 if err != nil && err != Nil {
1706 return nil, err
1707 }
1708
1709 cmd.val = append(cmd.val, XPendingExt{
1710 ID: id,
1711 Consumer: consumer,
1712 Idle: time.Duration(idle) * time.Millisecond,
1713 RetryCount: retryCount,
1714 })
1715 return nil, nil
1716 })
1717 if err != nil {
1718 return nil, err
1719 }
1720 }
1721 return nil, nil
1722 })
1723 return err
1724}
1725
1726//------------------------------------------------------------------------------
1727
1728type XAutoClaimCmd struct {
1729 baseCmd
1730
1731 start string
1732 val []XMessage
1733}
1734
1735var _ Cmder = (*XAutoClaimCmd)(nil)
1736
1737func NewXAutoClaimCmd(ctx context.Context, args ...interface{}) *XAutoClaimCmd {
1738 return &XAutoClaimCmd{
1739 baseCmd: baseCmd{
1740 ctx: ctx,
1741 args: args,
1742 },
1743 }
1744}
1745
1746func (cmd *XAutoClaimCmd) SetVal(val []XMessage, start string) {
1747 cmd.val = val
1748 cmd.start = start
1749}
1750
1751func (cmd *XAutoClaimCmd) Val() (messages []XMessage, start string) {
1752 return cmd.val, cmd.start
1753}
1754
1755func (cmd *XAutoClaimCmd) Result() (messages []XMessage, start string, err error) {
1756 return cmd.val, cmd.start, cmd.err
1757}
1758
1759func (cmd *XAutoClaimCmd) String() string {
1760 return cmdString(cmd, cmd.val)
1761}
1762
1763func (cmd *XAutoClaimCmd) readReply(rd *proto.Reader) error {
1764 _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
1765 if n != 2 {
1766 return nil, fmt.Errorf("got %d, wanted 2", n)
1767 }
1768 var err error
1769
1770 cmd.start, err = rd.ReadString()
1771 if err != nil {
1772 return nil, err
1773 }
1774
1775 cmd.val, err = readXMessageSlice(rd)
1776 if err != nil {
1777 return nil, err
1778 }
1779
1780 return nil, nil
1781 })
1782 return err
1783}
1784
1785//------------------------------------------------------------------------------
1786
1787type XAutoClaimJustIDCmd struct {
1788 baseCmd
1789
1790 start string
1791 val []string
1792}
1793
1794var _ Cmder = (*XAutoClaimJustIDCmd)(nil)
1795
1796func NewXAutoClaimJustIDCmd(ctx context.Context, args ...interface{}) *XAutoClaimJustIDCmd {
1797 return &XAutoClaimJustIDCmd{
1798 baseCmd: baseCmd{
1799 ctx: ctx,
1800 args: args,
1801 },
1802 }
1803}
1804
1805func (cmd *XAutoClaimJustIDCmd) SetVal(val []string, start string) {
1806 cmd.val = val
1807 cmd.start = start
1808}
1809
1810func (cmd *XAutoClaimJustIDCmd) Val() (ids []string, start string) {
1811 return cmd.val, cmd.start
1812}
1813
1814func (cmd *XAutoClaimJustIDCmd) Result() (ids []string, start string, err error) {
1815 return cmd.val, cmd.start, cmd.err
1816}
1817
1818func (cmd *XAutoClaimJustIDCmd) String() string {
1819 return cmdString(cmd, cmd.val)
1820}
1821
1822func (cmd *XAutoClaimJustIDCmd) readReply(rd *proto.Reader) error {
1823 _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
1824 if n != 2 {
1825 return nil, fmt.Errorf("got %d, wanted 2", n)
1826 }
1827 var err error
1828
1829 cmd.start, err = rd.ReadString()
1830 if err != nil {
1831 return nil, err
1832 }
1833
1834 nn, err := rd.ReadArrayLen()
1835 if err != nil {
1836 return nil, err
1837 }
1838
1839 cmd.val = make([]string, nn)
1840 for i := 0; i < nn; i++ {
1841 cmd.val[i], err = rd.ReadString()
1842 if err != nil {
1843 return nil, err
1844 }
1845 }
1846
1847 return nil, nil
1848 })
1849 return err
1850}
1851
1852//------------------------------------------------------------------------------
1853
1854type XInfoConsumersCmd struct {
1855 baseCmd
1856 val []XInfoConsumer
1857}
1858
1859type XInfoConsumer struct {
1860 Name string
1861 Pending int64
1862 Idle int64
1863}
1864
1865var _ Cmder = (*XInfoConsumersCmd)(nil)
1866
1867func NewXInfoConsumersCmd(ctx context.Context, stream string, group string) *XInfoConsumersCmd {
1868 return &XInfoConsumersCmd{
1869 baseCmd: baseCmd{
1870 ctx: ctx,
1871 args: []interface{}{"xinfo", "consumers", stream, group},
1872 },
1873 }
1874}
1875
1876func (cmd *XInfoConsumersCmd) SetVal(val []XInfoConsumer) {
1877 cmd.val = val
1878}
1879
1880func (cmd *XInfoConsumersCmd) Val() []XInfoConsumer {
1881 return cmd.val
1882}
1883
1884func (cmd *XInfoConsumersCmd) Result() ([]XInfoConsumer, error) {
1885 return cmd.val, cmd.err
1886}
1887
1888func (cmd *XInfoConsumersCmd) String() string {
1889 return cmdString(cmd, cmd.val)
1890}
1891
1892func (cmd *XInfoConsumersCmd) readReply(rd *proto.Reader) error {
1893 n, err := rd.ReadArrayLen()
1894 if err != nil {
1895 return err
1896 }
1897
1898 cmd.val = make([]XInfoConsumer, n)
1899
1900 for i := 0; i < n; i++ {
1901 cmd.val[i], err = readXConsumerInfo(rd)
1902 if err != nil {
1903 return err
1904 }
1905 }
1906
1907 return nil
1908}
1909
1910func readXConsumerInfo(rd *proto.Reader) (XInfoConsumer, error) {
1911 var consumer XInfoConsumer
1912
1913 n, err := rd.ReadArrayLen()
1914 if err != nil {
1915 return consumer, err
1916 }
1917 if n != 6 {
1918 return consumer, fmt.Errorf("redis: got %d elements in XINFO CONSUMERS reply, wanted 6", n)
1919 }
1920
1921 for i := 0; i < 3; i++ {
1922 key, err := rd.ReadString()
1923 if err != nil {
1924 return consumer, err
1925 }
1926
1927 val, err := rd.ReadString()
1928 if err != nil {
1929 return consumer, err
1930 }
1931
1932 switch key {
1933 case "name":
1934 consumer.Name = val
1935 case "pending":
1936 consumer.Pending, err = strconv.ParseInt(val, 0, 64)
1937 if err != nil {
1938 return consumer, err
1939 }
1940 case "idle":
1941 consumer.Idle, err = strconv.ParseInt(val, 0, 64)
1942 if err != nil {
1943 return consumer, err
1944 }
1945 default:
1946 return consumer, fmt.Errorf("redis: unexpected content %s in XINFO CONSUMERS reply", key)
1947 }
1948 }
1949
1950 return consumer, nil
1951}
1952
1953//------------------------------------------------------------------------------
1954
1955type XInfoGroupsCmd struct {
1956 baseCmd
1957 val []XInfoGroup
1958}
1959
1960type XInfoGroup struct {
1961 Name string
1962 Consumers int64
1963 Pending int64
1964 LastDeliveredID string
1965}
1966
1967var _ Cmder = (*XInfoGroupsCmd)(nil)
1968
1969func NewXInfoGroupsCmd(ctx context.Context, stream string) *XInfoGroupsCmd {
1970 return &XInfoGroupsCmd{
1971 baseCmd: baseCmd{
1972 ctx: ctx,
1973 args: []interface{}{"xinfo", "groups", stream},
1974 },
1975 }
1976}
1977
1978func (cmd *XInfoGroupsCmd) SetVal(val []XInfoGroup) {
1979 cmd.val = val
1980}
1981
1982func (cmd *XInfoGroupsCmd) Val() []XInfoGroup {
1983 return cmd.val
1984}
1985
1986func (cmd *XInfoGroupsCmd) Result() ([]XInfoGroup, error) {
1987 return cmd.val, cmd.err
1988}
1989
1990func (cmd *XInfoGroupsCmd) String() string {
1991 return cmdString(cmd, cmd.val)
1992}
1993
1994func (cmd *XInfoGroupsCmd) readReply(rd *proto.Reader) error {
1995 n, err := rd.ReadArrayLen()
1996 if err != nil {
1997 return err
1998 }
1999
2000 cmd.val = make([]XInfoGroup, n)
2001
2002 for i := 0; i < n; i++ {
2003 cmd.val[i], err = readXGroupInfo(rd)
2004 if err != nil {
2005 return err
2006 }
2007 }
2008
2009 return nil
2010}
2011
2012func readXGroupInfo(rd *proto.Reader) (XInfoGroup, error) {
2013 var group XInfoGroup
2014
2015 n, err := rd.ReadArrayLen()
2016 if err != nil {
2017 return group, err
2018 }
2019 if n != 8 {
2020 return group, fmt.Errorf("redis: got %d elements in XINFO GROUPS reply, wanted 8", n)
2021 }
2022
2023 for i := 0; i < 4; i++ {
2024 key, err := rd.ReadString()
2025 if err != nil {
2026 return group, err
2027 }
2028
2029 val, err := rd.ReadString()
2030 if err != nil {
2031 return group, err
2032 }
2033
2034 switch key {
2035 case "name":
2036 group.Name = val
2037 case "consumers":
2038 group.Consumers, err = strconv.ParseInt(val, 0, 64)
2039 if err != nil {
2040 return group, err
2041 }
2042 case "pending":
2043 group.Pending, err = strconv.ParseInt(val, 0, 64)
2044 if err != nil {
2045 return group, err
2046 }
2047 case "last-delivered-id":
2048 group.LastDeliveredID = val
2049 default:
2050 return group, fmt.Errorf("redis: unexpected content %s in XINFO GROUPS reply", key)
2051 }
2052 }
2053
2054 return group, nil
2055}
2056
2057//------------------------------------------------------------------------------
2058
2059type XInfoStreamCmd struct {
2060 baseCmd
2061 val *XInfoStream
2062}
2063
2064type XInfoStream struct {
2065 Length int64
2066 RadixTreeKeys int64
2067 RadixTreeNodes int64
2068 Groups int64
2069 LastGeneratedID string
2070 FirstEntry XMessage
2071 LastEntry XMessage
2072}
2073
2074var _ Cmder = (*XInfoStreamCmd)(nil)
2075
2076func NewXInfoStreamCmd(ctx context.Context, stream string) *XInfoStreamCmd {
2077 return &XInfoStreamCmd{
2078 baseCmd: baseCmd{
2079 ctx: ctx,
2080 args: []interface{}{"xinfo", "stream", stream},
2081 },
2082 }
2083}
2084
2085func (cmd *XInfoStreamCmd) SetVal(val *XInfoStream) {
2086 cmd.val = val
2087}
2088
2089func (cmd *XInfoStreamCmd) Val() *XInfoStream {
2090 return cmd.val
2091}
2092
2093func (cmd *XInfoStreamCmd) Result() (*XInfoStream, error) {
2094 return cmd.val, cmd.err
2095}
2096
2097func (cmd *XInfoStreamCmd) String() string {
2098 return cmdString(cmd, cmd.val)
2099}
2100
2101func (cmd *XInfoStreamCmd) readReply(rd *proto.Reader) error {
2102 v, err := rd.ReadReply(xStreamInfoParser)
2103 if err != nil {
2104 return err
2105 }
2106 cmd.val = v.(*XInfoStream)
2107 return nil
2108}
2109
2110func xStreamInfoParser(rd *proto.Reader, n int64) (interface{}, error) {
2111 if n != 14 {
2112 return nil, fmt.Errorf("redis: got %d elements in XINFO STREAM reply,"+
2113 "wanted 14", n)
2114 }
2115 var info XInfoStream
2116 for i := 0; i < 7; i++ {
2117 key, err := rd.ReadString()
2118 if err != nil {
2119 return nil, err
2120 }
2121 switch key {
2122 case "length":
2123 info.Length, err = rd.ReadIntReply()
2124 case "radix-tree-keys":
2125 info.RadixTreeKeys, err = rd.ReadIntReply()
2126 case "radix-tree-nodes":
2127 info.RadixTreeNodes, err = rd.ReadIntReply()
2128 case "groups":
2129 info.Groups, err = rd.ReadIntReply()
2130 case "last-generated-id":
2131 info.LastGeneratedID, err = rd.ReadString()
2132 case "first-entry":
2133 info.FirstEntry, err = readXMessage(rd)
2134 if err == Nil {
2135 err = nil
2136 }
2137 case "last-entry":
2138 info.LastEntry, err = readXMessage(rd)
2139 if err == Nil {
2140 err = nil
2141 }
2142 default:
2143 return nil, fmt.Errorf("redis: unexpected content %s "+
2144 "in XINFO STREAM reply", key)
2145 }
2146 if err != nil {
2147 return nil, err
2148 }
2149 }
2150 return &info, nil
2151}
2152
2153//------------------------------------------------------------------------------
2154
2155type XInfoStreamFullCmd struct {
2156 baseCmd
2157 val *XInfoStreamFull
2158}
2159
2160type XInfoStreamFull struct {
2161 Length int64
2162 RadixTreeKeys int64
2163 RadixTreeNodes int64
2164 LastGeneratedID string
2165 Entries []XMessage
2166 Groups []XInfoStreamGroup
2167}
2168
2169type XInfoStreamGroup struct {
2170 Name string
2171 LastDeliveredID string
2172 PelCount int64
2173 Pending []XInfoStreamGroupPending
2174 Consumers []XInfoStreamConsumer
2175}
2176
2177type XInfoStreamGroupPending struct {
2178 ID string
2179 Consumer string
2180 DeliveryTime time.Time
2181 DeliveryCount int64
2182}
2183
2184type XInfoStreamConsumer struct {
2185 Name string
2186 SeenTime time.Time
2187 PelCount int64
2188 Pending []XInfoStreamConsumerPending
2189}
2190
2191type XInfoStreamConsumerPending struct {
2192 ID string
2193 DeliveryTime time.Time
2194 DeliveryCount int64
2195}
2196
2197var _ Cmder = (*XInfoStreamFullCmd)(nil)
2198
2199func NewXInfoStreamFullCmd(ctx context.Context, args ...interface{}) *XInfoStreamFullCmd {
2200 return &XInfoStreamFullCmd{
2201 baseCmd: baseCmd{
2202 ctx: ctx,
2203 args: args,
2204 },
2205 }
2206}
2207
2208func (cmd *XInfoStreamFullCmd) SetVal(val *XInfoStreamFull) {
2209 cmd.val = val
2210}
2211
2212func (cmd *XInfoStreamFullCmd) Val() *XInfoStreamFull {
2213 return cmd.val
2214}
2215
2216func (cmd *XInfoStreamFullCmd) Result() (*XInfoStreamFull, error) {
2217 return cmd.val, cmd.err
2218}
2219
2220func (cmd *XInfoStreamFullCmd) String() string {
2221 return cmdString(cmd, cmd.val)
2222}
2223
2224func (cmd *XInfoStreamFullCmd) readReply(rd *proto.Reader) error {
2225 n, err := rd.ReadArrayLen()
2226 if err != nil {
2227 return err
2228 }
2229 if n != 12 {
2230 return fmt.Errorf("redis: got %d elements in XINFO STREAM FULL reply,"+
2231 "wanted 12", n)
2232 }
2233
2234 cmd.val = &XInfoStreamFull{}
2235
2236 for i := 0; i < 6; i++ {
2237 key, err := rd.ReadString()
2238 if err != nil {
2239 return err
2240 }
2241
2242 switch key {
2243 case "length":
2244 cmd.val.Length, err = rd.ReadIntReply()
2245 case "radix-tree-keys":
2246 cmd.val.RadixTreeKeys, err = rd.ReadIntReply()
2247 case "radix-tree-nodes":
2248 cmd.val.RadixTreeNodes, err = rd.ReadIntReply()
2249 case "last-generated-id":
2250 cmd.val.LastGeneratedID, err = rd.ReadString()
2251 case "entries":
2252 cmd.val.Entries, err = readXMessageSlice(rd)
2253 case "groups":
2254 cmd.val.Groups, err = readStreamGroups(rd)
2255 default:
2256 return fmt.Errorf("redis: unexpected content %s "+
2257 "in XINFO STREAM reply", key)
2258 }
2259 if err != nil {
2260 return err
2261 }
2262 }
2263 return nil
2264}
2265
2266func readStreamGroups(rd *proto.Reader) ([]XInfoStreamGroup, error) {
2267 n, err := rd.ReadArrayLen()
2268 if err != nil {
2269 return nil, err
2270 }
2271 groups := make([]XInfoStreamGroup, 0, n)
2272 for i := 0; i < n; i++ {
2273 nn, err := rd.ReadArrayLen()
2274 if err != nil {
2275 return nil, err
2276 }
2277 if nn != 10 {
2278 return nil, fmt.Errorf("redis: got %d elements in XINFO STREAM FULL reply,"+
2279 "wanted 10", nn)
2280 }
2281
2282 group := XInfoStreamGroup{}
2283
2284 for f := 0; f < 5; f++ {
2285 key, err := rd.ReadString()
2286 if err != nil {
2287 return nil, err
2288 }
2289
2290 switch key {
2291 case "name":
2292 group.Name, err = rd.ReadString()
2293 case "last-delivered-id":
2294 group.LastDeliveredID, err = rd.ReadString()
2295 case "pel-count":
2296 group.PelCount, err = rd.ReadIntReply()
2297 case "pending":
2298 group.Pending, err = readXInfoStreamGroupPending(rd)
2299 case "consumers":
2300 group.Consumers, err = readXInfoStreamConsumers(rd)
2301 default:
2302 return nil, fmt.Errorf("redis: unexpected content %s "+
2303 "in XINFO STREAM reply", key)
2304 }
2305
2306 if err != nil {
2307 return nil, err
2308 }
2309 }
2310
2311 groups = append(groups, group)
2312 }
2313
2314 return groups, nil
2315}
2316
2317func readXInfoStreamGroupPending(rd *proto.Reader) ([]XInfoStreamGroupPending, error) {
2318 n, err := rd.ReadArrayLen()
2319 if err != nil {
2320 return nil, err
2321 }
2322
2323 pending := make([]XInfoStreamGroupPending, 0, n)
2324
2325 for i := 0; i < n; i++ {
2326 nn, err := rd.ReadArrayLen()
2327 if err != nil {
2328 return nil, err
2329 }
2330 if nn != 4 {
2331 return nil, fmt.Errorf("redis: got %d elements in XINFO STREAM FULL reply,"+
2332 "wanted 4", nn)
2333 }
2334
2335 p := XInfoStreamGroupPending{}
2336
2337 p.ID, err = rd.ReadString()
2338 if err != nil {
2339 return nil, err
2340 }
2341
2342 p.Consumer, err = rd.ReadString()
2343 if err != nil {
2344 return nil, err
2345 }
2346
2347 delivery, err := rd.ReadIntReply()
2348 if err != nil {
2349 return nil, err
2350 }
2351 p.DeliveryTime = time.Unix(delivery/1000, delivery%1000*int64(time.Millisecond))
2352
2353 p.DeliveryCount, err = rd.ReadIntReply()
2354 if err != nil {
2355 return nil, err
2356 }
2357
2358 pending = append(pending, p)
2359 }
2360
2361 return pending, nil
2362}
2363
2364func readXInfoStreamConsumers(rd *proto.Reader) ([]XInfoStreamConsumer, error) {
2365 n, err := rd.ReadArrayLen()
2366 if err != nil {
2367 return nil, err
2368 }
2369
2370 consumers := make([]XInfoStreamConsumer, 0, n)
2371
2372 for i := 0; i < n; i++ {
2373 nn, err := rd.ReadArrayLen()
2374 if err != nil {
2375 return nil, err
2376 }
2377 if nn != 8 {
2378 return nil, fmt.Errorf("redis: got %d elements in XINFO STREAM FULL reply,"+
2379 "wanted 8", nn)
2380 }
2381
2382 c := XInfoStreamConsumer{}
2383
2384 for f := 0; f < 4; f++ {
2385 cKey, err := rd.ReadString()
2386 if err != nil {
2387 return nil, err
2388 }
2389
2390 switch cKey {
2391 case "name":
2392 c.Name, err = rd.ReadString()
2393 case "seen-time":
2394 seen, err := rd.ReadIntReply()
2395 if err != nil {
2396 return nil, err
2397 }
2398 c.SeenTime = time.Unix(seen/1000, seen%1000*int64(time.Millisecond))
2399 case "pel-count":
2400 c.PelCount, err = rd.ReadIntReply()
2401 case "pending":
2402 pendingNumber, err := rd.ReadArrayLen()
2403 if err != nil {
2404 return nil, err
2405 }
2406
2407 c.Pending = make([]XInfoStreamConsumerPending, 0, pendingNumber)
2408
2409 for pn := 0; pn < pendingNumber; pn++ {
2410 nn, err := rd.ReadArrayLen()
2411 if err != nil {
2412 return nil, err
2413 }
2414 if nn != 3 {
2415 return nil, fmt.Errorf("redis: got %d elements in XINFO STREAM reply,"+
2416 "wanted 3", nn)
2417 }
2418
2419 p := XInfoStreamConsumerPending{}
2420
2421 p.ID, err = rd.ReadString()
2422 if err != nil {
2423 return nil, err
2424 }
2425
2426 delivery, err := rd.ReadIntReply()
2427 if err != nil {
2428 return nil, err
2429 }
2430 p.DeliveryTime = time.Unix(delivery/1000, delivery%1000*int64(time.Millisecond))
2431
2432 p.DeliveryCount, err = rd.ReadIntReply()
2433 if err != nil {
2434 return nil, err
2435 }
2436
2437 c.Pending = append(c.Pending, p)
2438 }
2439 default:
2440 return nil, fmt.Errorf("redis: unexpected content %s "+
2441 "in XINFO STREAM reply", cKey)
2442 }
2443 if err != nil {
2444 return nil, err
2445 }
2446 }
2447 consumers = append(consumers, c)
2448 }
2449
2450 return consumers, nil
2451}
2452
2453//------------------------------------------------------------------------------
2454
2455type ZSliceCmd struct {
2456 baseCmd
2457
2458 val []Z
2459}
2460
2461var _ Cmder = (*ZSliceCmd)(nil)
2462
2463func NewZSliceCmd(ctx context.Context, args ...interface{}) *ZSliceCmd {
2464 return &ZSliceCmd{
2465 baseCmd: baseCmd{
2466 ctx: ctx,
2467 args: args,
2468 },
2469 }
2470}
2471
2472func (cmd *ZSliceCmd) SetVal(val []Z) {
2473 cmd.val = val
2474}
2475
2476func (cmd *ZSliceCmd) Val() []Z {
2477 return cmd.val
2478}
2479
2480func (cmd *ZSliceCmd) Result() ([]Z, error) {
2481 return cmd.val, cmd.err
2482}
2483
2484func (cmd *ZSliceCmd) String() string {
2485 return cmdString(cmd, cmd.val)
2486}
2487
2488func (cmd *ZSliceCmd) readReply(rd *proto.Reader) error {
2489 _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
2490 cmd.val = make([]Z, n/2)
2491 for i := 0; i < len(cmd.val); i++ {
2492 member, err := rd.ReadString()
2493 if err != nil {
2494 return nil, err
2495 }
2496
2497 score, err := rd.ReadFloatReply()
2498 if err != nil {
2499 return nil, err
2500 }
2501
2502 cmd.val[i] = Z{
2503 Member: member,
2504 Score: score,
2505 }
2506 }
2507 return nil, nil
2508 })
2509 return err
2510}
2511
2512//------------------------------------------------------------------------------
2513
2514type ZWithKeyCmd struct {
2515 baseCmd
2516
2517 val *ZWithKey
2518}
2519
2520var _ Cmder = (*ZWithKeyCmd)(nil)
2521
2522func NewZWithKeyCmd(ctx context.Context, args ...interface{}) *ZWithKeyCmd {
2523 return &ZWithKeyCmd{
2524 baseCmd: baseCmd{
2525 ctx: ctx,
2526 args: args,
2527 },
2528 }
2529}
2530
2531func (cmd *ZWithKeyCmd) SetVal(val *ZWithKey) {
2532 cmd.val = val
2533}
2534
2535func (cmd *ZWithKeyCmd) Val() *ZWithKey {
2536 return cmd.val
2537}
2538
2539func (cmd *ZWithKeyCmd) Result() (*ZWithKey, error) {
2540 return cmd.Val(), cmd.Err()
2541}
2542
2543func (cmd *ZWithKeyCmd) String() string {
2544 return cmdString(cmd, cmd.val)
2545}
2546
2547func (cmd *ZWithKeyCmd) readReply(rd *proto.Reader) error {
2548 _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
2549 if n != 3 {
2550 return nil, fmt.Errorf("got %d elements, expected 3", n)
2551 }
2552
2553 cmd.val = &ZWithKey{}
2554 var err error
2555
2556 cmd.val.Key, err = rd.ReadString()
2557 if err != nil {
2558 return nil, err
2559 }
2560
2561 cmd.val.Member, err = rd.ReadString()
2562 if err != nil {
2563 return nil, err
2564 }
2565
2566 cmd.val.Score, err = rd.ReadFloatReply()
2567 if err != nil {
2568 return nil, err
2569 }
2570
2571 return nil, nil
2572 })
2573 return err
2574}
2575
2576//------------------------------------------------------------------------------
2577
2578type ScanCmd struct {
2579 baseCmd
2580
2581 page []string
2582 cursor uint64
2583
2584 process cmdable
2585}
2586
2587var _ Cmder = (*ScanCmd)(nil)
2588
2589func NewScanCmd(ctx context.Context, process cmdable, args ...interface{}) *ScanCmd {
2590 return &ScanCmd{
2591 baseCmd: baseCmd{
2592 ctx: ctx,
2593 args: args,
2594 },
2595 process: process,
2596 }
2597}
2598
2599func (cmd *ScanCmd) SetVal(page []string, cursor uint64) {
2600 cmd.page = page
2601 cmd.cursor = cursor
2602}
2603
2604func (cmd *ScanCmd) Val() (keys []string, cursor uint64) {
2605 return cmd.page, cmd.cursor
2606}
2607
2608func (cmd *ScanCmd) Result() (keys []string, cursor uint64, err error) {
2609 return cmd.page, cmd.cursor, cmd.err
2610}
2611
2612func (cmd *ScanCmd) String() string {
2613 return cmdString(cmd, cmd.page)
2614}
2615
2616func (cmd *ScanCmd) readReply(rd *proto.Reader) (err error) {
2617 cmd.page, cmd.cursor, err = rd.ReadScanReply()
2618 return err
2619}
2620
2621// Iterator creates a new ScanIterator.
2622func (cmd *ScanCmd) Iterator() *ScanIterator {
2623 return &ScanIterator{
2624 cmd: cmd,
2625 }
2626}
2627
2628//------------------------------------------------------------------------------
2629
2630type ClusterNode struct {
2631 ID string
2632 Addr string
2633}
2634
2635type ClusterSlot struct {
2636 Start int
2637 End int
2638 Nodes []ClusterNode
2639}
2640
2641type ClusterSlotsCmd struct {
2642 baseCmd
2643
2644 val []ClusterSlot
2645}
2646
2647var _ Cmder = (*ClusterSlotsCmd)(nil)
2648
2649func NewClusterSlotsCmd(ctx context.Context, args ...interface{}) *ClusterSlotsCmd {
2650 return &ClusterSlotsCmd{
2651 baseCmd: baseCmd{
2652 ctx: ctx,
2653 args: args,
2654 },
2655 }
2656}
2657
2658func (cmd *ClusterSlotsCmd) SetVal(val []ClusterSlot) {
2659 cmd.val = val
2660}
2661
2662func (cmd *ClusterSlotsCmd) Val() []ClusterSlot {
2663 return cmd.val
2664}
2665
2666func (cmd *ClusterSlotsCmd) Result() ([]ClusterSlot, error) {
2667 return cmd.Val(), cmd.Err()
2668}
2669
2670func (cmd *ClusterSlotsCmd) String() string {
2671 return cmdString(cmd, cmd.val)
2672}
2673
2674func (cmd *ClusterSlotsCmd) readReply(rd *proto.Reader) error {
2675 _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
2676 cmd.val = make([]ClusterSlot, n)
2677 for i := 0; i < len(cmd.val); i++ {
2678 n, err := rd.ReadArrayLen()
2679 if err != nil {
2680 return nil, err
2681 }
2682 if n < 2 {
2683 err := fmt.Errorf("redis: got %d elements in cluster info, expected at least 2", n)
2684 return nil, err
2685 }
2686
2687 start, err := rd.ReadIntReply()
2688 if err != nil {
2689 return nil, err
2690 }
2691
2692 end, err := rd.ReadIntReply()
2693 if err != nil {
2694 return nil, err
2695 }
2696
2697 nodes := make([]ClusterNode, n-2)
2698 for j := 0; j < len(nodes); j++ {
2699 n, err := rd.ReadArrayLen()
2700 if err != nil {
2701 return nil, err
2702 }
2703 if n != 2 && n != 3 {
2704 err := fmt.Errorf("got %d elements in cluster info address, expected 2 or 3", n)
2705 return nil, err
2706 }
2707
2708 ip, err := rd.ReadString()
2709 if err != nil {
2710 return nil, err
2711 }
2712
2713 port, err := rd.ReadString()
2714 if err != nil {
2715 return nil, err
2716 }
2717
2718 nodes[j].Addr = net.JoinHostPort(ip, port)
2719
2720 if n == 3 {
2721 id, err := rd.ReadString()
2722 if err != nil {
2723 return nil, err
2724 }
2725 nodes[j].ID = id
2726 }
2727 }
2728
2729 cmd.val[i] = ClusterSlot{
2730 Start: int(start),
2731 End: int(end),
2732 Nodes: nodes,
2733 }
2734 }
2735 return nil, nil
2736 })
2737 return err
2738}
2739
2740//------------------------------------------------------------------------------
2741
2742// GeoLocation is used with GeoAdd to add geospatial location.
2743type GeoLocation struct {
2744 Name string
2745 Longitude, Latitude, Dist float64
2746 GeoHash int64
2747}
2748
2749// GeoRadiusQuery is used with GeoRadius to query geospatial index.
2750type GeoRadiusQuery struct {
2751 Radius float64
2752 // Can be m, km, ft, or mi. Default is km.
2753 Unit string
2754 WithCoord bool
2755 WithDist bool
2756 WithGeoHash bool
2757 Count int
2758 // Can be ASC or DESC. Default is no sort order.
2759 Sort string
2760 Store string
2761 StoreDist string
2762}
2763
2764type GeoLocationCmd struct {
2765 baseCmd
2766
2767 q *GeoRadiusQuery
2768 locations []GeoLocation
2769}
2770
2771var _ Cmder = (*GeoLocationCmd)(nil)
2772
2773func NewGeoLocationCmd(ctx context.Context, q *GeoRadiusQuery, args ...interface{}) *GeoLocationCmd {
2774 return &GeoLocationCmd{
2775 baseCmd: baseCmd{
2776 ctx: ctx,
2777 args: geoLocationArgs(q, args...),
2778 },
2779 q: q,
2780 }
2781}
2782
2783func geoLocationArgs(q *GeoRadiusQuery, args ...interface{}) []interface{} {
2784 args = append(args, q.Radius)
2785 if q.Unit != "" {
2786 args = append(args, q.Unit)
2787 } else {
2788 args = append(args, "km")
2789 }
2790 if q.WithCoord {
2791 args = append(args, "withcoord")
2792 }
2793 if q.WithDist {
2794 args = append(args, "withdist")
2795 }
2796 if q.WithGeoHash {
2797 args = append(args, "withhash")
2798 }
2799 if q.Count > 0 {
2800 args = append(args, "count", q.Count)
2801 }
2802 if q.Sort != "" {
2803 args = append(args, q.Sort)
2804 }
2805 if q.Store != "" {
2806 args = append(args, "store")
2807 args = append(args, q.Store)
2808 }
2809 if q.StoreDist != "" {
2810 args = append(args, "storedist")
2811 args = append(args, q.StoreDist)
2812 }
2813 return args
2814}
2815
2816func (cmd *GeoLocationCmd) SetVal(locations []GeoLocation) {
2817 cmd.locations = locations
2818}
2819
2820func (cmd *GeoLocationCmd) Val() []GeoLocation {
2821 return cmd.locations
2822}
2823
2824func (cmd *GeoLocationCmd) Result() ([]GeoLocation, error) {
2825 return cmd.locations, cmd.err
2826}
2827
2828func (cmd *GeoLocationCmd) String() string {
2829 return cmdString(cmd, cmd.locations)
2830}
2831
2832func (cmd *GeoLocationCmd) readReply(rd *proto.Reader) error {
2833 v, err := rd.ReadArrayReply(newGeoLocationSliceParser(cmd.q))
2834 if err != nil {
2835 return err
2836 }
2837 cmd.locations = v.([]GeoLocation)
2838 return nil
2839}
2840
2841func newGeoLocationSliceParser(q *GeoRadiusQuery) proto.MultiBulkParse {
2842 return func(rd *proto.Reader, n int64) (interface{}, error) {
2843 locs := make([]GeoLocation, 0, n)
2844 for i := int64(0); i < n; i++ {
2845 v, err := rd.ReadReply(newGeoLocationParser(q))
2846 if err != nil {
2847 return nil, err
2848 }
2849 switch vv := v.(type) {
2850 case string:
2851 locs = append(locs, GeoLocation{
2852 Name: vv,
2853 })
2854 case *GeoLocation:
2855 // TODO: avoid copying
2856 locs = append(locs, *vv)
2857 default:
2858 return nil, fmt.Errorf("got %T, expected string or *GeoLocation", v)
2859 }
2860 }
2861 return locs, nil
2862 }
2863}
2864
2865func newGeoLocationParser(q *GeoRadiusQuery) proto.MultiBulkParse {
2866 return func(rd *proto.Reader, n int64) (interface{}, error) {
2867 var loc GeoLocation
2868 var err error
2869
2870 loc.Name, err = rd.ReadString()
2871 if err != nil {
2872 return nil, err
2873 }
2874 if q.WithDist {
2875 loc.Dist, err = rd.ReadFloatReply()
2876 if err != nil {
2877 return nil, err
2878 }
2879 }
2880 if q.WithGeoHash {
2881 loc.GeoHash, err = rd.ReadIntReply()
2882 if err != nil {
2883 return nil, err
2884 }
2885 }
2886 if q.WithCoord {
2887 n, err := rd.ReadArrayLen()
2888 if err != nil {
2889 return nil, err
2890 }
2891 if n != 2 {
2892 return nil, fmt.Errorf("got %d coordinates, expected 2", n)
2893 }
2894
2895 loc.Longitude, err = rd.ReadFloatReply()
2896 if err != nil {
2897 return nil, err
2898 }
2899 loc.Latitude, err = rd.ReadFloatReply()
2900 if err != nil {
2901 return nil, err
2902 }
2903 }
2904
2905 return &loc, nil
2906 }
2907}
2908
2909//------------------------------------------------------------------------------
2910
2911// GeoSearchQuery is used for GEOSearch/GEOSearchStore command query.
2912type GeoSearchQuery struct {
2913 Member string
2914
2915 // Latitude and Longitude when using FromLonLat option.
2916 Longitude float64
2917 Latitude float64
2918
2919 // Distance and unit when using ByRadius option.
2920 // Can use m, km, ft, or mi. Default is km.
2921 Radius float64
2922 RadiusUnit string
2923
2924 // Height, width and unit when using ByBox option.
2925 // Can be m, km, ft, or mi. Default is km.
2926 BoxWidth float64
2927 BoxHeight float64
2928 BoxUnit string
2929
2930 // Can be ASC or DESC. Default is no sort order.
2931 Sort string
2932 Count int
2933 CountAny bool
2934}
2935
2936type GeoSearchLocationQuery struct {
2937 GeoSearchQuery
2938
2939 WithCoord bool
2940 WithDist bool
2941 WithHash bool
2942}
2943
2944type GeoSearchStoreQuery struct {
2945 GeoSearchQuery
2946
2947 // When using the StoreDist option, the command stores the items in a
2948 // sorted set populated with their distance from the center of the circle or box,
2949 // as a floating-point number, in the same unit specified for that shape.
2950 StoreDist bool
2951}
2952
2953func geoSearchLocationArgs(q *GeoSearchLocationQuery, args []interface{}) []interface{} {
2954 args = geoSearchArgs(&q.GeoSearchQuery, args)
2955
2956 if q.WithCoord {
2957 args = append(args, "withcoord")
2958 }
2959 if q.WithDist {
2960 args = append(args, "withdist")
2961 }
2962 if q.WithHash {
2963 args = append(args, "withhash")
2964 }
2965
2966 return args
2967}
2968
2969func geoSearchArgs(q *GeoSearchQuery, args []interface{}) []interface{} {
2970 if q.Member != "" {
2971 args = append(args, "frommember", q.Member)
2972 } else {
2973 args = append(args, "fromlonlat", q.Longitude, q.Latitude)
2974 }
2975
2976 if q.Radius > 0 {
2977 if q.RadiusUnit == "" {
2978 q.RadiusUnit = "km"
2979 }
2980 args = append(args, "byradius", q.Radius, q.RadiusUnit)
2981 } else {
2982 if q.BoxUnit == "" {
2983 q.BoxUnit = "km"
2984 }
2985 args = append(args, "bybox", q.BoxWidth, q.BoxHeight, q.BoxUnit)
2986 }
2987
2988 if q.Sort != "" {
2989 args = append(args, q.Sort)
2990 }
2991
2992 if q.Count > 0 {
2993 args = append(args, "count", q.Count)
2994 if q.CountAny {
2995 args = append(args, "any")
2996 }
2997 }
2998
2999 return args
3000}
3001
3002type GeoSearchLocationCmd struct {
3003 baseCmd
3004
3005 opt *GeoSearchLocationQuery
3006 val []GeoLocation
3007}
3008
3009var _ Cmder = (*GeoSearchLocationCmd)(nil)
3010
3011func NewGeoSearchLocationCmd(
3012 ctx context.Context, opt *GeoSearchLocationQuery, args ...interface{},
3013) *GeoSearchLocationCmd {
3014 return &GeoSearchLocationCmd{
3015 baseCmd: baseCmd{
3016 ctx: ctx,
3017 args: args,
3018 },
3019 opt: opt,
3020 }
3021}
3022
3023func (cmd *GeoSearchLocationCmd) SetVal(val []GeoLocation) {
3024 cmd.val = val
3025}
3026
3027func (cmd *GeoSearchLocationCmd) Val() []GeoLocation {
3028 return cmd.val
3029}
3030
3031func (cmd *GeoSearchLocationCmd) Result() ([]GeoLocation, error) {
3032 return cmd.val, cmd.err
3033}
3034
3035func (cmd *GeoSearchLocationCmd) String() string {
3036 return cmdString(cmd, cmd.val)
3037}
3038
3039func (cmd *GeoSearchLocationCmd) readReply(rd *proto.Reader) error {
3040 n, err := rd.ReadArrayLen()
3041 if err != nil {
3042 return err
3043 }
3044
3045 cmd.val = make([]GeoLocation, n)
3046 for i := 0; i < n; i++ {
3047 _, err = rd.ReadArrayLen()
3048 if err != nil {
3049 return err
3050 }
3051
3052 var loc GeoLocation
3053
3054 loc.Name, err = rd.ReadString()
3055 if err != nil {
3056 return err
3057 }
3058 if cmd.opt.WithDist {
3059 loc.Dist, err = rd.ReadFloatReply()
3060 if err != nil {
3061 return err
3062 }
3063 }
3064 if cmd.opt.WithHash {
3065 loc.GeoHash, err = rd.ReadIntReply()
3066 if err != nil {
3067 return err
3068 }
3069 }
3070 if cmd.opt.WithCoord {
3071 nn, err := rd.ReadArrayLen()
3072 if err != nil {
3073 return err
3074 }
3075 if nn != 2 {
3076 return fmt.Errorf("got %d coordinates, expected 2", nn)
3077 }
3078
3079 loc.Longitude, err = rd.ReadFloatReply()
3080 if err != nil {
3081 return err
3082 }
3083 loc.Latitude, err = rd.ReadFloatReply()
3084 if err != nil {
3085 return err
3086 }
3087 }
3088
3089 cmd.val[i] = loc
3090 }
3091
3092 return nil
3093}
3094
3095//------------------------------------------------------------------------------
3096
3097type GeoPos struct {
3098 Longitude, Latitude float64
3099}
3100
3101type GeoPosCmd struct {
3102 baseCmd
3103
3104 val []*GeoPos
3105}
3106
3107var _ Cmder = (*GeoPosCmd)(nil)
3108
3109func NewGeoPosCmd(ctx context.Context, args ...interface{}) *GeoPosCmd {
3110 return &GeoPosCmd{
3111 baseCmd: baseCmd{
3112 ctx: ctx,
3113 args: args,
3114 },
3115 }
3116}
3117
3118func (cmd *GeoPosCmd) SetVal(val []*GeoPos) {
3119 cmd.val = val
3120}
3121
3122func (cmd *GeoPosCmd) Val() []*GeoPos {
3123 return cmd.val
3124}
3125
3126func (cmd *GeoPosCmd) Result() ([]*GeoPos, error) {
3127 return cmd.Val(), cmd.Err()
3128}
3129
3130func (cmd *GeoPosCmd) String() string {
3131 return cmdString(cmd, cmd.val)
3132}
3133
3134func (cmd *GeoPosCmd) readReply(rd *proto.Reader) error {
3135 _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
3136 cmd.val = make([]*GeoPos, n)
3137 for i := 0; i < len(cmd.val); i++ {
3138 i := i
3139 _, err := rd.ReadReply(func(rd *proto.Reader, n int64) (interface{}, error) {
3140 longitude, err := rd.ReadFloatReply()
3141 if err != nil {
3142 return nil, err
3143 }
3144
3145 latitude, err := rd.ReadFloatReply()
3146 if err != nil {
3147 return nil, err
3148 }
3149
3150 cmd.val[i] = &GeoPos{
3151 Longitude: longitude,
3152 Latitude: latitude,
3153 }
3154 return nil, nil
3155 })
3156 if err != nil {
3157 if err == Nil {
3158 cmd.val[i] = nil
3159 continue
3160 }
3161 return nil, err
3162 }
3163 }
3164 return nil, nil
3165 })
3166 return err
3167}
3168
3169//------------------------------------------------------------------------------
3170
3171type CommandInfo struct {
3172 Name string
3173 Arity int8
3174 Flags []string
3175 ACLFlags []string
3176 FirstKeyPos int8
3177 LastKeyPos int8
3178 StepCount int8
3179 ReadOnly bool
3180}
3181
3182type CommandsInfoCmd struct {
3183 baseCmd
3184
3185 val map[string]*CommandInfo
3186}
3187
3188var _ Cmder = (*CommandsInfoCmd)(nil)
3189
3190func NewCommandsInfoCmd(ctx context.Context, args ...interface{}) *CommandsInfoCmd {
3191 return &CommandsInfoCmd{
3192 baseCmd: baseCmd{
3193 ctx: ctx,
3194 args: args,
3195 },
3196 }
3197}
3198
3199func (cmd *CommandsInfoCmd) SetVal(val map[string]*CommandInfo) {
3200 cmd.val = val
3201}
3202
3203func (cmd *CommandsInfoCmd) Val() map[string]*CommandInfo {
3204 return cmd.val
3205}
3206
3207func (cmd *CommandsInfoCmd) Result() (map[string]*CommandInfo, error) {
3208 return cmd.Val(), cmd.Err()
3209}
3210
3211func (cmd *CommandsInfoCmd) String() string {
3212 return cmdString(cmd, cmd.val)
3213}
3214
3215func (cmd *CommandsInfoCmd) readReply(rd *proto.Reader) error {
3216 _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
3217 cmd.val = make(map[string]*CommandInfo, n)
3218 for i := int64(0); i < n; i++ {
3219 v, err := rd.ReadReply(commandInfoParser)
3220 if err != nil {
3221 return nil, err
3222 }
3223 vv := v.(*CommandInfo)
3224 cmd.val[vv.Name] = vv
3225 }
3226 return nil, nil
3227 })
3228 return err
3229}
3230
3231func commandInfoParser(rd *proto.Reader, n int64) (interface{}, error) {
3232 const numArgRedis5 = 6
3233 const numArgRedis6 = 7
3234
3235 switch n {
3236 case numArgRedis5, numArgRedis6:
3237 // continue
3238 default:
3239 return nil, fmt.Errorf("redis: got %d elements in COMMAND reply, wanted 7", n)
3240 }
3241
3242 var cmd CommandInfo
3243 var err error
3244
3245 cmd.Name, err = rd.ReadString()
3246 if err != nil {
3247 return nil, err
3248 }
3249
3250 arity, err := rd.ReadIntReply()
3251 if err != nil {
3252 return nil, err
3253 }
3254 cmd.Arity = int8(arity)
3255
3256 _, err = rd.ReadReply(func(rd *proto.Reader, n int64) (interface{}, error) {
3257 cmd.Flags = make([]string, n)
3258 for i := 0; i < len(cmd.Flags); i++ {
3259 switch s, err := rd.ReadString(); {
3260 case err == Nil:
3261 cmd.Flags[i] = ""
3262 case err != nil:
3263 return nil, err
3264 default:
3265 cmd.Flags[i] = s
3266 }
3267 }
3268 return nil, nil
3269 })
3270 if err != nil {
3271 return nil, err
3272 }
3273
3274 firstKeyPos, err := rd.ReadIntReply()
3275 if err != nil {
3276 return nil, err
3277 }
3278 cmd.FirstKeyPos = int8(firstKeyPos)
3279
3280 lastKeyPos, err := rd.ReadIntReply()
3281 if err != nil {
3282 return nil, err
3283 }
3284 cmd.LastKeyPos = int8(lastKeyPos)
3285
3286 stepCount, err := rd.ReadIntReply()
3287 if err != nil {
3288 return nil, err
3289 }
3290 cmd.StepCount = int8(stepCount)
3291
3292 for _, flag := range cmd.Flags {
3293 if flag == "readonly" {
3294 cmd.ReadOnly = true
3295 break
3296 }
3297 }
3298
3299 if n == numArgRedis5 {
3300 return &cmd, nil
3301 }
3302
3303 _, err = rd.ReadReply(func(rd *proto.Reader, n int64) (interface{}, error) {
3304 cmd.ACLFlags = make([]string, n)
3305 for i := 0; i < len(cmd.ACLFlags); i++ {
3306 switch s, err := rd.ReadString(); {
3307 case err == Nil:
3308 cmd.ACLFlags[i] = ""
3309 case err != nil:
3310 return nil, err
3311 default:
3312 cmd.ACLFlags[i] = s
3313 }
3314 }
3315 return nil, nil
3316 })
3317 if err != nil {
3318 return nil, err
3319 }
3320
3321 return &cmd, nil
3322}
3323
3324//------------------------------------------------------------------------------
3325
3326type cmdsInfoCache struct {
3327 fn func(ctx context.Context) (map[string]*CommandInfo, error)
3328
3329 once internal.Once
3330 cmds map[string]*CommandInfo
3331}
3332
3333func newCmdsInfoCache(fn func(ctx context.Context) (map[string]*CommandInfo, error)) *cmdsInfoCache {
3334 return &cmdsInfoCache{
3335 fn: fn,
3336 }
3337}
3338
3339func (c *cmdsInfoCache) Get(ctx context.Context) (map[string]*CommandInfo, error) {
3340 err := c.once.Do(func() error {
3341 cmds, err := c.fn(ctx)
3342 if err != nil {
3343 return err
3344 }
3345
3346 // Extensions have cmd names in upper case. Convert them to lower case.
3347 for k, v := range cmds {
3348 lower := internal.ToLower(k)
3349 if lower != k {
3350 cmds[lower] = v
3351 }
3352 }
3353
3354 c.cmds = cmds
3355 return nil
3356 })
3357 return c.cmds, err
3358}
3359
3360//------------------------------------------------------------------------------
3361
3362type SlowLog struct {
3363 ID int64
3364 Time time.Time
3365 Duration time.Duration
3366 Args []string
3367 // These are also optional fields emitted only by Redis 4.0 or greater:
3368 // https://redis.io/commands/slowlog#output-format
3369 ClientAddr string
3370 ClientName string
3371}
3372
3373type SlowLogCmd struct {
3374 baseCmd
3375
3376 val []SlowLog
3377}
3378
3379var _ Cmder = (*SlowLogCmd)(nil)
3380
3381func NewSlowLogCmd(ctx context.Context, args ...interface{}) *SlowLogCmd {
3382 return &SlowLogCmd{
3383 baseCmd: baseCmd{
3384 ctx: ctx,
3385 args: args,
3386 },
3387 }
3388}
3389
3390func (cmd *SlowLogCmd) SetVal(val []SlowLog) {
3391 cmd.val = val
3392}
3393
3394func (cmd *SlowLogCmd) Val() []SlowLog {
3395 return cmd.val
3396}
3397
3398func (cmd *SlowLogCmd) Result() ([]SlowLog, error) {
3399 return cmd.Val(), cmd.Err()
3400}
3401
3402func (cmd *SlowLogCmd) String() string {
3403 return cmdString(cmd, cmd.val)
3404}
3405
3406func (cmd *SlowLogCmd) readReply(rd *proto.Reader) error {
3407 _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
3408 cmd.val = make([]SlowLog, n)
3409 for i := 0; i < len(cmd.val); i++ {
3410 n, err := rd.ReadArrayLen()
3411 if err != nil {
3412 return nil, err
3413 }
3414 if n < 4 {
3415 err := fmt.Errorf("redis: got %d elements in slowlog get, expected at least 4", n)
3416 return nil, err
3417 }
3418
3419 id, err := rd.ReadIntReply()
3420 if err != nil {
3421 return nil, err
3422 }
3423
3424 createdAt, err := rd.ReadIntReply()
3425 if err != nil {
3426 return nil, err
3427 }
3428 createdAtTime := time.Unix(createdAt, 0)
3429
3430 costs, err := rd.ReadIntReply()
3431 if err != nil {
3432 return nil, err
3433 }
3434 costsDuration := time.Duration(costs) * time.Microsecond
3435
3436 cmdLen, err := rd.ReadArrayLen()
3437 if err != nil {
3438 return nil, err
3439 }
3440 if cmdLen < 1 {
3441 err := fmt.Errorf("redis: got %d elements commands reply in slowlog get, expected at least 1", cmdLen)
3442 return nil, err
3443 }
3444
3445 cmdString := make([]string, cmdLen)
3446 for i := 0; i < cmdLen; i++ {
3447 cmdString[i], err = rd.ReadString()
3448 if err != nil {
3449 return nil, err
3450 }
3451 }
3452
3453 var address, name string
3454 for i := 4; i < n; i++ {
3455 str, err := rd.ReadString()
3456 if err != nil {
3457 return nil, err
3458 }
3459 if i == 4 {
3460 address = str
3461 } else if i == 5 {
3462 name = str
3463 }
3464 }
3465
3466 cmd.val[i] = SlowLog{
3467 ID: id,
3468 Time: createdAtTime,
3469 Duration: costsDuration,
3470 Args: cmdString,
3471 ClientAddr: address,
3472 ClientName: name,
3473 }
3474 }
3475 return nil, nil
3476 })
3477 return err
3478}