1 package redis
2
3 import (
4 "context"
5 "fmt"
6
7 "github.com/redis/go-redis/v9/internal/proto"
8 )
9
10 type ProbabilisticCmdable interface {
11 BFAdd(ctx context.Context, key string, element interface{}) *BoolCmd
12 BFCard(ctx context.Context, key string) *IntCmd
13 BFExists(ctx context.Context, key string, element interface{}) *BoolCmd
14 BFInfo(ctx context.Context, key string) *BFInfoCmd
15 BFInfoArg(ctx context.Context, key, option string) *BFInfoCmd
16 BFInfoCapacity(ctx context.Context, key string) *BFInfoCmd
17 BFInfoSize(ctx context.Context, key string) *BFInfoCmd
18 BFInfoFilters(ctx context.Context, key string) *BFInfoCmd
19 BFInfoItems(ctx context.Context, key string) *BFInfoCmd
20 BFInfoExpansion(ctx context.Context, key string) *BFInfoCmd
21 BFInsert(ctx context.Context, key string, options *BFInsertOptions, elements ...interface{}) *BoolSliceCmd
22 BFMAdd(ctx context.Context, key string, elements ...interface{}) *BoolSliceCmd
23 BFMExists(ctx context.Context, key string, elements ...interface{}) *BoolSliceCmd
24 BFReserve(ctx context.Context, key string, errorRate float64, capacity int64) *StatusCmd
25 BFReserveExpansion(ctx context.Context, key string, errorRate float64, capacity, expansion int64) *StatusCmd
26 BFReserveNonScaling(ctx context.Context, key string, errorRate float64, capacity int64) *StatusCmd
27 BFReserveWithArgs(ctx context.Context, key string, options *BFReserveOptions) *StatusCmd
28 BFScanDump(ctx context.Context, key string, iterator int64) *ScanDumpCmd
29 BFLoadChunk(ctx context.Context, key string, iterator int64, data interface{}) *StatusCmd
30
31 CFAdd(ctx context.Context, key string, element interface{}) *BoolCmd
32 CFAddNX(ctx context.Context, key string, element interface{}) *BoolCmd
33 CFCount(ctx context.Context, key string, element interface{}) *IntCmd
34 CFDel(ctx context.Context, key string, element interface{}) *BoolCmd
35 CFExists(ctx context.Context, key string, element interface{}) *BoolCmd
36 CFInfo(ctx context.Context, key string) *CFInfoCmd
37 CFInsert(ctx context.Context, key string, options *CFInsertOptions, elements ...interface{}) *BoolSliceCmd
38 CFInsertNX(ctx context.Context, key string, options *CFInsertOptions, elements ...interface{}) *IntSliceCmd
39 CFMExists(ctx context.Context, key string, elements ...interface{}) *BoolSliceCmd
40 CFReserve(ctx context.Context, key string, capacity int64) *StatusCmd
41 CFReserveWithArgs(ctx context.Context, key string, options *CFReserveOptions) *StatusCmd
42 CFReserveExpansion(ctx context.Context, key string, capacity int64, expansion int64) *StatusCmd
43 CFReserveBucketSize(ctx context.Context, key string, capacity int64, bucketsize int64) *StatusCmd
44 CFReserveMaxIterations(ctx context.Context, key string, capacity int64, maxiterations int64) *StatusCmd
45 CFScanDump(ctx context.Context, key string, iterator int64) *ScanDumpCmd
46 CFLoadChunk(ctx context.Context, key string, iterator int64, data interface{}) *StatusCmd
47
48 CMSIncrBy(ctx context.Context, key string, elements ...interface{}) *IntSliceCmd
49 CMSInfo(ctx context.Context, key string) *CMSInfoCmd
50 CMSInitByDim(ctx context.Context, key string, width, height int64) *StatusCmd
51 CMSInitByProb(ctx context.Context, key string, errorRate, probability float64) *StatusCmd
52 CMSMerge(ctx context.Context, destKey string, sourceKeys ...string) *StatusCmd
53 CMSMergeWithWeight(ctx context.Context, destKey string, sourceKeys map[string]int64) *StatusCmd
54 CMSQuery(ctx context.Context, key string, elements ...interface{}) *IntSliceCmd
55
56 TopKAdd(ctx context.Context, key string, elements ...interface{}) *StringSliceCmd
57 TopKCount(ctx context.Context, key string, elements ...interface{}) *IntSliceCmd
58 TopKIncrBy(ctx context.Context, key string, elements ...interface{}) *StringSliceCmd
59 TopKInfo(ctx context.Context, key string) *TopKInfoCmd
60 TopKList(ctx context.Context, key string) *StringSliceCmd
61 TopKListWithCount(ctx context.Context, key string) *MapStringIntCmd
62 TopKQuery(ctx context.Context, key string, elements ...interface{}) *BoolSliceCmd
63 TopKReserve(ctx context.Context, key string, k int64) *StatusCmd
64 TopKReserveWithOptions(ctx context.Context, key string, k int64, width, depth int64, decay float64) *StatusCmd
65
66 TDigestAdd(ctx context.Context, key string, elements ...float64) *StatusCmd
67 TDigestByRank(ctx context.Context, key string, rank ...uint64) *FloatSliceCmd
68 TDigestByRevRank(ctx context.Context, key string, rank ...uint64) *FloatSliceCmd
69 TDigestCDF(ctx context.Context, key string, elements ...float64) *FloatSliceCmd
70 TDigestCreate(ctx context.Context, key string) *StatusCmd
71 TDigestCreateWithCompression(ctx context.Context, key string, compression int64) *StatusCmd
72 TDigestInfo(ctx context.Context, key string) *TDigestInfoCmd
73 TDigestMax(ctx context.Context, key string) *FloatCmd
74 TDigestMin(ctx context.Context, key string) *FloatCmd
75 TDigestMerge(ctx context.Context, destKey string, options *TDigestMergeOptions, sourceKeys ...string) *StatusCmd
76 TDigestQuantile(ctx context.Context, key string, elements ...float64) *FloatSliceCmd
77 TDigestRank(ctx context.Context, key string, values ...float64) *IntSliceCmd
78 TDigestReset(ctx context.Context, key string) *StatusCmd
79 TDigestRevRank(ctx context.Context, key string, values ...float64) *IntSliceCmd
80 TDigestTrimmedMean(ctx context.Context, key string, lowCutQuantile, highCutQuantile float64) *FloatCmd
81 }
82
83 type BFInsertOptions struct {
84 Capacity int64
85 Error float64
86 Expansion int64
87 NonScaling bool
88 NoCreate bool
89 }
90
91 type BFReserveOptions struct {
92 Capacity int64
93 Error float64
94 Expansion int64
95 NonScaling bool
96 }
97
98 type CFReserveOptions struct {
99 Capacity int64
100 BucketSize int64
101 MaxIterations int64
102 Expansion int64
103 }
104
105 type CFInsertOptions struct {
106 Capacity int64
107 NoCreate bool
108 }
109
110
111
112
113
114
115
116
117 func (c cmdable) BFReserve(ctx context.Context, key string, errorRate float64, capacity int64) *StatusCmd {
118 args := []interface{}{"BF.RESERVE", key, errorRate, capacity}
119 cmd := NewStatusCmd(ctx, args...)
120 _ = c(ctx, cmd)
121 return cmd
122 }
123
124
125
126
127
128 func (c cmdable) BFReserveExpansion(ctx context.Context, key string, errorRate float64, capacity, expansion int64) *StatusCmd {
129 args := []interface{}{"BF.RESERVE", key, errorRate, capacity, "EXPANSION", expansion}
130 cmd := NewStatusCmd(ctx, args...)
131 _ = c(ctx, cmd)
132 return cmd
133 }
134
135
136
137
138
139 func (c cmdable) BFReserveNonScaling(ctx context.Context, key string, errorRate float64, capacity int64) *StatusCmd {
140 args := []interface{}{"BF.RESERVE", key, errorRate, capacity, "NONSCALING"}
141 cmd := NewStatusCmd(ctx, args...)
142 _ = c(ctx, cmd)
143 return cmd
144 }
145
146
147
148
149
150 func (c cmdable) BFReserveWithArgs(ctx context.Context, key string, options *BFReserveOptions) *StatusCmd {
151 args := []interface{}{"BF.RESERVE", key}
152 if options != nil {
153 args = append(args, options.Error, options.Capacity)
154 if options.Expansion != 0 {
155 args = append(args, "EXPANSION", options.Expansion)
156 }
157 if options.NonScaling {
158 args = append(args, "NONSCALING")
159 }
160 }
161 cmd := NewStatusCmd(ctx, args...)
162 _ = c(ctx, cmd)
163 return cmd
164 }
165
166
167
168 func (c cmdable) BFAdd(ctx context.Context, key string, element interface{}) *BoolCmd {
169 args := []interface{}{"BF.ADD", key, element}
170 cmd := NewBoolCmd(ctx, args...)
171 _ = c(ctx, cmd)
172 return cmd
173 }
174
175
176
177
178
179 func (c cmdable) BFCard(ctx context.Context, key string) *IntCmd {
180 args := []interface{}{"BF.CARD", key}
181 cmd := NewIntCmd(ctx, args...)
182 _ = c(ctx, cmd)
183 return cmd
184 }
185
186
187
188 func (c cmdable) BFExists(ctx context.Context, key string, element interface{}) *BoolCmd {
189 args := []interface{}{"BF.EXISTS", key, element}
190 cmd := NewBoolCmd(ctx, args...)
191 _ = c(ctx, cmd)
192 return cmd
193 }
194
195
196
197 func (c cmdable) BFLoadChunk(ctx context.Context, key string, iterator int64, data interface{}) *StatusCmd {
198 args := []interface{}{"BF.LOADCHUNK", key, iterator, data}
199 cmd := NewStatusCmd(ctx, args...)
200 _ = c(ctx, cmd)
201 return cmd
202 }
203
204
205
206
207 func (c cmdable) BFScanDump(ctx context.Context, key string, iterator int64) *ScanDumpCmd {
208 args := []interface{}{"BF.SCANDUMP", key, iterator}
209 cmd := newScanDumpCmd(ctx, args...)
210 _ = c(ctx, cmd)
211 return cmd
212 }
213
214 type ScanDump struct {
215 Iter int64
216 Data string
217 }
218
219 type ScanDumpCmd struct {
220 baseCmd
221
222 val ScanDump
223 }
224
225 func newScanDumpCmd(ctx context.Context, args ...interface{}) *ScanDumpCmd {
226 return &ScanDumpCmd{
227 baseCmd: baseCmd{
228 ctx: ctx,
229 args: args,
230 },
231 }
232 }
233
234 func (cmd *ScanDumpCmd) String() string {
235 return cmdString(cmd, cmd.val)
236 }
237
238 func (cmd *ScanDumpCmd) SetVal(val ScanDump) {
239 cmd.val = val
240 }
241
242 func (cmd *ScanDumpCmd) Result() (ScanDump, error) {
243 return cmd.val, cmd.err
244 }
245
246 func (cmd *ScanDumpCmd) Val() ScanDump {
247 return cmd.val
248 }
249
250 func (cmd *ScanDumpCmd) readReply(rd *proto.Reader) (err error) {
251 n, err := rd.ReadMapLen()
252 if err != nil {
253 return err
254 }
255 cmd.val = ScanDump{}
256 for i := 0; i < n; i++ {
257 iter, err := rd.ReadInt()
258 if err != nil {
259 return err
260 }
261 data, err := rd.ReadString()
262 if err != nil {
263 return err
264 }
265 cmd.val.Data = data
266 cmd.val.Iter = iter
267
268 }
269
270 return nil
271 }
272
273
274
275 func (c cmdable) BFInfo(ctx context.Context, key string) *BFInfoCmd {
276 args := []interface{}{"BF.INFO", key}
277 cmd := NewBFInfoCmd(ctx, args...)
278 _ = c(ctx, cmd)
279 return cmd
280 }
281
282 type BFInfo struct {
283 Capacity int64
284 Size int64
285 Filters int64
286 ItemsInserted int64
287 ExpansionRate int64
288 }
289
290 type BFInfoCmd struct {
291 baseCmd
292
293 val BFInfo
294 }
295
296 func NewBFInfoCmd(ctx context.Context, args ...interface{}) *BFInfoCmd {
297 return &BFInfoCmd{
298 baseCmd: baseCmd{
299 ctx: ctx,
300 args: args,
301 },
302 }
303 }
304
305 func (cmd *BFInfoCmd) SetVal(val BFInfo) {
306 cmd.val = val
307 }
308
309 func (cmd *BFInfoCmd) String() string {
310 return cmdString(cmd, cmd.val)
311 }
312
313 func (cmd *BFInfoCmd) Val() BFInfo {
314 return cmd.val
315 }
316
317 func (cmd *BFInfoCmd) Result() (BFInfo, error) {
318 return cmd.val, cmd.err
319 }
320
321 func (cmd *BFInfoCmd) readReply(rd *proto.Reader) (err error) {
322 result := BFInfo{}
323
324
325 respMapping := map[string]*int64{
326 "Capacity": &result.Capacity,
327 "CAPACITY": &result.Capacity,
328 "Size": &result.Size,
329 "SIZE": &result.Size,
330 "Number of filters": &result.Filters,
331 "FILTERS": &result.Filters,
332 "Number of items inserted": &result.ItemsInserted,
333 "ITEMS": &result.ItemsInserted,
334 "Expansion rate": &result.ExpansionRate,
335 "EXPANSION": &result.ExpansionRate,
336 }
337
338
339 readAndAssignValue := func(key string) error {
340 fieldPtr, exists := respMapping[key]
341 if !exists {
342 return fmt.Errorf("redis: BLOOM.INFO unexpected key %s", key)
343 }
344
345
346 val, err := rd.ReadInt()
347 if err != nil {
348 return err
349 }
350 *fieldPtr = val
351 return nil
352 }
353
354 readType, err := rd.PeekReplyType()
355 if err != nil {
356 return err
357 }
358
359 if len(cmd.args) > 2 && readType == proto.RespArray {
360 n, err := rd.ReadArrayLen()
361 if err != nil {
362 return err
363 }
364 if key, ok := cmd.args[2].(string); ok && n == 1 {
365 if err := readAndAssignValue(key); err != nil {
366 return err
367 }
368 } else {
369 return fmt.Errorf("redis: BLOOM.INFO invalid argument key type")
370 }
371 } else {
372 n, err := rd.ReadMapLen()
373 if err != nil {
374 return err
375 }
376 for i := 0; i < n; i++ {
377 key, err := rd.ReadString()
378 if err != nil {
379 return err
380 }
381 if err := readAndAssignValue(key); err != nil {
382 return err
383 }
384 }
385 }
386
387 cmd.val = result
388 return nil
389 }
390
391
392
393 func (c cmdable) BFInfoCapacity(ctx context.Context, key string) *BFInfoCmd {
394 return c.BFInfoArg(ctx, key, "CAPACITY")
395 }
396
397
398
399 func (c cmdable) BFInfoSize(ctx context.Context, key string) *BFInfoCmd {
400 return c.BFInfoArg(ctx, key, "SIZE")
401 }
402
403
404
405 func (c cmdable) BFInfoFilters(ctx context.Context, key string) *BFInfoCmd {
406 return c.BFInfoArg(ctx, key, "FILTERS")
407 }
408
409
410
411 func (c cmdable) BFInfoItems(ctx context.Context, key string) *BFInfoCmd {
412 return c.BFInfoArg(ctx, key, "ITEMS")
413 }
414
415
416
417 func (c cmdable) BFInfoExpansion(ctx context.Context, key string) *BFInfoCmd {
418 return c.BFInfoArg(ctx, key, "EXPANSION")
419 }
420
421
422
423 func (c cmdable) BFInfoArg(ctx context.Context, key, option string) *BFInfoCmd {
424 args := []interface{}{"BF.INFO", key, option}
425 cmd := NewBFInfoCmd(ctx, args...)
426 _ = c(ctx, cmd)
427 return cmd
428 }
429
430
431
432
433
434 func (c cmdable) BFInsert(ctx context.Context, key string, options *BFInsertOptions, elements ...interface{}) *BoolSliceCmd {
435 args := []interface{}{"BF.INSERT", key}
436 if options != nil {
437 if options.Capacity != 0 {
438 args = append(args, "CAPACITY", options.Capacity)
439 }
440 if options.Error != 0 {
441 args = append(args, "ERROR", options.Error)
442 }
443 if options.Expansion != 0 {
444 args = append(args, "EXPANSION", options.Expansion)
445 }
446 if options.NoCreate {
447 args = append(args, "NOCREATE")
448 }
449 if options.NonScaling {
450 args = append(args, "NONSCALING")
451 }
452 }
453 args = append(args, "ITEMS")
454 args = append(args, elements...)
455
456 cmd := NewBoolSliceCmd(ctx, args...)
457 _ = c(ctx, cmd)
458 return cmd
459 }
460
461
462
463
464 func (c cmdable) BFMAdd(ctx context.Context, key string, elements ...interface{}) *BoolSliceCmd {
465 args := []interface{}{"BF.MADD", key}
466 args = append(args, elements...)
467 cmd := NewBoolSliceCmd(ctx, args...)
468 _ = c(ctx, cmd)
469 return cmd
470 }
471
472
473
474
475 func (c cmdable) BFMExists(ctx context.Context, key string, elements ...interface{}) *BoolSliceCmd {
476 args := []interface{}{"BF.MEXISTS", key}
477 args = append(args, elements...)
478
479 cmd := NewBoolSliceCmd(ctx, args...)
480 _ = c(ctx, cmd)
481 return cmd
482 }
483
484
485
486
487
488
489
490 func (c cmdable) CFReserve(ctx context.Context, key string, capacity int64) *StatusCmd {
491 args := []interface{}{"CF.RESERVE", key, capacity}
492 cmd := NewStatusCmd(ctx, args...)
493 _ = c(ctx, cmd)
494 return cmd
495 }
496
497
498
499 func (c cmdable) CFReserveExpansion(ctx context.Context, key string, capacity int64, expansion int64) *StatusCmd {
500 args := []interface{}{"CF.RESERVE", key, capacity, "EXPANSION", expansion}
501 cmd := NewStatusCmd(ctx, args...)
502 _ = c(ctx, cmd)
503 return cmd
504 }
505
506
507
508 func (c cmdable) CFReserveBucketSize(ctx context.Context, key string, capacity int64, bucketsize int64) *StatusCmd {
509 args := []interface{}{"CF.RESERVE", key, capacity, "BUCKETSIZE", bucketsize}
510 cmd := NewStatusCmd(ctx, args...)
511 _ = c(ctx, cmd)
512 return cmd
513 }
514
515
516
517 func (c cmdable) CFReserveMaxIterations(ctx context.Context, key string, capacity int64, maxiterations int64) *StatusCmd {
518 args := []interface{}{"CF.RESERVE", key, capacity, "MAXITERATIONS", maxiterations}
519 cmd := NewStatusCmd(ctx, args...)
520 _ = c(ctx, cmd)
521 return cmd
522 }
523
524
525
526
527 func (c cmdable) CFReserveWithArgs(ctx context.Context, key string, options *CFReserveOptions) *StatusCmd {
528 args := []interface{}{"CF.RESERVE", key, options.Capacity}
529 if options.BucketSize != 0 {
530 args = append(args, "BUCKETSIZE", options.BucketSize)
531 }
532 if options.MaxIterations != 0 {
533 args = append(args, "MAXITERATIONS", options.MaxIterations)
534 }
535 if options.Expansion != 0 {
536 args = append(args, "EXPANSION", options.Expansion)
537 }
538 cmd := NewStatusCmd(ctx, args...)
539 _ = c(ctx, cmd)
540 return cmd
541 }
542
543
544
545
546 func (c cmdable) CFAdd(ctx context.Context, key string, element interface{}) *BoolCmd {
547 args := []interface{}{"CF.ADD", key, element}
548 cmd := NewBoolCmd(ctx, args...)
549 _ = c(ctx, cmd)
550 return cmd
551 }
552
553
554
555
556 func (c cmdable) CFAddNX(ctx context.Context, key string, element interface{}) *BoolCmd {
557 args := []interface{}{"CF.ADDNX", key, element}
558 cmd := NewBoolCmd(ctx, args...)
559 _ = c(ctx, cmd)
560 return cmd
561 }
562
563
564
565 func (c cmdable) CFCount(ctx context.Context, key string, element interface{}) *IntCmd {
566 args := []interface{}{"CF.COUNT", key, element}
567 cmd := NewIntCmd(ctx, args...)
568 _ = c(ctx, cmd)
569 return cmd
570 }
571
572
573
574 func (c cmdable) CFDel(ctx context.Context, key string, element interface{}) *BoolCmd {
575 args := []interface{}{"CF.DEL", key, element}
576 cmd := NewBoolCmd(ctx, args...)
577 _ = c(ctx, cmd)
578 return cmd
579 }
580
581
582
583 func (c cmdable) CFExists(ctx context.Context, key string, element interface{}) *BoolCmd {
584 args := []interface{}{"CF.EXISTS", key, element}
585 cmd := NewBoolCmd(ctx, args...)
586 _ = c(ctx, cmd)
587 return cmd
588 }
589
590
591
592 func (c cmdable) CFLoadChunk(ctx context.Context, key string, iterator int64, data interface{}) *StatusCmd {
593 args := []interface{}{"CF.LOADCHUNK", key, iterator, data}
594 cmd := NewStatusCmd(ctx, args...)
595 _ = c(ctx, cmd)
596 return cmd
597 }
598
599
600
601 func (c cmdable) CFScanDump(ctx context.Context, key string, iterator int64) *ScanDumpCmd {
602 args := []interface{}{"CF.SCANDUMP", key, iterator}
603 cmd := newScanDumpCmd(ctx, args...)
604 _ = c(ctx, cmd)
605 return cmd
606 }
607
608 type CFInfo struct {
609 Size int64
610 NumBuckets int64
611 NumFilters int64
612 NumItemsInserted int64
613 NumItemsDeleted int64
614 BucketSize int64
615 ExpansionRate int64
616 MaxIteration int64
617 }
618
619 type CFInfoCmd struct {
620 baseCmd
621
622 val CFInfo
623 }
624
625 func NewCFInfoCmd(ctx context.Context, args ...interface{}) *CFInfoCmd {
626 return &CFInfoCmd{
627 baseCmd: baseCmd{
628 ctx: ctx,
629 args: args,
630 },
631 }
632 }
633
634 func (cmd *CFInfoCmd) SetVal(val CFInfo) {
635 cmd.val = val
636 }
637
638 func (cmd *CFInfoCmd) String() string {
639 return cmdString(cmd, cmd.val)
640 }
641
642 func (cmd *CFInfoCmd) Val() CFInfo {
643 return cmd.val
644 }
645
646 func (cmd *CFInfoCmd) Result() (CFInfo, error) {
647 return cmd.val, cmd.err
648 }
649
650 func (cmd *CFInfoCmd) readReply(rd *proto.Reader) (err error) {
651 n, err := rd.ReadMapLen()
652 if err != nil {
653 return err
654 }
655
656 var key string
657 var result CFInfo
658 for f := 0; f < n; f++ {
659 key, err = rd.ReadString()
660 if err != nil {
661 return err
662 }
663
664 switch key {
665 case "Size":
666 result.Size, err = rd.ReadInt()
667 case "Number of buckets":
668 result.NumBuckets, err = rd.ReadInt()
669 case "Number of filters":
670 result.NumFilters, err = rd.ReadInt()
671 case "Number of items inserted":
672 result.NumItemsInserted, err = rd.ReadInt()
673 case "Number of items deleted":
674 result.NumItemsDeleted, err = rd.ReadInt()
675 case "Bucket size":
676 result.BucketSize, err = rd.ReadInt()
677 case "Expansion rate":
678 result.ExpansionRate, err = rd.ReadInt()
679 case "Max iterations":
680 result.MaxIteration, err = rd.ReadInt()
681
682 default:
683 return fmt.Errorf("redis: CF.INFO unexpected key %s", key)
684 }
685
686 if err != nil {
687 return err
688 }
689 }
690
691 cmd.val = result
692 return nil
693 }
694
695
696
697 func (c cmdable) CFInfo(ctx context.Context, key string) *CFInfoCmd {
698 args := []interface{}{"CF.INFO", key}
699 cmd := NewCFInfoCmd(ctx, args...)
700 _ = c(ctx, cmd)
701 return cmd
702 }
703
704
705
706
707
708 func (c cmdable) CFInsert(ctx context.Context, key string, options *CFInsertOptions, elements ...interface{}) *BoolSliceCmd {
709 args := []interface{}{"CF.INSERT", key}
710 args = c.getCfInsertWithArgs(args, options, elements...)
711
712 cmd := NewBoolSliceCmd(ctx, args...)
713 _ = c(ctx, cmd)
714 return cmd
715 }
716
717
718
719
720
721
722 func (c cmdable) CFInsertNX(ctx context.Context, key string, options *CFInsertOptions, elements ...interface{}) *IntSliceCmd {
723 args := []interface{}{"CF.INSERTNX", key}
724 args = c.getCfInsertWithArgs(args, options, elements...)
725
726 cmd := NewIntSliceCmd(ctx, args...)
727 _ = c(ctx, cmd)
728 return cmd
729 }
730
731 func (c cmdable) getCfInsertWithArgs(args []interface{}, options *CFInsertOptions, elements ...interface{}) []interface{} {
732 if options != nil {
733 if options.Capacity != 0 {
734 args = append(args, "CAPACITY", options.Capacity)
735 }
736 if options.NoCreate {
737 args = append(args, "NOCREATE")
738 }
739 }
740 args = append(args, "ITEMS")
741 args = append(args, elements...)
742
743 return args
744 }
745
746
747
748
749 func (c cmdable) CFMExists(ctx context.Context, key string, elements ...interface{}) *BoolSliceCmd {
750 args := []interface{}{"CF.MEXISTS", key}
751 args = append(args, elements...)
752 cmd := NewBoolSliceCmd(ctx, args...)
753 _ = c(ctx, cmd)
754 return cmd
755 }
756
757
758
759
760
761
762
763
764 func (c cmdable) CMSIncrBy(ctx context.Context, key string, elements ...interface{}) *IntSliceCmd {
765 args := make([]interface{}, 2, 2+len(elements))
766 args[0] = "CMS.INCRBY"
767 args[1] = key
768 args = appendArgs(args, elements)
769
770 cmd := NewIntSliceCmd(ctx, args...)
771 _ = c(ctx, cmd)
772 return cmd
773 }
774
775 type CMSInfo struct {
776 Width int64
777 Depth int64
778 Count int64
779 }
780
781 type CMSInfoCmd struct {
782 baseCmd
783
784 val CMSInfo
785 }
786
787 func NewCMSInfoCmd(ctx context.Context, args ...interface{}) *CMSInfoCmd {
788 return &CMSInfoCmd{
789 baseCmd: baseCmd{
790 ctx: ctx,
791 args: args,
792 },
793 }
794 }
795
796 func (cmd *CMSInfoCmd) SetVal(val CMSInfo) {
797 cmd.val = val
798 }
799
800 func (cmd *CMSInfoCmd) String() string {
801 return cmdString(cmd, cmd.val)
802 }
803
804 func (cmd *CMSInfoCmd) Val() CMSInfo {
805 return cmd.val
806 }
807
808 func (cmd *CMSInfoCmd) Result() (CMSInfo, error) {
809 return cmd.val, cmd.err
810 }
811
812 func (cmd *CMSInfoCmd) readReply(rd *proto.Reader) (err error) {
813 n, err := rd.ReadMapLen()
814 if err != nil {
815 return err
816 }
817
818 var key string
819 var result CMSInfo
820 for f := 0; f < n; f++ {
821 key, err = rd.ReadString()
822 if err != nil {
823 return err
824 }
825
826 switch key {
827 case "width":
828 result.Width, err = rd.ReadInt()
829 case "depth":
830 result.Depth, err = rd.ReadInt()
831 case "count":
832 result.Count, err = rd.ReadInt()
833 default:
834 return fmt.Errorf("redis: CMS.INFO unexpected key %s", key)
835 }
836
837 if err != nil {
838 return err
839 }
840 }
841
842 cmd.val = result
843 return nil
844 }
845
846
847
848 func (c cmdable) CMSInfo(ctx context.Context, key string) *CMSInfoCmd {
849 args := []interface{}{"CMS.INFO", key}
850 cmd := NewCMSInfoCmd(ctx, args...)
851 _ = c(ctx, cmd)
852 return cmd
853 }
854
855
856
857 func (c cmdable) CMSInitByDim(ctx context.Context, key string, width, depth int64) *StatusCmd {
858 args := []interface{}{"CMS.INITBYDIM", key, width, depth}
859 cmd := NewStatusCmd(ctx, args...)
860 _ = c(ctx, cmd)
861 return cmd
862 }
863
864
865
866 func (c cmdable) CMSInitByProb(ctx context.Context, key string, errorRate, probability float64) *StatusCmd {
867 args := []interface{}{"CMS.INITBYPROB", key, errorRate, probability}
868 cmd := NewStatusCmd(ctx, args...)
869 _ = c(ctx, cmd)
870 return cmd
871 }
872
873
874
875
876
877
878 func (c cmdable) CMSMerge(ctx context.Context, destKey string, sourceKeys ...string) *StatusCmd {
879 args := []interface{}{"CMS.MERGE", destKey, len(sourceKeys)}
880 for _, s := range sourceKeys {
881 args = append(args, s)
882 }
883 cmd := NewStatusCmd(ctx, args...)
884 _ = c(ctx, cmd)
885 return cmd
886 }
887
888
889
890
891
892
893 func (c cmdable) CMSMergeWithWeight(ctx context.Context, destKey string, sourceKeys map[string]int64) *StatusCmd {
894 args := make([]interface{}, 0, 4+(len(sourceKeys)*2+1))
895 args = append(args, "CMS.MERGE", destKey, len(sourceKeys))
896
897 if len(sourceKeys) > 0 {
898 sk := make([]interface{}, len(sourceKeys))
899 sw := make([]interface{}, len(sourceKeys))
900
901 i := 0
902 for k, w := range sourceKeys {
903 sk[i] = k
904 sw[i] = w
905 i++
906 }
907
908 args = append(args, sk...)
909 args = append(args, "WEIGHTS")
910 args = append(args, sw...)
911 }
912
913 cmd := NewStatusCmd(ctx, args...)
914 _ = c(ctx, cmd)
915 return cmd
916 }
917
918
919
920 func (c cmdable) CMSQuery(ctx context.Context, key string, elements ...interface{}) *IntSliceCmd {
921 args := []interface{}{"CMS.QUERY", key}
922 args = append(args, elements...)
923 cmd := NewIntSliceCmd(ctx, args...)
924 _ = c(ctx, cmd)
925 return cmd
926 }
927
928
929
930
931
932
933
934
935 func (c cmdable) TopKAdd(ctx context.Context, key string, elements ...interface{}) *StringSliceCmd {
936 args := make([]interface{}, 2, 2+len(elements))
937 args[0] = "TOPK.ADD"
938 args[1] = key
939 args = appendArgs(args, elements)
940
941 cmd := NewStringSliceCmd(ctx, args...)
942 _ = c(ctx, cmd)
943 return cmd
944 }
945
946
947
948 func (c cmdable) TopKReserve(ctx context.Context, key string, k int64) *StatusCmd {
949 args := []interface{}{"TOPK.RESERVE", key, k}
950
951 cmd := NewStatusCmd(ctx, args...)
952 _ = c(ctx, cmd)
953 return cmd
954 }
955
956
957
958
959 func (c cmdable) TopKReserveWithOptions(ctx context.Context, key string, k int64, width, depth int64, decay float64) *StatusCmd {
960 args := []interface{}{"TOPK.RESERVE", key, k, width, depth, decay}
961
962 cmd := NewStatusCmd(ctx, args...)
963 _ = c(ctx, cmd)
964 return cmd
965 }
966
967 type TopKInfo struct {
968 K int64
969 Width int64
970 Depth int64
971 Decay float64
972 }
973
974 type TopKInfoCmd struct {
975 baseCmd
976
977 val TopKInfo
978 }
979
980 func NewTopKInfoCmd(ctx context.Context, args ...interface{}) *TopKInfoCmd {
981 return &TopKInfoCmd{
982 baseCmd: baseCmd{
983 ctx: ctx,
984 args: args,
985 },
986 }
987 }
988
989 func (cmd *TopKInfoCmd) SetVal(val TopKInfo) {
990 cmd.val = val
991 }
992
993 func (cmd *TopKInfoCmd) String() string {
994 return cmdString(cmd, cmd.val)
995 }
996
997 func (cmd *TopKInfoCmd) Val() TopKInfo {
998 return cmd.val
999 }
1000
1001 func (cmd *TopKInfoCmd) Result() (TopKInfo, error) {
1002 return cmd.val, cmd.err
1003 }
1004
1005 func (cmd *TopKInfoCmd) readReply(rd *proto.Reader) (err error) {
1006 n, err := rd.ReadMapLen()
1007 if err != nil {
1008 return err
1009 }
1010
1011 var key string
1012 var result TopKInfo
1013 for f := 0; f < n; f++ {
1014 key, err = rd.ReadString()
1015 if err != nil {
1016 return err
1017 }
1018
1019 switch key {
1020 case "k":
1021 result.K, err = rd.ReadInt()
1022 case "width":
1023 result.Width, err = rd.ReadInt()
1024 case "depth":
1025 result.Depth, err = rd.ReadInt()
1026 case "decay":
1027 result.Decay, err = rd.ReadFloat()
1028 default:
1029 return fmt.Errorf("redis: topk.info unexpected key %s", key)
1030 }
1031
1032 if err != nil {
1033 return err
1034 }
1035 }
1036
1037 cmd.val = result
1038 return nil
1039 }
1040
1041
1042
1043 func (c cmdable) TopKInfo(ctx context.Context, key string) *TopKInfoCmd {
1044 args := []interface{}{"TOPK.INFO", key}
1045
1046 cmd := NewTopKInfoCmd(ctx, args...)
1047 _ = c(ctx, cmd)
1048 return cmd
1049 }
1050
1051
1052
1053
1054 func (c cmdable) TopKQuery(ctx context.Context, key string, elements ...interface{}) *BoolSliceCmd {
1055 args := make([]interface{}, 2, 2+len(elements))
1056 args[0] = "TOPK.QUERY"
1057 args[1] = key
1058 args = appendArgs(args, elements)
1059
1060 cmd := NewBoolSliceCmd(ctx, args...)
1061 _ = c(ctx, cmd)
1062 return cmd
1063 }
1064
1065
1066
1067 func (c cmdable) TopKCount(ctx context.Context, key string, elements ...interface{}) *IntSliceCmd {
1068 args := make([]interface{}, 2, 2+len(elements))
1069 args[0] = "TOPK.COUNT"
1070 args[1] = key
1071 args = appendArgs(args, elements)
1072
1073 cmd := NewIntSliceCmd(ctx, args...)
1074 _ = c(ctx, cmd)
1075 return cmd
1076 }
1077
1078
1079
1080 func (c cmdable) TopKIncrBy(ctx context.Context, key string, elements ...interface{}) *StringSliceCmd {
1081 args := make([]interface{}, 2, 2+len(elements))
1082 args[0] = "TOPK.INCRBY"
1083 args[1] = key
1084 args = appendArgs(args, elements)
1085
1086 cmd := NewStringSliceCmd(ctx, args...)
1087 _ = c(ctx, cmd)
1088 return cmd
1089 }
1090
1091
1092
1093 func (c cmdable) TopKList(ctx context.Context, key string) *StringSliceCmd {
1094 args := []interface{}{"TOPK.LIST", key}
1095
1096 cmd := NewStringSliceCmd(ctx, args...)
1097 _ = c(ctx, cmd)
1098 return cmd
1099 }
1100
1101
1102
1103 func (c cmdable) TopKListWithCount(ctx context.Context, key string) *MapStringIntCmd {
1104 args := []interface{}{"TOPK.LIST", key, "WITHCOUNT"}
1105
1106 cmd := NewMapStringIntCmd(ctx, args...)
1107 _ = c(ctx, cmd)
1108 return cmd
1109 }
1110
1111
1112
1113
1114
1115
1116
1117
1118 func (c cmdable) TDigestAdd(ctx context.Context, key string, elements ...float64) *StatusCmd {
1119 args := make([]interface{}, 2+len(elements))
1120 args[0] = "TDIGEST.ADD"
1121 args[1] = key
1122
1123 for i, v := range elements {
1124 args[2+i] = v
1125 }
1126
1127 cmd := NewStatusCmd(ctx, args...)
1128 _ = c(ctx, cmd)
1129 return cmd
1130 }
1131
1132
1133
1134
1135
1136 func (c cmdable) TDigestByRank(ctx context.Context, key string, rank ...uint64) *FloatSliceCmd {
1137 args := make([]interface{}, 2+len(rank))
1138 args[0] = "TDIGEST.BYRANK"
1139 args[1] = key
1140
1141 for i, r := range rank {
1142 args[2+i] = r
1143 }
1144
1145 cmd := NewFloatSliceCmd(ctx, args...)
1146 _ = c(ctx, cmd)
1147 return cmd
1148 }
1149
1150
1151
1152
1153
1154 func (c cmdable) TDigestByRevRank(ctx context.Context, key string, rank ...uint64) *FloatSliceCmd {
1155 args := make([]interface{}, 2+len(rank))
1156 args[0] = "TDIGEST.BYREVRANK"
1157 args[1] = key
1158
1159 for i, r := range rank {
1160 args[2+i] = r
1161 }
1162
1163 cmd := NewFloatSliceCmd(ctx, args...)
1164 _ = c(ctx, cmd)
1165 return cmd
1166 }
1167
1168
1169
1170
1171
1172 func (c cmdable) TDigestCDF(ctx context.Context, key string, elements ...float64) *FloatSliceCmd {
1173 args := make([]interface{}, 2+len(elements))
1174 args[0] = "TDIGEST.CDF"
1175 args[1] = key
1176
1177 for i, v := range elements {
1178 args[2+i] = v
1179 }
1180
1181 cmd := NewFloatSliceCmd(ctx, args...)
1182 _ = c(ctx, cmd)
1183 return cmd
1184 }
1185
1186
1187
1188
1189 func (c cmdable) TDigestCreate(ctx context.Context, key string) *StatusCmd {
1190 args := []interface{}{"TDIGEST.CREATE", key}
1191
1192 cmd := NewStatusCmd(ctx, args...)
1193 _ = c(ctx, cmd)
1194 return cmd
1195 }
1196
1197
1198
1199
1200
1201 func (c cmdable) TDigestCreateWithCompression(ctx context.Context, key string, compression int64) *StatusCmd {
1202 args := []interface{}{"TDIGEST.CREATE", key, "COMPRESSION", compression}
1203
1204 cmd := NewStatusCmd(ctx, args...)
1205 _ = c(ctx, cmd)
1206 return cmd
1207 }
1208
1209 type TDigestInfo struct {
1210 Compression int64
1211 Capacity int64
1212 MergedNodes int64
1213 UnmergedNodes int64
1214 MergedWeight int64
1215 UnmergedWeight int64
1216 Observations int64
1217 TotalCompressions int64
1218 MemoryUsage int64
1219 }
1220
1221 type TDigestInfoCmd struct {
1222 baseCmd
1223
1224 val TDigestInfo
1225 }
1226
1227 func NewTDigestInfoCmd(ctx context.Context, args ...interface{}) *TDigestInfoCmd {
1228 return &TDigestInfoCmd{
1229 baseCmd: baseCmd{
1230 ctx: ctx,
1231 args: args,
1232 },
1233 }
1234 }
1235
1236 func (cmd *TDigestInfoCmd) SetVal(val TDigestInfo) {
1237 cmd.val = val
1238 }
1239
1240 func (cmd *TDigestInfoCmd) String() string {
1241 return cmdString(cmd, cmd.val)
1242 }
1243
1244 func (cmd *TDigestInfoCmd) Val() TDigestInfo {
1245 return cmd.val
1246 }
1247
1248 func (cmd *TDigestInfoCmd) Result() (TDigestInfo, error) {
1249 return cmd.val, cmd.err
1250 }
1251
1252 func (cmd *TDigestInfoCmd) readReply(rd *proto.Reader) (err error) {
1253 n, err := rd.ReadMapLen()
1254 if err != nil {
1255 return err
1256 }
1257
1258 var key string
1259 var result TDigestInfo
1260 for f := 0; f < n; f++ {
1261 key, err = rd.ReadString()
1262 if err != nil {
1263 return err
1264 }
1265
1266 switch key {
1267 case "Compression":
1268 result.Compression, err = rd.ReadInt()
1269 case "Capacity":
1270 result.Capacity, err = rd.ReadInt()
1271 case "Merged nodes":
1272 result.MergedNodes, err = rd.ReadInt()
1273 case "Unmerged nodes":
1274 result.UnmergedNodes, err = rd.ReadInt()
1275 case "Merged weight":
1276 result.MergedWeight, err = rd.ReadInt()
1277 case "Unmerged weight":
1278 result.UnmergedWeight, err = rd.ReadInt()
1279 case "Observations":
1280 result.Observations, err = rd.ReadInt()
1281 case "Total compressions":
1282 result.TotalCompressions, err = rd.ReadInt()
1283 case "Memory usage":
1284 result.MemoryUsage, err = rd.ReadInt()
1285 default:
1286 return fmt.Errorf("redis: tdigest.info unexpected key %s", key)
1287 }
1288
1289 if err != nil {
1290 return err
1291 }
1292 }
1293
1294 cmd.val = result
1295 return nil
1296 }
1297
1298
1299
1300 func (c cmdable) TDigestInfo(ctx context.Context, key string) *TDigestInfoCmd {
1301 args := []interface{}{"TDIGEST.INFO", key}
1302
1303 cmd := NewTDigestInfoCmd(ctx, args...)
1304 _ = c(ctx, cmd)
1305 return cmd
1306 }
1307
1308
1309
1310 func (c cmdable) TDigestMax(ctx context.Context, key string) *FloatCmd {
1311 args := []interface{}{"TDIGEST.MAX", key}
1312
1313 cmd := NewFloatCmd(ctx, args...)
1314 _ = c(ctx, cmd)
1315 return cmd
1316 }
1317
1318 type TDigestMergeOptions struct {
1319 Compression int64
1320 Override bool
1321 }
1322
1323
1324
1325
1326
1327 func (c cmdable) TDigestMerge(ctx context.Context, destKey string, options *TDigestMergeOptions, sourceKeys ...string) *StatusCmd {
1328 args := []interface{}{"TDIGEST.MERGE", destKey, len(sourceKeys)}
1329
1330 for _, sourceKey := range sourceKeys {
1331 args = append(args, sourceKey)
1332 }
1333
1334 if options != nil {
1335 if options.Compression != 0 {
1336 args = append(args, "COMPRESSION", options.Compression)
1337 }
1338 if options.Override {
1339 args = append(args, "OVERRIDE")
1340 }
1341 }
1342
1343 cmd := NewStatusCmd(ctx, args...)
1344 _ = c(ctx, cmd)
1345 return cmd
1346 }
1347
1348
1349
1350 func (c cmdable) TDigestMin(ctx context.Context, key string) *FloatCmd {
1351 args := []interface{}{"TDIGEST.MIN", key}
1352
1353 cmd := NewFloatCmd(ctx, args...)
1354 _ = c(ctx, cmd)
1355 return cmd
1356 }
1357
1358
1359
1360
1361
1362 func (c cmdable) TDigestQuantile(ctx context.Context, key string, elements ...float64) *FloatSliceCmd {
1363 args := make([]interface{}, 2+len(elements))
1364 args[0] = "TDIGEST.QUANTILE"
1365 args[1] = key
1366
1367 for i, v := range elements {
1368 args[2+i] = v
1369 }
1370
1371 cmd := NewFloatSliceCmd(ctx, args...)
1372 _ = c(ctx, cmd)
1373 return cmd
1374 }
1375
1376
1377
1378
1379
1380 func (c cmdable) TDigestRank(ctx context.Context, key string, values ...float64) *IntSliceCmd {
1381 args := make([]interface{}, 2+len(values))
1382 args[0] = "TDIGEST.RANK"
1383 args[1] = key
1384
1385 for i, v := range values {
1386 args[i+2] = v
1387 }
1388
1389 cmd := NewIntSliceCmd(ctx, args...)
1390 _ = c(ctx, cmd)
1391 return cmd
1392 }
1393
1394
1395
1396
1397 func (c cmdable) TDigestReset(ctx context.Context, key string) *StatusCmd {
1398 args := []interface{}{"TDIGEST.RESET", key}
1399
1400 cmd := NewStatusCmd(ctx, args...)
1401 _ = c(ctx, cmd)
1402 return cmd
1403 }
1404
1405
1406
1407
1408
1409 func (c cmdable) TDigestRevRank(ctx context.Context, key string, values ...float64) *IntSliceCmd {
1410 args := make([]interface{}, 2+len(values))
1411 args[0] = "TDIGEST.REVRANK"
1412 args[1] = key
1413
1414 for i, v := range values {
1415 args[2+i] = v
1416 }
1417
1418 cmd := NewIntSliceCmd(ctx, args...)
1419 _ = c(ctx, cmd)
1420 return cmd
1421 }
1422
1423
1424
1425
1426
1427 func (c cmdable) TDigestTrimmedMean(ctx context.Context, key string, lowCutQuantile, highCutQuantile float64) *FloatCmd {
1428 args := []interface{}{"TDIGEST.TRIMMED_MEAN", key, lowCutQuantile, highCutQuantile}
1429
1430 cmd := NewFloatCmd(ctx, args...)
1431 _ = c(ctx, cmd)
1432 return cmd
1433 }
1434
View as plain text