From 1915c903d022089a0e5bac38a72e0a79e6907d20 Mon Sep 17 00:00:00 2001 From: Nic Gibson Date: Tue, 20 Jun 2023 14:09:04 +0100 Subject: [PATCH 01/15] bloom - initial import --- commands.go | 225 ++++++++++++++++++++++++++++++++++++++++++ probabilistic_test.go | 36 +++++++ 2 files changed, 261 insertions(+) create mode 100644 probabilistic_test.go diff --git a/commands.go b/commands.go index 34f4d2c22..854a7df06 100644 --- a/commands.go +++ b/commands.go @@ -3965,3 +3965,228 @@ func (c cmdable) ACLLogReset(ctx context.Context) *StatusCmd { _ = c(ctx, cmd) return cmd } + +// ------------------------------------------- + +type BFReserveOptions struct { + Capacity int64 + Error float64 + Expansion int64 + NonScaling bool +} + +type CFReserveOptions struct { + Capacity int64 + BucketSize int64 + MaxIterations int64 + Expansion int64 +} + +type BFInfo int + +const ( + BFCAPACITY BFInfo = iota + BFSIZE + BFFILTERS + BFITEMS + BFEXPANSION +) + +func (b BFInfo) String() string { + switch b { + case BFCAPACITY: + return "capacity" + case BFSIZE: + return "size" + case BFFILTERS: + return "filters" + case BFITEMS: + return "items" + case BFEXPANSION: + return "expansion" + } + return "" +} + +func (c cmdable) BFReserve(ctx context.Context, key string, errorRate float64, capacity int64) *StatusCmd { + args := []interface{}{"bf.reserve", key, errorRate, capacity} + cmd := NewStatusCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) BFReserveExpansion(ctx context.Context, key string, errorRate float64, capacity, expansion int64) *StatusCmd { + args := []interface{}{"bf.reserve", key, errorRate, capacity, "expansion", expansion} + cmd := NewStatusCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) BFReserveNonScaling(ctx context.Context, key string, errorRate float64, capacity int64) *StatusCmd { + args := []interface{}{"bf.reserve", key, errorRate, capacity, "nonscaling"} + cmd := NewStatusCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) BFReserveArgs(ctx context.Context, key string, options *BFReserveOptions) *StatusCmd { + args := []interface{}{"bf.reserve", key} + if options != nil { + if options.Error != 0 { + args = append(args, options.Error) + } + if options.Capacity != 0 { + args = append(args, options.Capacity) + } + if options.Expansion != 0 { + args = append(args, "expansion", options.Expansion) + } + if options.NonScaling { + args = append(args, "nonscaling") + } + } + cmd := NewStatusCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) BFAdd(ctx context.Context, key, item string) *IntCmd { + args := []interface{}{"bf.add", key, item} + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) BFCard(ctx context.Context, key string) *IntCmd { + args := []interface{}{"bf.card", key} + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) BFExists(ctx context.Context, key, item string) *IntCmd { + args := []interface{}{"bf.exists", key, item} + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) BFInfo(ctx context.Context, key string) *MapStringStringCmd { + args := []interface{}{"bf.info", key} + cmd := NewMapStringStringCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) BFInfoArg(ctx context.Context, key string, option BFInfo) *IntCmd { + args := []interface{}{"bf.info", key, option.String()} + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) BFInsert(ctx context.Context, key string, options *BFReserveOptions, items ...string) *IntSliceCmd { + args := []interface{}{"bf.insert", key} + if options != nil { + if options.Error != 0 { + args = append(args, "error", options.Error) + } + if options.Capacity != 0 { + args = append(args, "capacity", options.Capacity) + } + if options.Expansion != 0 { + args = append(args, "expansion", options.Expansion) + } + if options.NonScaling { + args = append(args, "nonscaling") + } + } + args = append(args, "items") + for _, s := range items { + args = append(args, s) + } + + cmd := NewIntSliceCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) BFMAdd(ctx context.Context, key string, items ...string) *IntSliceCmd { + args := []interface{}{"bf.madd", key, "items"} + for _, s := range items { + args = append(args, s) + } + cmd := NewIntSliceCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) BFMExists(ctx context.Context, key string, items ...string) *IntSliceCmd { + args := []interface{}{"bf.mexists", key, "items"} + for _, s := range items { + args = append(args, s) + } + cmd := NewIntSliceCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +// ------------------------------------------- + +func (c cmdable) CFReserve(ctx context.Context, key string, capacity int64) *StatusCmd { + args := []interface{}{"cf.reserve", key, capacity} + cmd := NewStatusCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) CFReserveArgs(ctx context.Context, key string, options *CFReserveOptions) *StatusCmd { + args := []interface{}{"cf.reserve", key, options.Capacity} + if options.BucketSize != 0 { + args = append(args, "bucketsize", options.BucketSize) + } + if options.MaxIterations != 0 { + args = append(args, "maxiterations", options.MaxIterations) + } + if options.Expansion != 0 { + args = append(args, "expansion", options.Expansion) + } + cmd := NewStatusCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) CFAdd(ctx context.Context, key, item string) *IntCmd { + args := []interface{}{"cf.add", key, item} + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) CFCount(ctx context.Context, key, item string) *IntCmd { + args := []interface{}{"cf.count", key, item} + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) CFAddNX(ctx context.Context, key, item string) *IntCmd { + args := []interface{}{"cf.addnx", key, item} + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) CFDel(ctx context.Context, key string) *IntCmd { + args := []interface{}{"cf.del", key} + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) CFExists(ctx context.Context, key, item string) *IntCmd { + args := []interface{}{"cf.exists", key, item} + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} diff --git a/probabilistic_test.go b/probabilistic_test.go new file mode 100644 index 000000000..afb4177a2 --- /dev/null +++ b/probabilistic_test.go @@ -0,0 +1,36 @@ +package redis_test + +import ( + "context" + + . "github.com/bsm/ginkgo/v2" + . "github.com/bsm/gomega" + + "github.com/redis/go-redis/v9" +) + +var _ = Describe("Probabilistic commands", Label("probabilistic"), func() { + ctx := context.TODO() + var client *redis.Client + + BeforeEach(func() { + client = redis.NewClient(redisOptions()) + Expect(client.FlushDB(ctx).Err()).NotTo(HaveOccurred()) + }) + + AfterEach(func() { + Expect(client.Close()).NotTo(HaveOccurred()) + }) + + Describe("bloom", Label("bloom"), func() { + It("should BFInfo", Label("bf.info"), func() { + err := client.BFReserve(ctx, "testbf1", 0.001, 1000).Err() + Expect(err).NotTo(HaveOccurred()) + + result, err := client.BFInfo(ctx, "testbf1").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(result).To(BeAssignableToTypeOf(map[string]string{})) + + }) + }) +}) From db11cea2c596df354eb9768d05124c62bfa9195e Mon Sep 17 00:00:00 2001 From: Elena Kolevska Date: Wed, 28 Jun 2023 17:05:47 +0100 Subject: [PATCH 02/15] Adds test for Bloom commands --- commands.go | 20 +++++- probabilistic_test.go | 139 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 153 insertions(+), 6 deletions(-) diff --git a/commands.go b/commands.go index 854a7df06..4e2ee6664 100644 --- a/commands.go +++ b/commands.go @@ -504,6 +504,22 @@ type Cmdable interface { ACLLogReset(ctx context.Context) *StatusCmd ModuleLoadex(ctx context.Context, conf *ModuleLoadexConfig) *StringCmd + + BFAdd(ctx context.Context, key, item string) *IntCmd + BFCard(ctx context.Context, key string) *IntCmd + BFExists(ctx context.Context, key, item string) *IntCmd + BFInfo(ctx context.Context, key string) *MapStringStringCmd + BFInfoArg(ctx context.Context, key string, option BFInfo) *IntCmd + BFInsert(ctx context.Context, key string, options *BFReserveOptions, items ...string) *IntSliceCmd + BFMAdd(ctx context.Context, key string, items ...string) *IntSliceCmd + BFMExists(ctx context.Context, key string, items ...string) *IntSliceCmd + BFReserve(ctx context.Context, key string, errorRate float64, capacity int64) *StatusCmd + BFReserveExpansion(ctx context.Context, key string, errorRate float64, capacity, expansion int64) *StatusCmd + BFReserveNonScaling(ctx context.Context, key string, errorRate float64, capacity int64) *StatusCmd + BFReserveArgs(ctx context.Context, key string, options *BFReserveOptions) *StatusCmd + //TODO Loadchunk and scandump missing + + CFReserve(ctx context.Context, key string, capacity int64) *StatusCmd } type StatefulCmdable interface { @@ -4112,7 +4128,7 @@ func (c cmdable) BFInsert(ctx context.Context, key string, options *BFReserveOpt } func (c cmdable) BFMAdd(ctx context.Context, key string, items ...string) *IntSliceCmd { - args := []interface{}{"bf.madd", key, "items"} + args := []interface{}{"bf.madd", key} for _, s := range items { args = append(args, s) } @@ -4122,7 +4138,7 @@ func (c cmdable) BFMAdd(ctx context.Context, key string, items ...string) *IntSl } func (c cmdable) BFMExists(ctx context.Context, key string, items ...string) *IntSliceCmd { - args := []interface{}{"bf.mexists", key, "items"} + args := []interface{}{"bf.mexists", key} for _, s := range items { args = append(args, s) } diff --git a/probabilistic_test.go b/probabilistic_test.go index afb4177a2..dacfddfcc 100644 --- a/probabilistic_test.go +++ b/probabilistic_test.go @@ -2,9 +2,10 @@ package redis_test import ( "context" - + "fmt" . "github.com/bsm/ginkgo/v2" . "github.com/bsm/gomega" + "strconv" "github.com/redis/go-redis/v9" ) @@ -22,15 +23,145 @@ var _ = Describe("Probabilistic commands", Label("probabilistic"), func() { Expect(client.Close()).NotTo(HaveOccurred()) }) - Describe("bloom", Label("bloom"), func() { - It("should BFInfo", Label("bf.info"), func() { - err := client.BFReserve(ctx, "testbf1", 0.001, 1000).Err() + Describe("bloom", Label("bloom", "bfadd"), func() { + It("should BFAdd", Label("bloom"), func() { + resultAdd, err := client.BFAdd(ctx, "testbf1", "test1").Result() + + Expect(err).NotTo(HaveOccurred()) + Expect(resultAdd).To(Equal(int64(1))) + + resultInfo, err := client.BFInfo(ctx, "testbf1").Result() + + Expect(err).NotTo(HaveOccurred()) + Expect(resultInfo).To(BeAssignableToTypeOf(map[string]string{})) + Expect(resultInfo["Number of items inserted"]).To(BeEquivalentTo(strconv.Itoa(1))) + }) + + It("should BFCard", Label("bloom", "bfcard"), func() { + // This is a probabilistic data structure, and it's not always guaranteed that we will get back + // the exact number of inserted items, during hash collisions + // But with such a low number of items (only 3), + // the probability of a collision is very low, so we can expect to get back the exact number of items + _, err := client.BFAdd(ctx, "testbf1", "item1").Result() + Expect(err).NotTo(HaveOccurred()) + _, err = client.BFAdd(ctx, "testbf1", "item2").Result() + Expect(err).NotTo(HaveOccurred()) + _, err = client.BFAdd(ctx, "testbf1", "item3").Result() + Expect(err).NotTo(HaveOccurred()) + + result, err := client.BFCard(ctx, "testbf1").Result() + + Expect(err).NotTo(HaveOccurred()) + Expect(result).To(BeEquivalentTo(int64(3))) + }) + + It("should BFExists", Label("bloom", "bfexists"), func() { + exists, err := client.BFExists(ctx, "testbf1", "item1").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(exists).To(Equal(int64(0))) + + _, err = client.BFAdd(ctx, "testbf1", "item1").Result() + Expect(err).NotTo(HaveOccurred()) + + exists, err = client.BFExists(ctx, "testbf1", "item1").Result() + + Expect(err).NotTo(HaveOccurred()) + Expect(exists).To(BeEquivalentTo(int64(1))) + }) + + It("should BFInfo and BFReserve", Label("bloom", "bfinfo", "bfreserve"), func() { + err := client.BFReserve(ctx, "testbf1", 0.001, 2000).Err() Expect(err).NotTo(HaveOccurred()) result, err := client.BFInfo(ctx, "testbf1").Result() Expect(err).NotTo(HaveOccurred()) Expect(result).To(BeAssignableToTypeOf(map[string]string{})) + Expect(result["Capacity"]).To(BeEquivalentTo(strconv.Itoa(2000))) + }) + + It("should BFInsert", Label("bloom", "bfinsert"), func() { + options := &redis.BFReserveOptions{ + Capacity: 2000, + Error: 0.001, + Expansion: 3, + NonScaling: false, + } + err := client.BFInsert(ctx, "testbf1", options, "item1").Err() + Expect(err).NotTo(HaveOccurred()) + exists, err := client.BFExists(ctx, "testbf1", "item1").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(exists).To(BeEquivalentTo(int64(1))) + + result, err := client.BFInfo(ctx, "testbf1").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(result).To(BeAssignableToTypeOf(map[string]string{})) + Expect(result["Capacity"]).To(BeEquivalentTo(strconv.Itoa(2000))) + Expect(result["Expansion rate"]).To(BeEquivalentTo(strconv.Itoa(3))) + }) + + It("should BFMAdd", Label("bloom", "bfmadd"), func() { + resultAdd, err := client.BFMAdd(ctx, "testbf1", "item1", "item2", "item3").Result() + fmt.Printf("resultAdd: %v\n", resultAdd) + + Expect(err).NotTo(HaveOccurred()) + Expect(len(resultAdd)).To(Equal(int(3))) + + resultInfo, err := client.BFInfo(ctx, "testbf1").Result() + + Expect(err).NotTo(HaveOccurred()) + Expect(resultInfo).To(BeAssignableToTypeOf(map[string]string{})) + Expect(resultInfo["Number of items inserted"]).To(BeEquivalentTo(strconv.Itoa(3))) + }) + + It("should BFMExists", Label("bloom", "bfmexists"), func() { + exist, err := client.BFMExists(ctx, "testbf1", "item1", "item2", "item3").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(len(exist)).To(Equal(int(3))) + Expect(exist[0]).To(Equal(int64(0))) + Expect(exist[1]).To(Equal(int64(0))) + Expect(exist[2]).To(Equal(int64(0))) + + _, err = client.BFMAdd(ctx, "testbf1", "item1", "item2", "item3").Result() + Expect(err).NotTo(HaveOccurred()) + + exist, err = client.BFMExists(ctx, "testbf1", "item1", "item2", "item3", "item4").Result() + + Expect(err).NotTo(HaveOccurred()) + Expect(len(exist)).To(Equal(int(4))) + Expect(exist[0]).To(Equal(int64(1))) + Expect(exist[1]).To(Equal(int64(1))) + Expect(exist[2]).To(Equal(int64(1))) + Expect(exist[3]).To(Equal(int64(0))) + }) + + It("should BFReserveExpansion", Label("bloom", "bfreserveexpansion"), func() { + err := client.BFReserveExpansion(ctx, "testbf1", 0.001, 2000, 3).Err() + Expect(err).NotTo(HaveOccurred()) + + result, err := client.BFInfo(ctx, "testbf1").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(result).To(BeAssignableToTypeOf(map[string]string{})) + Expect(result["Capacity"]).To(BeEquivalentTo(strconv.Itoa(2000))) + Expect(result["Expansion rate"]).To(BeEquivalentTo(strconv.Itoa(3))) }) + + It("should BFReserveArgs", Label("bloom", "bfreserveargs"), func() { + options := &redis.BFReserveOptions{ + Capacity: 2000, + Error: 0.001, + Expansion: 3, + NonScaling: false, + } + err := client.BFReserveArgs(ctx, "testbf", options).Err() + Expect(err).NotTo(HaveOccurred()) + + result, err := client.BFInfo(ctx, "testbf").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(result).To(BeAssignableToTypeOf(map[string]string{})) + Expect(result["Capacity"]).To(BeEquivalentTo(strconv.Itoa(2000))) + Expect(result["Expansion rate"]).To(BeEquivalentTo(strconv.Itoa(3))) + }) + }) }) From 92dc80840fabbe5da4ff0c7f50147387787edd1f Mon Sep 17 00:00:00 2001 From: Elena Kolevska Date: Sat, 1 Jul 2023 23:56:21 +0100 Subject: [PATCH 03/15] Finishes bloom and cuckoo filters --- commands.go | 241 -------------------------------- probabilistic.go | 312 ++++++++++++++++++++++++++++++++++++++++++ probabilistic_test.go | 182 +++++++++++++++++++++--- 3 files changed, 475 insertions(+), 260 deletions(-) create mode 100644 probabilistic.go diff --git a/commands.go b/commands.go index 4e2ee6664..34f4d2c22 100644 --- a/commands.go +++ b/commands.go @@ -504,22 +504,6 @@ type Cmdable interface { ACLLogReset(ctx context.Context) *StatusCmd ModuleLoadex(ctx context.Context, conf *ModuleLoadexConfig) *StringCmd - - BFAdd(ctx context.Context, key, item string) *IntCmd - BFCard(ctx context.Context, key string) *IntCmd - BFExists(ctx context.Context, key, item string) *IntCmd - BFInfo(ctx context.Context, key string) *MapStringStringCmd - BFInfoArg(ctx context.Context, key string, option BFInfo) *IntCmd - BFInsert(ctx context.Context, key string, options *BFReserveOptions, items ...string) *IntSliceCmd - BFMAdd(ctx context.Context, key string, items ...string) *IntSliceCmd - BFMExists(ctx context.Context, key string, items ...string) *IntSliceCmd - BFReserve(ctx context.Context, key string, errorRate float64, capacity int64) *StatusCmd - BFReserveExpansion(ctx context.Context, key string, errorRate float64, capacity, expansion int64) *StatusCmd - BFReserveNonScaling(ctx context.Context, key string, errorRate float64, capacity int64) *StatusCmd - BFReserveArgs(ctx context.Context, key string, options *BFReserveOptions) *StatusCmd - //TODO Loadchunk and scandump missing - - CFReserve(ctx context.Context, key string, capacity int64) *StatusCmd } type StatefulCmdable interface { @@ -3981,228 +3965,3 @@ func (c cmdable) ACLLogReset(ctx context.Context) *StatusCmd { _ = c(ctx, cmd) return cmd } - -// ------------------------------------------- - -type BFReserveOptions struct { - Capacity int64 - Error float64 - Expansion int64 - NonScaling bool -} - -type CFReserveOptions struct { - Capacity int64 - BucketSize int64 - MaxIterations int64 - Expansion int64 -} - -type BFInfo int - -const ( - BFCAPACITY BFInfo = iota - BFSIZE - BFFILTERS - BFITEMS - BFEXPANSION -) - -func (b BFInfo) String() string { - switch b { - case BFCAPACITY: - return "capacity" - case BFSIZE: - return "size" - case BFFILTERS: - return "filters" - case BFITEMS: - return "items" - case BFEXPANSION: - return "expansion" - } - return "" -} - -func (c cmdable) BFReserve(ctx context.Context, key string, errorRate float64, capacity int64) *StatusCmd { - args := []interface{}{"bf.reserve", key, errorRate, capacity} - cmd := NewStatusCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) BFReserveExpansion(ctx context.Context, key string, errorRate float64, capacity, expansion int64) *StatusCmd { - args := []interface{}{"bf.reserve", key, errorRate, capacity, "expansion", expansion} - cmd := NewStatusCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) BFReserveNonScaling(ctx context.Context, key string, errorRate float64, capacity int64) *StatusCmd { - args := []interface{}{"bf.reserve", key, errorRate, capacity, "nonscaling"} - cmd := NewStatusCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) BFReserveArgs(ctx context.Context, key string, options *BFReserveOptions) *StatusCmd { - args := []interface{}{"bf.reserve", key} - if options != nil { - if options.Error != 0 { - args = append(args, options.Error) - } - if options.Capacity != 0 { - args = append(args, options.Capacity) - } - if options.Expansion != 0 { - args = append(args, "expansion", options.Expansion) - } - if options.NonScaling { - args = append(args, "nonscaling") - } - } - cmd := NewStatusCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) BFAdd(ctx context.Context, key, item string) *IntCmd { - args := []interface{}{"bf.add", key, item} - cmd := NewIntCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) BFCard(ctx context.Context, key string) *IntCmd { - args := []interface{}{"bf.card", key} - cmd := NewIntCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) BFExists(ctx context.Context, key, item string) *IntCmd { - args := []interface{}{"bf.exists", key, item} - cmd := NewIntCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) BFInfo(ctx context.Context, key string) *MapStringStringCmd { - args := []interface{}{"bf.info", key} - cmd := NewMapStringStringCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) BFInfoArg(ctx context.Context, key string, option BFInfo) *IntCmd { - args := []interface{}{"bf.info", key, option.String()} - cmd := NewIntCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) BFInsert(ctx context.Context, key string, options *BFReserveOptions, items ...string) *IntSliceCmd { - args := []interface{}{"bf.insert", key} - if options != nil { - if options.Error != 0 { - args = append(args, "error", options.Error) - } - if options.Capacity != 0 { - args = append(args, "capacity", options.Capacity) - } - if options.Expansion != 0 { - args = append(args, "expansion", options.Expansion) - } - if options.NonScaling { - args = append(args, "nonscaling") - } - } - args = append(args, "items") - for _, s := range items { - args = append(args, s) - } - - cmd := NewIntSliceCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) BFMAdd(ctx context.Context, key string, items ...string) *IntSliceCmd { - args := []interface{}{"bf.madd", key} - for _, s := range items { - args = append(args, s) - } - cmd := NewIntSliceCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) BFMExists(ctx context.Context, key string, items ...string) *IntSliceCmd { - args := []interface{}{"bf.mexists", key} - for _, s := range items { - args = append(args, s) - } - cmd := NewIntSliceCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -// ------------------------------------------- - -func (c cmdable) CFReserve(ctx context.Context, key string, capacity int64) *StatusCmd { - args := []interface{}{"cf.reserve", key, capacity} - cmd := NewStatusCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) CFReserveArgs(ctx context.Context, key string, options *CFReserveOptions) *StatusCmd { - args := []interface{}{"cf.reserve", key, options.Capacity} - if options.BucketSize != 0 { - args = append(args, "bucketsize", options.BucketSize) - } - if options.MaxIterations != 0 { - args = append(args, "maxiterations", options.MaxIterations) - } - if options.Expansion != 0 { - args = append(args, "expansion", options.Expansion) - } - cmd := NewStatusCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) CFAdd(ctx context.Context, key, item string) *IntCmd { - args := []interface{}{"cf.add", key, item} - cmd := NewIntCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) CFCount(ctx context.Context, key, item string) *IntCmd { - args := []interface{}{"cf.count", key, item} - cmd := NewIntCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) CFAddNX(ctx context.Context, key, item string) *IntCmd { - args := []interface{}{"cf.addnx", key, item} - cmd := NewIntCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) CFDel(ctx context.Context, key string) *IntCmd { - args := []interface{}{"cf.del", key} - cmd := NewIntCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} - -func (c cmdable) CFExists(ctx context.Context, key, item string) *IntCmd { - args := []interface{}{"cf.exists", key, item} - cmd := NewIntCmd(ctx, args...) - _ = c(ctx, cmd) - return cmd -} diff --git a/probabilistic.go b/probabilistic.go new file mode 100644 index 000000000..1ad4c88ae --- /dev/null +++ b/probabilistic.go @@ -0,0 +1,312 @@ +package redis + +import ( + "context" +) + +type ProbabilisticCmdble interface { + BFAdd(ctx context.Context, key, item string) *IntCmd + BFCard(ctx context.Context, key string) *IntCmd + BFExists(ctx context.Context, key, item string) *IntCmd + BFInfo(ctx context.Context, key string) *MapStringIntCmd + BFInfoArg(ctx context.Context, key string, option BFInfo) *IntCmd + BFInsert(ctx context.Context, key string, options *BFReserveOptions, items ...string) *IntSliceCmd + BFMAdd(ctx context.Context, key string, items ...string) *IntSliceCmd + BFMExists(ctx context.Context, key string, items ...string) *IntSliceCmd + BFReserve(ctx context.Context, key string, errorRate float64, capacity int64) *StatusCmd + BFReserveExpansion(ctx context.Context, key string, errorRate float64, capacity, expansion int64) *StatusCmd + BFReserveNonScaling(ctx context.Context, key string, errorRate float64, capacity int64) *StatusCmd + BFReserveArgs(ctx context.Context, key string, options *BFReserveOptions) *StatusCmd + //TODO Loadchunk and scandump missing + + CFAdd(ctx context.Context, key, item string) *IntCmd + CFAddNX(ctx context.Context, key, item string) *IntCmd + CFCount(ctx context.Context, key, item string) *IntCmd + CFDel(ctx context.Context, key string) *IntCmd + CFExists(ctx context.Context, key, item string) *IntCmd + CFInfo(ctx context.Context, key string) *MapStringStringCmd + CFReserve(ctx context.Context, key string, capacity int64) *StatusCmd + CFInsert(ctx context.Context, key string, options *CFInsertOptions, items ...string) *IntSliceCmd + CFInsertNx(ctx context.Context, key string, options *CFInsertOptions, items ...string) *IntSliceCmd + CFMExists(ctx context.Context, key string, items ...string) *IntSliceCmd + //TODO Loadchunk and scandump missing +} + +type BFReserveOptions struct { + Capacity int64 + Error float64 + Expansion int64 + NonScaling bool +} + +type CFReserveOptions struct { + Capacity int64 + BucketSize int64 + MaxIterations int64 + Expansion int64 +} + +type CFInsertOptions struct { + Capacity int64 + NoCreate bool +} + +type BFInfo int + +const ( + BFCAPACITY BFInfo = iota + BFSIZE + BFFILTERS + BFITEMS + BFEXPANSION +) + +func (b BFInfo) String() string { + switch b { + case BFCAPACITY: + return "capacity" + case BFSIZE: + return "size" + case BFFILTERS: + return "filters" + case BFITEMS: + return "items" + case BFEXPANSION: + return "expansion" + } + return "" +} + +func (c cmdable) BFReserve(ctx context.Context, key string, errorRate float64, capacity int64) *StatusCmd { + args := []interface{}{"bf.reserve", key, errorRate, capacity} + cmd := NewStatusCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) BFReserveExpansion(ctx context.Context, key string, errorRate float64, capacity, expansion int64) *StatusCmd { + args := []interface{}{"bf.reserve", key, errorRate, capacity, "expansion", expansion} + cmd := NewStatusCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) BFReserveNonScaling(ctx context.Context, key string, errorRate float64, capacity int64) *StatusCmd { + args := []interface{}{"bf.reserve", key, errorRate, capacity, "nonscaling"} + cmd := NewStatusCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) BFReserveArgs(ctx context.Context, key string, options *BFReserveOptions) *StatusCmd { + args := []interface{}{"bf.reserve", key} + if options != nil { + if options.Error != 0 { + args = append(args, options.Error) + } + if options.Capacity != 0 { + args = append(args, options.Capacity) + } + if options.Expansion != 0 { + args = append(args, "expansion", options.Expansion) + } + if options.NonScaling { + args = append(args, "nonscaling") + } + } + cmd := NewStatusCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) BFAdd(ctx context.Context, key, item string) *IntCmd { + args := []interface{}{"bf.add", key, item} + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) BFCard(ctx context.Context, key string) *IntCmd { + args := []interface{}{"bf.card", key} + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) BFExists(ctx context.Context, key, item string) *IntCmd { + args := []interface{}{"bf.exists", key, item} + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) BFInfo(ctx context.Context, key string) *MapStringIntCmd { + args := []interface{}{"bf.info", key} + cmd := NewMapStringIntCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) BFInfoArg(ctx context.Context, key string, option BFInfo) *IntCmd { + args := []interface{}{"bf.info", key, option.String()} + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) BFInsert(ctx context.Context, key string, options *BFReserveOptions, items ...string) *IntSliceCmd { + args := []interface{}{"bf.insert", key} + if options != nil { + if options.Error != 0 { + args = append(args, "error", options.Error) + } + if options.Capacity != 0 { + args = append(args, "capacity", options.Capacity) + } + if options.Expansion != 0 { + args = append(args, "expansion", options.Expansion) + } + if options.NonScaling { + args = append(args, "nonscaling") + } + } + args = append(args, "items") + for _, s := range items { + args = append(args, s) + } + + cmd := NewIntSliceCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) BFMAdd(ctx context.Context, key string, items ...string) *IntSliceCmd { + args := []interface{}{"bf.madd", key} + for _, s := range items { + args = append(args, s) + } + cmd := NewIntSliceCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) BFMExists(ctx context.Context, key string, items ...string) *IntSliceCmd { + args := []interface{}{"bf.mexists", key} + for _, s := range items { + args = append(args, s) + } + cmd := NewIntSliceCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +// ------------------------------------------- + +func (c cmdable) CFReserve(ctx context.Context, key string, capacity int64) *StatusCmd { + args := []interface{}{"cf.reserve", key, capacity} + cmd := NewStatusCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) CFReserveArgs(ctx context.Context, key string, options *CFReserveOptions) *StatusCmd { + args := []interface{}{"cf.reserve", key, options.Capacity} + if options.BucketSize != 0 { + args = append(args, "bucketsize", options.BucketSize) + } + if options.MaxIterations != 0 { + args = append(args, "maxiterations", options.MaxIterations) + } + if options.Expansion != 0 { + args = append(args, "expansion", options.Expansion) + } + cmd := NewStatusCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) CFAdd(ctx context.Context, key, item string) *IntCmd { + args := []interface{}{"cf.add", key, item} + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) CFAddNX(ctx context.Context, key, item string) *IntCmd { + args := []interface{}{"cf.addnx", key, item} + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) CFCount(ctx context.Context, key, item string) *IntCmd { + args := []interface{}{"cf.count", key, item} + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) CFDel(ctx context.Context, key string, item string) *IntCmd { + args := []interface{}{"cf.del", key, item} + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) CFExists(ctx context.Context, key, item string) *IntCmd { + args := []interface{}{"cf.exists", key, item} + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) CFInfo(ctx context.Context, key string) *MapStringIntCmd { + args := []interface{}{"cf.info", key} + cmd := NewMapStringIntCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) CFInsert(ctx context.Context, key string, options *CFInsertOptions, items ...string) *IntSliceCmd { + args := []interface{}{"cf.insert", key} + args = c.getCfInsertArgs(args, options, items...) + + cmd := NewIntSliceCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) CFInsertNx(ctx context.Context, key string, options *CFInsertOptions, items ...string) *IntSliceCmd { + args := []interface{}{"cf.insertnx", key} + args = c.getCfInsertArgs(args, options, items...) + + cmd := NewIntSliceCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) getCfInsertArgs(args []interface{}, options *CFInsertOptions, items ...string) []interface{} { + if options != nil { + if options.Capacity != 0 { + args = append(args, "capacity", options.Capacity) + } + if options.NoCreate { + args = append(args, "nocreate") + } + } + args = append(args, "items") + for _, s := range items { + args = append(args, s) + } + return args +} + +func (c cmdable) CFMExists(ctx context.Context, key string, items ...string) *IntSliceCmd { + args := []interface{}{"cf.mexists", key} + for _, s := range items { + args = append(args, s) + } + cmd := NewIntSliceCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} diff --git a/probabilistic_test.go b/probabilistic_test.go index dacfddfcc..bf3783a95 100644 --- a/probabilistic_test.go +++ b/probabilistic_test.go @@ -5,8 +5,6 @@ import ( "fmt" . "github.com/bsm/ginkgo/v2" . "github.com/bsm/gomega" - "strconv" - "github.com/redis/go-redis/v9" ) @@ -23,8 +21,8 @@ var _ = Describe("Probabilistic commands", Label("probabilistic"), func() { Expect(client.Close()).NotTo(HaveOccurred()) }) - Describe("bloom", Label("bloom", "bfadd"), func() { - It("should BFAdd", Label("bloom"), func() { + Describe("bloom", Label("bloom"), func() { + It("should BFAdd", Label("bloom", "bfadd"), func() { resultAdd, err := client.BFAdd(ctx, "testbf1", "test1").Result() Expect(err).NotTo(HaveOccurred()) @@ -33,8 +31,8 @@ var _ = Describe("Probabilistic commands", Label("probabilistic"), func() { resultInfo, err := client.BFInfo(ctx, "testbf1").Result() Expect(err).NotTo(HaveOccurred()) - Expect(resultInfo).To(BeAssignableToTypeOf(map[string]string{})) - Expect(resultInfo["Number of items inserted"]).To(BeEquivalentTo(strconv.Itoa(1))) + Expect(resultInfo).To(BeAssignableToTypeOf(map[string]int64{})) + Expect(resultInfo["Number of items inserted"]).To(BeEquivalentTo(int64(1))) }) It("should BFCard", Label("bloom", "bfcard"), func() { @@ -75,8 +73,8 @@ var _ = Describe("Probabilistic commands", Label("probabilistic"), func() { result, err := client.BFInfo(ctx, "testbf1").Result() Expect(err).NotTo(HaveOccurred()) - Expect(result).To(BeAssignableToTypeOf(map[string]string{})) - Expect(result["Capacity"]).To(BeEquivalentTo(strconv.Itoa(2000))) + Expect(result).To(BeAssignableToTypeOf(map[string]int64{})) + Expect(result["Capacity"]).To(BeEquivalentTo(int64(2000))) }) It("should BFInsert", Label("bloom", "bfinsert"), func() { @@ -95,9 +93,9 @@ var _ = Describe("Probabilistic commands", Label("probabilistic"), func() { result, err := client.BFInfo(ctx, "testbf1").Result() Expect(err).NotTo(HaveOccurred()) - Expect(result).To(BeAssignableToTypeOf(map[string]string{})) - Expect(result["Capacity"]).To(BeEquivalentTo(strconv.Itoa(2000))) - Expect(result["Expansion rate"]).To(BeEquivalentTo(strconv.Itoa(3))) + Expect(result).To(BeAssignableToTypeOf(map[string]int64{})) + Expect(result["Capacity"]).To(BeEquivalentTo(int64(2000))) + Expect(result["Expansion rate"]).To(BeEquivalentTo(int64(3))) }) It("should BFMAdd", Label("bloom", "bfmadd"), func() { @@ -110,8 +108,8 @@ var _ = Describe("Probabilistic commands", Label("probabilistic"), func() { resultInfo, err := client.BFInfo(ctx, "testbf1").Result() Expect(err).NotTo(HaveOccurred()) - Expect(resultInfo).To(BeAssignableToTypeOf(map[string]string{})) - Expect(resultInfo["Number of items inserted"]).To(BeEquivalentTo(strconv.Itoa(3))) + Expect(resultInfo).To(BeAssignableToTypeOf(map[string]int64{})) + Expect(resultInfo["Number of items inserted"]).To(BeEquivalentTo(int64(3))) }) It("should BFMExists", Label("bloom", "bfmexists"), func() { @@ -141,9 +139,9 @@ var _ = Describe("Probabilistic commands", Label("probabilistic"), func() { result, err := client.BFInfo(ctx, "testbf1").Result() Expect(err).NotTo(HaveOccurred()) - Expect(result).To(BeAssignableToTypeOf(map[string]string{})) - Expect(result["Capacity"]).To(BeEquivalentTo(strconv.Itoa(2000))) - Expect(result["Expansion rate"]).To(BeEquivalentTo(strconv.Itoa(3))) + Expect(result).To(BeAssignableToTypeOf(map[string]int64{})) + Expect(result["Capacity"]).To(BeEquivalentTo(int64(2000))) + Expect(result["Expansion rate"]).To(BeEquivalentTo(int64(3))) }) It("should BFReserveArgs", Label("bloom", "bfreserveargs"), func() { @@ -158,9 +156,155 @@ var _ = Describe("Probabilistic commands", Label("probabilistic"), func() { result, err := client.BFInfo(ctx, "testbf").Result() Expect(err).NotTo(HaveOccurred()) - Expect(result).To(BeAssignableToTypeOf(map[string]string{})) - Expect(result["Capacity"]).To(BeEquivalentTo(strconv.Itoa(2000))) - Expect(result["Expansion rate"]).To(BeEquivalentTo(strconv.Itoa(3))) + Expect(result).To(BeAssignableToTypeOf(map[string]int64{})) + Expect(result["Capacity"]).To(BeEquivalentTo(int64(2000))) + Expect(result["Expansion rate"]).To(BeEquivalentTo(int64(3))) + }) + }) + + FDescribe("cuckoo", Label("cuckoo"), func() { + It("should CFAdd", Label("cuckoo", "cfadd"), func() { + err := client.CFAdd(ctx, "testcf1", "item1").Err() + Expect(err).NotTo(HaveOccurred()) + + exists, err := client.CFExists(ctx, "testcf1", "item1").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(exists).To(BeEquivalentTo(int64(1))) + + info, err := client.CFInfo(ctx, "testcf1").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(info).To(BeAssignableToTypeOf(map[string]int64{})) + Expect(info["Number of items inserted"]).To(BeEquivalentTo(int64(1))) + }) + + It("should CFAddNX", Label("cuckoo", "cfaddnx"), func() { + err := client.CFAddNX(ctx, "testcf1", "item1").Err() + Expect(err).NotTo(HaveOccurred()) + + exists, err := client.CFExists(ctx, "testcf1", "item1").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(exists).To(BeEquivalentTo(int64(1))) + + result, err := client.CFAddNX(ctx, "testcf1", "item1").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(result).To(BeEquivalentTo(int64(0))) + + info, err := client.CFInfo(ctx, "testcf1").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(info).To(BeAssignableToTypeOf(map[string]int64{})) + Expect(info["Number of items inserted"]).To(BeEquivalentTo(int64(1))) + }) + + It("should CFInCFCountsert", Label("cuckoo", "cfinsert"), func() { + err := client.CFAdd(ctx, "testcf1", "item1").Err() + cnt, err := client.CFCount(ctx, "testcf1", "item1").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(cnt).To(BeEquivalentTo(int64(1))) + + err = client.CFAdd(ctx, "testcf1", "item1").Err() + Expect(err).NotTo(HaveOccurred()) + + cnt, err = client.CFCount(ctx, "testcf1", "item1").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(cnt).To(BeEquivalentTo(int64(2))) + }) + + It("should CFDel and CFExists", Label("cuckoo", "cfdel", "cfexists"), func() { + err := client.CFAdd(ctx, "testcf1", "item1").Err() + Expect(err).NotTo(HaveOccurred()) + + exists, err := client.CFExists(ctx, "testcf1", "item1").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(exists).To(BeEquivalentTo(int64(1))) + + err = client.CFDel(ctx, "testcf1", "item1").Err() + Expect(err).NotTo(HaveOccurred()) + + exists, err = client.CFExists(ctx, "testcf1", "item1").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(exists).To(BeEquivalentTo(int64(0))) + }) + + It("should CFInfo and CFReserve", Label("cuckoo", "cfinfo", "cfreserve"), func() { + err := client.CFReserve(ctx, "testcf1", 1000).Err() + Expect(err).NotTo(HaveOccurred()) + + result, err := client.CFInfo(ctx, "testcf1").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(result).To(BeAssignableToTypeOf(map[string]int64{})) + }) + + It("should CFInfo and CFReserveArgs", Label("cuckoo", "cfinfo", "cfreserveargs"), func() { + args := &redis.CFReserveOptions{ + Capacity: 2048, + BucketSize: 3, + MaxIterations: 15, + Expansion: 2, + } + + err := client.CFReserveArgs(ctx, "testcf1", args).Err() + Expect(err).NotTo(HaveOccurred()) + + result, err := client.CFInfo(ctx, "testcf1").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(result).To(BeAssignableToTypeOf(map[string]int64{})) + Expect(result["Bucket size"]).To(BeEquivalentTo(int64(3))) + Expect(result["Max iterations"]).To(BeEquivalentTo(int64(15))) + Expect(result["Expansion rate"]).To(BeEquivalentTo(int64(2))) + }) + + It("should CFInsert", Label("cuckoo", "cfinsert"), func() { + args := &redis.CFInsertOptions{ + Capacity: 3000, + NoCreate: true, + } + + result, err := client.CFInsert(ctx, "testcf1", args, "item1", "item2", "item3").Result() + Expect(err).To(HaveOccurred()) + + args = &redis.CFInsertOptions{ + Capacity: 3000, + NoCreate: false, + } + + result, err = client.CFInsert(ctx, "testcf1", args, "item1", "item2", "item3").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(len(result)).To(BeEquivalentTo(3)) + }) + + It("should CFInsertNx", Label("cuckoo", "cfinsertnx"), func() { + args := &redis.CFInsertOptions{ + Capacity: 3000, + NoCreate: true, + } + + result, err := client.CFInsertNx(ctx, "testcf1", args, "item1", "item2", "item2").Result() + Expect(err).To(HaveOccurred()) + + args = &redis.CFInsertOptions{ + Capacity: 3000, + NoCreate: false, + } + + result, err = client.CFInsertNx(ctx, "testcf2", args, "item1", "item2", "item2").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(len(result)).To(BeEquivalentTo(3)) + Expect(result[0]).To(BeEquivalentTo(int64(1))) + Expect(result[1]).To(BeEquivalentTo(int64(1))) + Expect(result[2]).To(BeEquivalentTo(int64(0))) + }) + + It("should CFMexists", Label("cuckoo", "cfmexists"), func() { + err := client.CFInsert(ctx, "testcf1", nil, "item1", "item2", "item3").Err() + Expect(err).NotTo(HaveOccurred()) + + result, err := client.CFMExists(ctx, "testcf1", "item1", "item2", "item3", "item4").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(len(result)).To(BeEquivalentTo(4)) + Expect(result[0]).To(BeEquivalentTo(int64(1))) + Expect(result[1]).To(BeEquivalentTo(int64(1))) + Expect(result[2]).To(BeEquivalentTo(int64(1))) + Expect(result[3]).To(BeEquivalentTo(int64(0))) }) }) From cbf2c707c7b8cb82e310251bc593964625db457a Mon Sep 17 00:00:00 2001 From: Elena Kolevska Date: Wed, 12 Jul 2023 15:40:54 +0100 Subject: [PATCH 04/15] Bloom, Cuckoo and CMS finished --- probabilistic.go | 116 +++++++++++++++++++++++++++++++++++++----- probabilistic_test.go | 100 ++++++++++++++++++++++++++++++++++-- 2 files changed, 200 insertions(+), 16 deletions(-) diff --git a/probabilistic.go b/probabilistic.go index 1ad4c88ae..935d58a19 100644 --- a/probabilistic.go +++ b/probabilistic.go @@ -5,31 +5,35 @@ import ( ) type ProbabilisticCmdble interface { - BFAdd(ctx context.Context, key, item string) *IntCmd + BFAdd(ctx context.Context, key, item interface{}) *IntCmd BFCard(ctx context.Context, key string) *IntCmd - BFExists(ctx context.Context, key, item string) *IntCmd + BFExists(ctx context.Context, key, item interface{}) *IntCmd BFInfo(ctx context.Context, key string) *MapStringIntCmd BFInfoArg(ctx context.Context, key string, option BFInfo) *IntCmd - BFInsert(ctx context.Context, key string, options *BFReserveOptions, items ...string) *IntSliceCmd - BFMAdd(ctx context.Context, key string, items ...string) *IntSliceCmd - BFMExists(ctx context.Context, key string, items ...string) *IntSliceCmd + BFInsert(ctx context.Context, key string, options *BFReserveOptions, items ...interface{}) *IntSliceCmd + BFMAdd(ctx context.Context, key string, items ...interface{}) *IntSliceCmd + BFMExists(ctx context.Context, key string, items ...interface{}) *IntSliceCmd BFReserve(ctx context.Context, key string, errorRate float64, capacity int64) *StatusCmd BFReserveExpansion(ctx context.Context, key string, errorRate float64, capacity, expansion int64) *StatusCmd BFReserveNonScaling(ctx context.Context, key string, errorRate float64, capacity int64) *StatusCmd BFReserveArgs(ctx context.Context, key string, options *BFReserveOptions) *StatusCmd //TODO Loadchunk and scandump missing - CFAdd(ctx context.Context, key, item string) *IntCmd - CFAddNX(ctx context.Context, key, item string) *IntCmd - CFCount(ctx context.Context, key, item string) *IntCmd + CFAdd(ctx context.Context, key, item interface{}) *IntCmd + CFAddNX(ctx context.Context, key, item interface{}) *IntCmd + CFCount(ctx context.Context, key, item interface{}) *IntCmd CFDel(ctx context.Context, key string) *IntCmd - CFExists(ctx context.Context, key, item string) *IntCmd + CFExists(ctx context.Context, key, item interface{}) *IntCmd CFInfo(ctx context.Context, key string) *MapStringStringCmd CFReserve(ctx context.Context, key string, capacity int64) *StatusCmd - CFInsert(ctx context.Context, key string, options *CFInsertOptions, items ...string) *IntSliceCmd - CFInsertNx(ctx context.Context, key string, options *CFInsertOptions, items ...string) *IntSliceCmd - CFMExists(ctx context.Context, key string, items ...string) *IntSliceCmd + CFInsert(ctx context.Context, key string, options *CFInsertOptions, items ...interface{}) *IntSliceCmd + CFInsertNx(ctx context.Context, key string, options *CFInsertOptions, items ...interface{}) *IntSliceCmd + CFMExists(ctx context.Context, key string, items ...interface{}) *IntSliceCmd //TODO Loadchunk and scandump missing + + CMSIncrBy(ctx context.Context, key string, items ...interface{}) *IntSliceCmd + CMSInitByDim(ctx context.Context, key string, width, height int64) *StatusCmd + CMSInitByProb(ctx context.Context, key string, error_rate, probability float64) *StatusCmd } type BFReserveOptions struct { @@ -77,6 +81,10 @@ func (b BFInfo) String() string { return "" } +// ------------------------------------------- +// Bloom filter commands +//------------------------------------------- + func (c cmdable) BFReserve(ctx context.Context, key string, errorRate float64, capacity int64) *StatusCmd { args := []interface{}{"bf.reserve", key, errorRate, capacity} cmd := NewStatusCmd(ctx, args...) @@ -119,7 +127,7 @@ func (c cmdable) BFReserveArgs(ctx context.Context, key string, options *BFReser return cmd } -func (c cmdable) BFAdd(ctx context.Context, key, item string) *IntCmd { +func (c cmdable) BFAdd(ctx context.Context, key, item interface{}) *IntCmd { args := []interface{}{"bf.add", key, item} cmd := NewIntCmd(ctx, args...) _ = c(ctx, cmd) @@ -201,6 +209,8 @@ func (c cmdable) BFMExists(ctx context.Context, key string, items ...string) *In } // ------------------------------------------- +// Cuckoo filter commands +//------------------------------------------- func (c cmdable) CFReserve(ctx context.Context, key string, capacity int64) *StatusCmd { args := []interface{}{"cf.reserve", key, capacity} @@ -310,3 +320,83 @@ func (c cmdable) CFMExists(ctx context.Context, key string, items ...string) *In _ = c(ctx, cmd) return cmd } + +// ------------------------------------------- +// CMS commands +//------------------------------------------- + +func (c cmdable) CMSIncrBy(ctx context.Context, key string, items ...interface{}) *IntSliceCmd { + args := make([]interface{}, 2, 2+len(items)) + args[0] = "cms.incrby" + args[1] = key + args = appendArgs(args, items) + + cmd := NewIntSliceCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) CMSInitByDim(ctx context.Context, key string, width, depth int64) *StatusCmd { + args := []interface{}{"cms.initbydim", key, width, depth} + cmd := NewStatusCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) CMSInitByProb(ctx context.Context, key string, error_rate, probability float64) *StatusCmd { + args := []interface{}{"cms.initbyprob", key, error_rate, probability} + cmd := NewStatusCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) CMSInfo(ctx context.Context, key string) *MapStringIntCmd { + args := []interface{}{"cms.info", key} + cmd := NewMapStringIntCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} +func (c cmdable) CMSMerge(ctx context.Context, destKey string, sourceKeys ...string) *StatusCmd { + args := []interface{}{"cms.merge", destKey, len(sourceKeys)} + for _, s := range sourceKeys { + args = append(args, s) + } + cmd := NewStatusCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) CMSMergeWithWeight(ctx context.Context, destKey string, sourceKeys map[string]int) *StatusCmd { + args := make([]interface{}, 0, 4+(len(sourceKeys)*2+1)) + args = append(args, "cms.merge", destKey, len(sourceKeys)) + + if len(sourceKeys) > 0 { + sk := make([]interface{}, len(sourceKeys)) + sw := make([]interface{}, len(sourceKeys)) + + i := 0 + for k, w := range sourceKeys { + sk[i] = k + sw[i] = w + i++ + } + + args = append(args, sk...) + args = append(args, "weights") + args = append(args, sw...) + } + + cmd := NewStatusCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) CMSQuery(ctx context.Context, key string, items ...interface{}) *IntSliceCmd { + args := []interface{}{"cms.query", key} + for _, s := range items { + args = append(args, s) + } + cmd := NewIntSliceCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} diff --git a/probabilistic_test.go b/probabilistic_test.go index bf3783a95..07b69e9fe 100644 --- a/probabilistic_test.go +++ b/probabilistic_test.go @@ -23,7 +23,7 @@ var _ = Describe("Probabilistic commands", Label("probabilistic"), func() { Describe("bloom", Label("bloom"), func() { It("should BFAdd", Label("bloom", "bfadd"), func() { - resultAdd, err := client.BFAdd(ctx, "testbf1", "test1").Result() + resultAdd, err := client.BFAdd(ctx, "testbf1", 1).Result() Expect(err).NotTo(HaveOccurred()) Expect(resultAdd).To(Equal(int64(1))) @@ -44,7 +44,7 @@ var _ = Describe("Probabilistic commands", Label("probabilistic"), func() { Expect(err).NotTo(HaveOccurred()) _, err = client.BFAdd(ctx, "testbf1", "item2").Result() Expect(err).NotTo(HaveOccurred()) - _, err = client.BFAdd(ctx, "testbf1", "item3").Result() + _, err = client.BFAdd(ctx, "testbf1", 3).Result() Expect(err).NotTo(HaveOccurred()) result, err := client.BFCard(ctx, "testbf1").Result() @@ -162,7 +162,7 @@ var _ = Describe("Probabilistic commands", Label("probabilistic"), func() { }) }) - FDescribe("cuckoo", Label("cuckoo"), func() { + Describe("cuckoo", Label("cuckoo"), func() { It("should CFAdd", Label("cuckoo", "cfadd"), func() { err := client.CFAdd(ctx, "testcf1", "item1").Err() Expect(err).NotTo(HaveOccurred()) @@ -308,4 +308,98 @@ var _ = Describe("Probabilistic commands", Label("probabilistic"), func() { }) }) + + FDescribe("CMS", Label("cms"), func() { + It("should CMSIncrBy", Label("cms", "cmsincrby"), func() { + err := client.CMSInitByDim(ctx, "testcms1", 5, 10).Err() + Expect(err).NotTo(HaveOccurred()) + + result, err := client.CMSIncrBy(ctx, "testcms1", "item1", 1, "item2", 2, "item3", 3).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(len(result)).To(BeEquivalentTo(3)) + Expect(result[0]).To(BeEquivalentTo(int64(1))) + Expect(result[1]).To(BeEquivalentTo(int64(2))) + Expect(result[2]).To(BeEquivalentTo(int64(3))) + + }) + + It("should CMSInitByDim and CMSInfo", Label("cms", "cmsinitbydim", "cmsinfo"), func() { + err := client.CMSInitByDim(ctx, "testcms1", 5, 10).Err() + Expect(err).NotTo(HaveOccurred()) + + info, err := client.CMSInfo(ctx, "testcms1").Result() + Expect(err).NotTo(HaveOccurred()) + + fmt.Println() + fmt.Println() + fmt.Println(info) + + Expect(info).To(BeAssignableToTypeOf(map[string]int64{})) + Expect(info["width"]).To(BeEquivalentTo(int64(5))) + Expect(info["depth"]).To(BeEquivalentTo(int64(10))) + }) + + It("should CMSInitByProb", Label("cms", "cmsinitbyprob"), func() { + err := client.CMSInitByProb(ctx, "testcms1", 0.002, 0.01).Err() + Expect(err).NotTo(HaveOccurred()) + + info, err := client.CMSInfo(ctx, "testcms1").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(info).To(BeAssignableToTypeOf(map[string]int64{})) + }) + + It("should CMSMerge, CMSMergeWithWeight and CMSQuery", Label("cms", "cmsmerge", "cmsquery"), func() { + err := client.CMSMerge(ctx, "destCms1", "testcms2", "testcms3").Err() + Expect(err).To(HaveOccurred()) + Expect(err).To(MatchError("CMS: key does not exist")) + + err = client.CMSInitByDim(ctx, "destCms1", 5, 10).Err() + Expect(err).NotTo(HaveOccurred()) + err = client.CMSInitByDim(ctx, "destCms2", 5, 10).Err() + Expect(err).NotTo(HaveOccurred()) + err = client.CMSInitByDim(ctx, "cms1", 2, 20).Err() + Expect(err).NotTo(HaveOccurred()) + err = client.CMSInitByDim(ctx, "cms2", 3, 20).Err() + Expect(err).NotTo(HaveOccurred()) + + err = client.CMSMerge(ctx, "destCms1", "cms1", "cms2").Err() + Expect(err).To(MatchError("CMS: width/depth is not equal")) + + client.Del(ctx, "cms1", "cms2") + + err = client.CMSInitByDim(ctx, "cms1", 5, 10).Err() + Expect(err).NotTo(HaveOccurred()) + err = client.CMSInitByDim(ctx, "cms2", 5, 10).Err() + Expect(err).NotTo(HaveOccurred()) + + client.CMSIncrBy(ctx, "cms1", "item1", 1, "item2", 2) + client.CMSIncrBy(ctx, "cms2", "item2", 2, "item3", 3) + + err = client.CMSMerge(ctx, "destCms1", "cms1", "cms2").Err() + Expect(err).NotTo(HaveOccurred()) + + result, err := client.CMSQuery(ctx, "destCms1", "item1", "item2", "item3").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(len(result)).To(BeEquivalentTo(3)) + Expect(result[0]).To(BeEquivalentTo(int64(1))) + Expect(result[1]).To(BeEquivalentTo(int64(4))) + Expect(result[2]).To(BeEquivalentTo(int64(3))) + + sourceSketches := map[string]int{ + "cms1": 1, + "cms2": 2, + } + err = client.CMSMergeWithWeight(ctx, "destCms2", sourceSketches).Err() + Expect(err).NotTo(HaveOccurred()) + + result, err = client.CMSQuery(ctx, "destCms2", "item1", "item2", "item3").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(len(result)).To(BeEquivalentTo(3)) + Expect(result[0]).To(BeEquivalentTo(int64(1))) + Expect(result[1]).To(BeEquivalentTo(int64(6))) + Expect(result[2]).To(BeEquivalentTo(int64(6))) + + }) + + }) }) From cbb05e933ac34a171bca8efcca4f50c4fd8a1a9d Mon Sep 17 00:00:00 2001 From: Elena Kolevska Date: Wed, 12 Jul 2023 16:01:26 +0100 Subject: [PATCH 05/15] Adds cms commands to interface --- probabilistic.go | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/probabilistic.go b/probabilistic.go index 935d58a19..374162237 100644 --- a/probabilistic.go +++ b/probabilistic.go @@ -32,8 +32,12 @@ type ProbabilisticCmdble interface { //TODO Loadchunk and scandump missing CMSIncrBy(ctx context.Context, key string, items ...interface{}) *IntSliceCmd + CMSInfo(ctx context.Context, key string) *MapStringStringCmd CMSInitByDim(ctx context.Context, key string, width, height int64) *StatusCmd - CMSInitByProb(ctx context.Context, key string, error_rate, probability float64) *StatusCmd + CMSInitByProb(ctx context.Context, key string, errorRate, probability float64) *StatusCmd + CMSMerge(ctx context.Context, destKey string, sourceKeys ...string) *StatusCmd + CMSMergeWithWeight(ctx context.Context, destKey string, sourceKeys map[string]int) *StatusCmd + CMSQuery(ctx context.Context, key string, items ...interface{}) *IntSliceCmd } type BFReserveOptions struct { @@ -336,26 +340,27 @@ func (c cmdable) CMSIncrBy(ctx context.Context, key string, items ...interface{} return cmd } -func (c cmdable) CMSInitByDim(ctx context.Context, key string, width, depth int64) *StatusCmd { - args := []interface{}{"cms.initbydim", key, width, depth} - cmd := NewStatusCmd(ctx, args...) +func (c cmdable) CMSInfo(ctx context.Context, key string) *MapStringIntCmd { + args := []interface{}{"cms.info", key} + cmd := NewMapStringIntCmd(ctx, args...) _ = c(ctx, cmd) return cmd } -func (c cmdable) CMSInitByProb(ctx context.Context, key string, error_rate, probability float64) *StatusCmd { - args := []interface{}{"cms.initbyprob", key, error_rate, probability} +func (c cmdable) CMSInitByDim(ctx context.Context, key string, width, depth int64) *StatusCmd { + args := []interface{}{"cms.initbydim", key, width, depth} cmd := NewStatusCmd(ctx, args...) _ = c(ctx, cmd) return cmd } -func (c cmdable) CMSInfo(ctx context.Context, key string) *MapStringIntCmd { - args := []interface{}{"cms.info", key} - cmd := NewMapStringIntCmd(ctx, args...) +func (c cmdable) CMSInitByProb(ctx context.Context, key string, errorRate, probability float64) *StatusCmd { + args := []interface{}{"cms.initbyprob", key, errorRate, probability} + cmd := NewStatusCmd(ctx, args...) _ = c(ctx, cmd) return cmd } + func (c cmdable) CMSMerge(ctx context.Context, destKey string, sourceKeys ...string) *StatusCmd { args := []interface{}{"cms.merge", destKey, len(sourceKeys)} for _, s := range sourceKeys { From 854a2da31fb7c489ad9d936566743cb72b499662 Mon Sep 17 00:00:00 2001 From: Elena Kolevska Date: Thu, 13 Jul 2023 11:21:44 +0100 Subject: [PATCH 06/15] Adds TopK --- probabilistic.go | 175 +++++++++++++++++++++++++++++++++++++++++- probabilistic_test.go | 69 ++++++++++++++++- 2 files changed, 242 insertions(+), 2 deletions(-) diff --git a/probabilistic.go b/probabilistic.go index 374162237..6752cbcce 100644 --- a/probabilistic.go +++ b/probabilistic.go @@ -2,6 +2,8 @@ package redis import ( "context" + "fmt" + "github.com/redis/go-redis/v9/internal/proto" ) type ProbabilisticCmdble interface { @@ -29,7 +31,6 @@ type ProbabilisticCmdble interface { CFInsert(ctx context.Context, key string, options *CFInsertOptions, items ...interface{}) *IntSliceCmd CFInsertNx(ctx context.Context, key string, options *CFInsertOptions, items ...interface{}) *IntSliceCmd CFMExists(ctx context.Context, key string, items ...interface{}) *IntSliceCmd - //TODO Loadchunk and scandump missing CMSIncrBy(ctx context.Context, key string, items ...interface{}) *IntSliceCmd CMSInfo(ctx context.Context, key string) *MapStringStringCmd @@ -38,6 +39,14 @@ type ProbabilisticCmdble interface { CMSMerge(ctx context.Context, destKey string, sourceKeys ...string) *StatusCmd CMSMergeWithWeight(ctx context.Context, destKey string, sourceKeys map[string]int) *StatusCmd CMSQuery(ctx context.Context, key string, items ...interface{}) *IntSliceCmd + + TOPKAdd(ctx context.Context, key string, items ...interface{}) *StringSliceCmd + TOPKReserve(ctx context.Context, key string, k int) *StatusCmd + TOPKReserveWithOptions(ctx context.Context, key string, k int, width, depth int64, decay float64) *StatusCmd + TOPKInfo(ctx context.Context, key string) *MapStringInterfaceCmd + TOPKQuery(ctx context.Context, key string, items ...interface{}) *BoolSliceCmd + TOPKCount(ctx context.Context, key string, items ...interface{}) *IntSliceCmd + TOPKIncrBy(ctx context.Context, key string, items ...interface{}) *StringSliceCmd } type BFReserveOptions struct { @@ -405,3 +414,167 @@ func (c cmdable) CMSQuery(ctx context.Context, key string, items ...interface{}) _ = c(ctx, cmd) return cmd } + +// ------------------------------------------- +// TOPK commands +//------------------------------------------- + +func (c cmdable) TOPKAdd(ctx context.Context, key string, items ...interface{}) *StringSliceCmd { + args := make([]interface{}, 2, 2+len(items)) + args[0] = "topk.add" + args[1] = key + args = appendArgs(args, items) + + cmd := NewStringSliceCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) TOPKReserve(ctx context.Context, key string, k int) *StatusCmd { + args := []interface{}{"topk.reserve", key, k} + + cmd := NewStatusCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) TOPKReserveWithOptions(ctx context.Context, key string, k int, width, depth int64, decay float64) *StatusCmd { + args := []interface{}{"topk.reserve", key, k, width, depth, decay} + + cmd := NewStatusCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +type TOPKInfo struct { + K int64 + Width int64 + Depth int64 + Decay float64 +} + +type TOPKInfoCmd struct { + baseCmd + + val TOPKInfo +} + +func NewTOPKInfoCmd(ctx context.Context, args ...interface{}) *TOPKInfoCmd { + return &TOPKInfoCmd{ + baseCmd: baseCmd{ + ctx: ctx, + args: args, + }, + } +} + +func (cmd *TOPKInfoCmd) SetVal(val TOPKInfo) { + cmd.val = val +} + +func (cmd *TOPKInfoCmd) String() string { + return cmdString(cmd, cmd.val) +} + +func (cmd *TOPKInfoCmd) Val() TOPKInfo { + return cmd.val +} + +func (cmd *TOPKInfoCmd) Result() (TOPKInfo, error) { + return cmd.val, cmd.err +} + +func (cmd *TOPKInfoCmd) readReply(rd *proto.Reader) (err error) { + n, err := rd.ReadMapLen() + if err != nil { + return err + } + + var key string + var result TOPKInfo + for f := 0; f < n; f++ { + key, err = rd.ReadString() + if err != nil { + return err + } + + switch key { + case "k": + result.K, err = rd.ReadInt() + case "width": + result.Width, err = rd.ReadInt() + case "depth": + result.Depth, err = rd.ReadInt() + case "decay": + result.Decay, err = rd.ReadFloat() + default: + return fmt.Errorf("redis: topk.info unexpected key %s", key) + } + + if err != nil { + return err + } + } + + cmd.val = result + return nil +} + +func (c cmdable) TOPKInfo(ctx context.Context, key string) *TOPKInfoCmd { + args := make([]interface{}, 2, 2) + args[0] = "topk.info" + args[1] = key + + cmd := NewTOPKInfoCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) TOPKQuery(ctx context.Context, key string, items ...interface{}) *BoolSliceCmd { + args := make([]interface{}, 2, 2+len(items)) + args[0] = "topk.query" + args[1] = key + args = appendArgs(args, items) + + cmd := NewBoolSliceCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) TOPKCount(ctx context.Context, key string, items ...interface{}) *IntSliceCmd { + args := make([]interface{}, 2, 2+len(items)) + args[0] = "topk.count" + args[1] = key + args = appendArgs(args, items) + + cmd := NewIntSliceCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) TOPKIncrBy(ctx context.Context, key string, items ...interface{}) *StringSliceCmd { + args := make([]interface{}, 2, 2+len(items)) + args[0] = "topk.incrby" + args[1] = key + args = appendArgs(args, items) + + cmd := NewStringSliceCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) TOPKList(ctx context.Context, key string) *StringSliceCmd { + args := []interface{}{"topk.list", key} + + cmd := NewStringSliceCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) TOPKListWithCount(ctx context.Context, key string) *MapStringIntCmd { + args := []interface{}{"topk.list", key, "withcount"} + + cmd := NewMapStringIntCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} diff --git a/probabilistic_test.go b/probabilistic_test.go index 07b69e9fe..67fedb2b3 100644 --- a/probabilistic_test.go +++ b/probabilistic_test.go @@ -309,7 +309,7 @@ var _ = Describe("Probabilistic commands", Label("probabilistic"), func() { }) - FDescribe("CMS", Label("cms"), func() { + Describe("CMS", Label("cms"), func() { It("should CMSIncrBy", Label("cms", "cmsincrby"), func() { err := client.CMSInitByDim(ctx, "testcms1", 5, 10).Err() Expect(err).NotTo(HaveOccurred()) @@ -402,4 +402,71 @@ var _ = Describe("Probabilistic commands", Label("probabilistic"), func() { }) }) + + Describe("TopK", Label("topk"), func() { + It("should TopKReserve, TOPKInfo, TOPKAdd, TOPKQuery, TOPKCount, TOPKIncrBy, TOPKList, TOPKListWithCount", Label("topk", "topkreserve", "topkinfo", "topkadd", "topkquery", "topkcount", "topkincrby", "topklist", "topklistwithcount"), func() { + err := client.TOPKReserve(ctx, "topk1", 3).Err() + Expect(err).NotTo(HaveOccurred()) + + resultInfo, err := client.TOPKInfo(ctx, "topk1").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(resultInfo.K).To(BeEquivalentTo(int64(3))) + + resultAdd, err := client.TOPKAdd(ctx, "topk1", "item1", "item2", 3, "item1").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(len(resultAdd)).To(BeEquivalentTo(int64(4))) + + resultQuery, err := client.TOPKQuery(ctx, "topk1", "item1", "item2", 4, 3).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(len(resultQuery)).To(BeEquivalentTo(int(4))) + Expect(resultQuery[0]).To(BeTrue()) + Expect(resultQuery[1]).To(BeTrue()) + Expect(resultQuery[2]).To(BeFalse()) + Expect(resultQuery[3]).To(BeTrue()) + + resultCount, err := client.TOPKCount(ctx, "topk1", "item1", "item2", "item3").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(len(resultCount)).To(BeEquivalentTo(int(3))) + Expect(resultCount[0]).To(BeEquivalentTo(int64(2))) + Expect(resultCount[1]).To(BeEquivalentTo(int64(1))) + Expect(resultCount[2]).To(BeEquivalentTo(int64(0))) + + resultIncr, err := client.TOPKIncrBy(ctx, "topk1", "item1", 5, "item2", 10).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(len(resultIncr)).To(BeEquivalentTo(int(2))) + + resultCount, err = client.TOPKCount(ctx, "topk1", "item1", "item2", "item3").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(len(resultCount)).To(BeEquivalentTo(int(3))) + Expect(resultCount[0]).To(BeEquivalentTo(int64(7))) + Expect(resultCount[1]).To(BeEquivalentTo(int64(11))) + Expect(resultCount[2]).To(BeEquivalentTo(int64(0))) + + resultList, err := client.TOPKList(ctx, "topk1").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(len(resultList)).To(BeEquivalentTo(int(3))) + Expect(resultList).To(ContainElements("item2", "item1", "3")) + + resultListWithCount, err := client.TOPKListWithCount(ctx, "topk1").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(len(resultListWithCount)).To(BeEquivalentTo(int(3))) + Expect(resultListWithCount["3"]).To(BeEquivalentTo(int64(1))) + Expect(resultListWithCount["item1"]).To(BeEquivalentTo(int64(7))) + Expect(resultListWithCount["item2"]).To(BeEquivalentTo(int64(11))) + }) + + It("should TOPKReserveWithOptions", Label("topk", "topkreservewithoptions"), func() { + //&redis.TOPKReserveOptions{Width: 1500, Depth: 8, Decay: 0.5} + err := client.TOPKReserveWithOptions(ctx, "topk1", 3, 1500, 8, 0.5).Err() + Expect(err).NotTo(HaveOccurred()) + + resultInfo, err := client.TOPKInfo(ctx, "topk1").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(resultInfo.K).To(BeEquivalentTo(int64(3))) + Expect(resultInfo.Width).To(BeEquivalentTo(int64(1500))) + Expect(resultInfo.Depth).To(BeEquivalentTo(int64(8))) + Expect(resultInfo.Decay).To(BeEquivalentTo(float64(0.5))) + }) + + }) }) From cf8ed97d65bf2a9e4b2e8a8b9793b00024a9b1a6 Mon Sep 17 00:00:00 2001 From: Elena Kolevska Date: Sun, 16 Jul 2023 16:50:12 +0100 Subject: [PATCH 07/15] Update for latest resp3 changes. Use a custom INFO response objects for all data structures --- probabilistic.go | 311 ++++++++++++++++++++++++++++++++++++------ probabilistic_test.go | 127 +++++++++-------- 2 files changed, 340 insertions(+), 98 deletions(-) diff --git a/probabilistic.go b/probabilistic.go index 6752cbcce..da3c3fd37 100644 --- a/probabilistic.go +++ b/probabilistic.go @@ -10,8 +10,8 @@ type ProbabilisticCmdble interface { BFAdd(ctx context.Context, key, item interface{}) *IntCmd BFCard(ctx context.Context, key string) *IntCmd BFExists(ctx context.Context, key, item interface{}) *IntCmd - BFInfo(ctx context.Context, key string) *MapStringIntCmd - BFInfoArg(ctx context.Context, key string, option BFInfo) *IntCmd + BFInfo(ctx context.Context, key string) *BFInfoCmd + BFInfoArg(ctx context.Context, key string, option BFInfo) *BFInfoCmd BFInsert(ctx context.Context, key string, options *BFReserveOptions, items ...interface{}) *IntSliceCmd BFMAdd(ctx context.Context, key string, items ...interface{}) *IntSliceCmd BFMExists(ctx context.Context, key string, items ...interface{}) *IntSliceCmd @@ -26,14 +26,14 @@ type ProbabilisticCmdble interface { CFCount(ctx context.Context, key, item interface{}) *IntCmd CFDel(ctx context.Context, key string) *IntCmd CFExists(ctx context.Context, key, item interface{}) *IntCmd - CFInfo(ctx context.Context, key string) *MapStringStringCmd + CFInfo(ctx context.Context, key string) *CFInfoCmd CFReserve(ctx context.Context, key string, capacity int64) *StatusCmd CFInsert(ctx context.Context, key string, options *CFInsertOptions, items ...interface{}) *IntSliceCmd CFInsertNx(ctx context.Context, key string, options *CFInsertOptions, items ...interface{}) *IntSliceCmd CFMExists(ctx context.Context, key string, items ...interface{}) *IntSliceCmd CMSIncrBy(ctx context.Context, key string, items ...interface{}) *IntSliceCmd - CMSInfo(ctx context.Context, key string) *MapStringStringCmd + CMSInfo(ctx context.Context, key string) *CMSInfoCmd CMSInitByDim(ctx context.Context, key string, width, height int64) *StatusCmd CMSInitByProb(ctx context.Context, key string, errorRate, probability float64) *StatusCmd CMSMerge(ctx context.Context, destKey string, sourceKeys ...string) *StatusCmd @@ -43,7 +43,7 @@ type ProbabilisticCmdble interface { TOPKAdd(ctx context.Context, key string, items ...interface{}) *StringSliceCmd TOPKReserve(ctx context.Context, key string, k int) *StatusCmd TOPKReserveWithOptions(ctx context.Context, key string, k int, width, depth int64, decay float64) *StatusCmd - TOPKInfo(ctx context.Context, key string) *MapStringInterfaceCmd + TOPKInfo(ctx context.Context, key string) *TOPKInfoCmd TOPKQuery(ctx context.Context, key string, items ...interface{}) *BoolSliceCmd TOPKCount(ctx context.Context, key string, items ...interface{}) *IntSliceCmd TOPKIncrBy(ctx context.Context, key string, items ...interface{}) *StringSliceCmd @@ -68,17 +68,17 @@ type CFInsertOptions struct { NoCreate bool } -type BFInfo int +type BFInfoArgs int const ( - BFCAPACITY BFInfo = iota + BFCAPACITY BFInfoArgs = iota BFSIZE BFFILTERS BFITEMS BFEXPANSION ) -func (b BFInfo) String() string { +func (b BFInfoArgs) String() string { switch b { case BFCAPACITY: return "capacity" @@ -140,9 +140,9 @@ func (c cmdable) BFReserveArgs(ctx context.Context, key string, options *BFReser return cmd } -func (c cmdable) BFAdd(ctx context.Context, key, item interface{}) *IntCmd { +func (c cmdable) BFAdd(ctx context.Context, key, item interface{}) *BoolCmd { args := []interface{}{"bf.add", key, item} - cmd := NewIntCmd(ctx, args...) + cmd := NewBoolCmd(ctx, args...) _ = c(ctx, cmd) return cmd } @@ -154,28 +154,105 @@ func (c cmdable) BFCard(ctx context.Context, key string) *IntCmd { return cmd } -func (c cmdable) BFExists(ctx context.Context, key, item string) *IntCmd { +func (c cmdable) BFExists(ctx context.Context, key, item string) *BoolCmd { args := []interface{}{"bf.exists", key, item} - cmd := NewIntCmd(ctx, args...) + cmd := NewBoolCmd(ctx, args...) _ = c(ctx, cmd) return cmd } -func (c cmdable) BFInfo(ctx context.Context, key string) *MapStringIntCmd { +func (c cmdable) BFInfo(ctx context.Context, key string) *BFInfoCmd { args := []interface{}{"bf.info", key} - cmd := NewMapStringIntCmd(ctx, args...) + cmd := NewBFInfoCmd(ctx, args...) _ = c(ctx, cmd) return cmd } -func (c cmdable) BFInfoArg(ctx context.Context, key string, option BFInfo) *IntCmd { +type BFInfo struct { + Capacity int64 + Size int64 + NumFilters int64 + NumItemsInserted int64 + ExpansionRate int64 +} + +type BFInfoCmd struct { + baseCmd + + val BFInfo +} + +func NewBFInfoCmd(ctx context.Context, args ...interface{}) *BFInfoCmd { + return &BFInfoCmd{ + baseCmd: baseCmd{ + ctx: ctx, + args: args, + }, + } +} + +func (cmd *BFInfoCmd) SetVal(val BFInfo) { + cmd.val = val +} + +func (cmd *BFInfoCmd) String() string { + return cmdString(cmd, cmd.val) +} + +func (cmd *BFInfoCmd) Val() BFInfo { + return cmd.val +} + +func (cmd *BFInfoCmd) Result() (BFInfo, error) { + return cmd.val, cmd.err +} + +func (cmd *BFInfoCmd) readReply(rd *proto.Reader) (err error) { + n, err := rd.ReadMapLen() + if err != nil { + return err + } + + var key string + var result BFInfo + for f := 0; f < n; f++ { + key, err = rd.ReadString() + if err != nil { + return err + } + + switch key { + case "Capacity": + result.Capacity, err = rd.ReadInt() + case "Size": + result.Size, err = rd.ReadInt() + case "Number of filters": + result.NumFilters, err = rd.ReadInt() + case "Number of items inserted": + result.NumItemsInserted, err = rd.ReadInt() + case "Expansion rate": + result.ExpansionRate, err = rd.ReadInt() + default: + return fmt.Errorf("redis: bloom.info unexpected key %s", key) + } + + if err != nil { + return err + } + } + + cmd.val = result + return nil +} + +func (c cmdable) BFInfoArg(ctx context.Context, key string, option BFInfoArgs) *BFInfoCmd { args := []interface{}{"bf.info", key, option.String()} - cmd := NewIntCmd(ctx, args...) + cmd := NewBFInfoCmd(ctx, args...) _ = c(ctx, cmd) return cmd } -func (c cmdable) BFInsert(ctx context.Context, key string, options *BFReserveOptions, items ...string) *IntSliceCmd { +func (c cmdable) BFInsert(ctx context.Context, key string, options *BFReserveOptions, items ...string) *BoolSliceCmd { args := []interface{}{"bf.insert", key} if options != nil { if options.Error != 0 { @@ -196,27 +273,27 @@ func (c cmdable) BFInsert(ctx context.Context, key string, options *BFReserveOpt args = append(args, s) } - cmd := NewIntSliceCmd(ctx, args...) + cmd := NewBoolSliceCmd(ctx, args...) _ = c(ctx, cmd) return cmd } -func (c cmdable) BFMAdd(ctx context.Context, key string, items ...string) *IntSliceCmd { +func (c cmdable) BFMAdd(ctx context.Context, key string, items ...string) *BoolSliceCmd { args := []interface{}{"bf.madd", key} for _, s := range items { args = append(args, s) } - cmd := NewIntSliceCmd(ctx, args...) + cmd := NewBoolSliceCmd(ctx, args...) _ = c(ctx, cmd) return cmd } -func (c cmdable) BFMExists(ctx context.Context, key string, items ...string) *IntSliceCmd { +func (c cmdable) BFMExists(ctx context.Context, key string, items ...string) *BoolSliceCmd { args := []interface{}{"bf.mexists", key} for _, s := range items { args = append(args, s) } - cmd := NewIntSliceCmd(ctx, args...) + cmd := NewBoolSliceCmd(ctx, args...) _ = c(ctx, cmd) return cmd } @@ -248,16 +325,16 @@ func (c cmdable) CFReserveArgs(ctx context.Context, key string, options *CFReser return cmd } -func (c cmdable) CFAdd(ctx context.Context, key, item string) *IntCmd { +func (c cmdable) CFAdd(ctx context.Context, key, item string) *BoolCmd { args := []interface{}{"cf.add", key, item} - cmd := NewIntCmd(ctx, args...) + cmd := NewBoolCmd(ctx, args...) _ = c(ctx, cmd) return cmd } -func (c cmdable) CFAddNX(ctx context.Context, key, item string) *IntCmd { +func (c cmdable) CFAddNX(ctx context.Context, key, item string) *BoolCmd { args := []interface{}{"cf.addnx", key, item} - cmd := NewIntCmd(ctx, args...) + cmd := NewBoolCmd(ctx, args...) _ = c(ctx, cmd) return cmd } @@ -269,32 +346,119 @@ func (c cmdable) CFCount(ctx context.Context, key, item string) *IntCmd { return cmd } -func (c cmdable) CFDel(ctx context.Context, key string, item string) *IntCmd { +func (c cmdable) CFDel(ctx context.Context, key string, item string) *BoolCmd { args := []interface{}{"cf.del", key, item} - cmd := NewIntCmd(ctx, args...) + cmd := NewBoolCmd(ctx, args...) _ = c(ctx, cmd) return cmd } -func (c cmdable) CFExists(ctx context.Context, key, item string) *IntCmd { +func (c cmdable) CFExists(ctx context.Context, key, item string) *BoolCmd { args := []interface{}{"cf.exists", key, item} - cmd := NewIntCmd(ctx, args...) + cmd := NewBoolCmd(ctx, args...) _ = c(ctx, cmd) return cmd } -func (c cmdable) CFInfo(ctx context.Context, key string) *MapStringIntCmd { +type CFInfo struct { + Size int64 + NumBuckets int64 + NumFilters int64 + NumItemsInserted int64 + NumItemsDeleted int64 + BucketSize int64 + ExpansionRate int64 + MaxIteration int64 +} + +type CFInfoCmd struct { + baseCmd + + val CFInfo +} + +func NewCFInfoCmd(ctx context.Context, args ...interface{}) *CFInfoCmd { + return &CFInfoCmd{ + baseCmd: baseCmd{ + ctx: ctx, + args: args, + }, + } +} + +func (cmd *CFInfoCmd) SetVal(val CFInfo) { + cmd.val = val +} + +func (cmd *CFInfoCmd) String() string { + return cmdString(cmd, cmd.val) +} + +func (cmd *CFInfoCmd) Val() CFInfo { + return cmd.val +} + +func (cmd *CFInfoCmd) Result() (CFInfo, error) { + return cmd.val, cmd.err +} + +func (cmd *CFInfoCmd) readReply(rd *proto.Reader) (err error) { + n, err := rd.ReadMapLen() + if err != nil { + return err + } + + var key string + var result CFInfo + for f := 0; f < n; f++ { + key, err = rd.ReadString() + if err != nil { + return err + } + + switch key { + case "Size": + result.Size, err = rd.ReadInt() + case "Number of buckets": + result.NumBuckets, err = rd.ReadInt() + case "Number of filters": + result.NumFilters, err = rd.ReadInt() + case "Number of items inserted": + result.NumItemsInserted, err = rd.ReadInt() + case "Number of items deleted": + result.NumItemsDeleted, err = rd.ReadInt() + case "Bucket size": + result.BucketSize, err = rd.ReadInt() + case "Expansion rate": + result.ExpansionRate, err = rd.ReadInt() + case "Max iterations": + result.MaxIteration, err = rd.ReadInt() + + default: + return fmt.Errorf("redis: cf.info unexpected key %s", key) + } + + if err != nil { + return err + } + } + + cmd.val = result + return nil +} + +func (c cmdable) CFInfo(ctx context.Context, key string) *CFInfoCmd { args := []interface{}{"cf.info", key} - cmd := NewMapStringIntCmd(ctx, args...) + cmd := NewCFInfoCmd(ctx, args...) _ = c(ctx, cmd) return cmd } -func (c cmdable) CFInsert(ctx context.Context, key string, options *CFInsertOptions, items ...string) *IntSliceCmd { +func (c cmdable) CFInsert(ctx context.Context, key string, options *CFInsertOptions, items ...string) *BoolSliceCmd { args := []interface{}{"cf.insert", key} args = c.getCfInsertArgs(args, options, items...) - cmd := NewIntSliceCmd(ctx, args...) + cmd := NewBoolSliceCmd(ctx, args...) _ = c(ctx, cmd) return cmd } @@ -324,12 +488,12 @@ func (c cmdable) getCfInsertArgs(args []interface{}, options *CFInsertOptions, i return args } -func (c cmdable) CFMExists(ctx context.Context, key string, items ...string) *IntSliceCmd { +func (c cmdable) CFMExists(ctx context.Context, key string, items ...string) *BoolSliceCmd { args := []interface{}{"cf.mexists", key} for _, s := range items { args = append(args, s) } - cmd := NewIntSliceCmd(ctx, args...) + cmd := NewBoolSliceCmd(ctx, args...) _ = c(ctx, cmd) return cmd } @@ -349,9 +513,80 @@ func (c cmdable) CMSIncrBy(ctx context.Context, key string, items ...interface{} return cmd } -func (c cmdable) CMSInfo(ctx context.Context, key string) *MapStringIntCmd { +type CMSInfo struct { + Width int64 + Depth int64 + Count int64 +} + +type CMSInfoCmd struct { + baseCmd + + val CMSInfo +} + +func NewCMSInfoCmd(ctx context.Context, args ...interface{}) *CMSInfoCmd { + return &CMSInfoCmd{ + baseCmd: baseCmd{ + ctx: ctx, + args: args, + }, + } +} + +func (cmd *CMSInfoCmd) SetVal(val CMSInfo) { + cmd.val = val +} + +func (cmd *CMSInfoCmd) String() string { + return cmdString(cmd, cmd.val) +} + +func (cmd *CMSInfoCmd) Val() CMSInfo { + return cmd.val +} + +func (cmd *CMSInfoCmd) Result() (CMSInfo, error) { + return cmd.val, cmd.err +} + +func (cmd *CMSInfoCmd) readReply(rd *proto.Reader) (err error) { + n, err := rd.ReadMapLen() + if err != nil { + return err + } + + var key string + var result CMSInfo + for f := 0; f < n; f++ { + key, err = rd.ReadString() + if err != nil { + return err + } + + switch key { + case "width": + result.Width, err = rd.ReadInt() + case "depth": + result.Depth, err = rd.ReadInt() + case "count": + result.Count, err = rd.ReadInt() + default: + return fmt.Errorf("redis: cms.info unexpected key %s", key) + } + + if err != nil { + return err + } + } + + cmd.val = result + return nil +} + +func (c cmdable) CMSInfo(ctx context.Context, key string) *CMSInfoCmd { args := []interface{}{"cms.info", key} - cmd := NewMapStringIntCmd(ctx, args...) + cmd := NewCMSInfoCmd(ctx, args...) _ = c(ctx, cmd) return cmd } diff --git a/probabilistic_test.go b/probabilistic_test.go index 67fedb2b3..6a661ab05 100644 --- a/probabilistic_test.go +++ b/probabilistic_test.go @@ -2,7 +2,6 @@ package redis_test import ( "context" - "fmt" . "github.com/bsm/ginkgo/v2" . "github.com/bsm/gomega" "github.com/redis/go-redis/v9" @@ -26,13 +25,13 @@ var _ = Describe("Probabilistic commands", Label("probabilistic"), func() { resultAdd, err := client.BFAdd(ctx, "testbf1", 1).Result() Expect(err).NotTo(HaveOccurred()) - Expect(resultAdd).To(Equal(int64(1))) + Expect(resultAdd).To(BeTrue()) resultInfo, err := client.BFInfo(ctx, "testbf1").Result() Expect(err).NotTo(HaveOccurred()) - Expect(resultInfo).To(BeAssignableToTypeOf(map[string]int64{})) - Expect(resultInfo["Number of items inserted"]).To(BeEquivalentTo(int64(1))) + Expect(resultInfo).To(BeAssignableToTypeOf(redis.BFInfo{})) + Expect(resultInfo.NumItemsInserted).To(BeEquivalentTo(int64(1))) }) It("should BFCard", Label("bloom", "bfcard"), func() { @@ -56,7 +55,7 @@ var _ = Describe("Probabilistic commands", Label("probabilistic"), func() { It("should BFExists", Label("bloom", "bfexists"), func() { exists, err := client.BFExists(ctx, "testbf1", "item1").Result() Expect(err).NotTo(HaveOccurred()) - Expect(exists).To(Equal(int64(0))) + Expect(exists).To(BeFalse()) _, err = client.BFAdd(ctx, "testbf1", "item1").Result() Expect(err).NotTo(HaveOccurred()) @@ -64,7 +63,7 @@ var _ = Describe("Probabilistic commands", Label("probabilistic"), func() { exists, err = client.BFExists(ctx, "testbf1", "item1").Result() Expect(err).NotTo(HaveOccurred()) - Expect(exists).To(BeEquivalentTo(int64(1))) + Expect(exists).To(BeTrue()) }) It("should BFInfo and BFReserve", Label("bloom", "bfinfo", "bfreserve"), func() { @@ -73,8 +72,17 @@ var _ = Describe("Probabilistic commands", Label("probabilistic"), func() { result, err := client.BFInfo(ctx, "testbf1").Result() Expect(err).NotTo(HaveOccurred()) - Expect(result).To(BeAssignableToTypeOf(map[string]int64{})) - Expect(result["Capacity"]).To(BeEquivalentTo(int64(2000))) + Expect(result).To(BeAssignableToTypeOf(redis.BFInfo{})) + Expect(result.Capacity).To(BeEquivalentTo(int64(2000))) + }) + + It("should BFInfoArg", Label("bloom", "bfinfoarg"), func() { + err := client.BFReserve(ctx, "testbf1", 0.001, 2000).Err() + Expect(err).NotTo(HaveOccurred()) + + result, err := client.BFInfoArg(ctx, "testbf1", redis.BFInfoArgs(redis.BFCAPACITY)).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(result.Capacity).To(BeEquivalentTo(int64(2000))) }) It("should BFInsert", Label("bloom", "bfinsert"), func() { @@ -84,41 +92,41 @@ var _ = Describe("Probabilistic commands", Label("probabilistic"), func() { Expansion: 3, NonScaling: false, } - err := client.BFInsert(ctx, "testbf1", options, "item1").Err() + resultInsert, err := client.BFInsert(ctx, "testbf1", options, "item1").Result() Expect(err).NotTo(HaveOccurred()) + Expect(len(resultInsert)).To(BeEquivalentTo(1)) exists, err := client.BFExists(ctx, "testbf1", "item1").Result() Expect(err).NotTo(HaveOccurred()) - Expect(exists).To(BeEquivalentTo(int64(1))) + Expect(exists).To(BeTrue()) result, err := client.BFInfo(ctx, "testbf1").Result() Expect(err).NotTo(HaveOccurred()) - Expect(result).To(BeAssignableToTypeOf(map[string]int64{})) - Expect(result["Capacity"]).To(BeEquivalentTo(int64(2000))) - Expect(result["Expansion rate"]).To(BeEquivalentTo(int64(3))) + Expect(result).To(BeAssignableToTypeOf(redis.BFInfo{})) + Expect(result.Capacity).To(BeEquivalentTo(int64(2000))) + Expect(result.ExpansionRate).To(BeEquivalentTo(int64(3))) }) It("should BFMAdd", Label("bloom", "bfmadd"), func() { resultAdd, err := client.BFMAdd(ctx, "testbf1", "item1", "item2", "item3").Result() - fmt.Printf("resultAdd: %v\n", resultAdd) Expect(err).NotTo(HaveOccurred()) - Expect(len(resultAdd)).To(Equal(int(3))) + Expect(len(resultAdd)).To(Equal(3)) resultInfo, err := client.BFInfo(ctx, "testbf1").Result() Expect(err).NotTo(HaveOccurred()) - Expect(resultInfo).To(BeAssignableToTypeOf(map[string]int64{})) - Expect(resultInfo["Number of items inserted"]).To(BeEquivalentTo(int64(3))) + Expect(resultInfo).To(BeAssignableToTypeOf(redis.BFInfo{})) + Expect(resultInfo.NumItemsInserted).To(BeEquivalentTo(int64(3))) }) It("should BFMExists", Label("bloom", "bfmexists"), func() { exist, err := client.BFMExists(ctx, "testbf1", "item1", "item2", "item3").Result() Expect(err).NotTo(HaveOccurred()) Expect(len(exist)).To(Equal(int(3))) - Expect(exist[0]).To(Equal(int64(0))) - Expect(exist[1]).To(Equal(int64(0))) - Expect(exist[2]).To(Equal(int64(0))) + Expect(exist[0]).To(BeFalse()) + Expect(exist[1]).To(BeFalse()) + Expect(exist[2]).To(BeFalse()) _, err = client.BFMAdd(ctx, "testbf1", "item1", "item2", "item3").Result() Expect(err).NotTo(HaveOccurred()) @@ -127,10 +135,10 @@ var _ = Describe("Probabilistic commands", Label("probabilistic"), func() { Expect(err).NotTo(HaveOccurred()) Expect(len(exist)).To(Equal(int(4))) - Expect(exist[0]).To(Equal(int64(1))) - Expect(exist[1]).To(Equal(int64(1))) - Expect(exist[2]).To(Equal(int64(1))) - Expect(exist[3]).To(Equal(int64(0))) + Expect(exist[0]).To(BeTrue()) + Expect(exist[1]).To(BeTrue()) + Expect(exist[2]).To(BeTrue()) + Expect(exist[3]).To(BeFalse()) }) It("should BFReserveExpansion", Label("bloom", "bfreserveexpansion"), func() { @@ -139,9 +147,9 @@ var _ = Describe("Probabilistic commands", Label("probabilistic"), func() { result, err := client.BFInfo(ctx, "testbf1").Result() Expect(err).NotTo(HaveOccurred()) - Expect(result).To(BeAssignableToTypeOf(map[string]int64{})) - Expect(result["Capacity"]).To(BeEquivalentTo(int64(2000))) - Expect(result["Expansion rate"]).To(BeEquivalentTo(int64(3))) + Expect(result).To(BeAssignableToTypeOf(redis.BFInfo{})) + Expect(result.Capacity).To(BeEquivalentTo(int64(2000))) + Expect(result.ExpansionRate).To(BeEquivalentTo(int64(3))) }) It("should BFReserveArgs", Label("bloom", "bfreserveargs"), func() { @@ -156,46 +164,48 @@ var _ = Describe("Probabilistic commands", Label("probabilistic"), func() { result, err := client.BFInfo(ctx, "testbf").Result() Expect(err).NotTo(HaveOccurred()) - Expect(result).To(BeAssignableToTypeOf(map[string]int64{})) - Expect(result["Capacity"]).To(BeEquivalentTo(int64(2000))) - Expect(result["Expansion rate"]).To(BeEquivalentTo(int64(3))) + Expect(result).To(BeAssignableToTypeOf(redis.BFInfo{})) + Expect(result.Capacity).To(BeEquivalentTo(int64(2000))) + Expect(result.ExpansionRate).To(BeEquivalentTo(int64(3))) }) }) Describe("cuckoo", Label("cuckoo"), func() { It("should CFAdd", Label("cuckoo", "cfadd"), func() { - err := client.CFAdd(ctx, "testcf1", "item1").Err() + add, err := client.CFAdd(ctx, "testcf1", "item1").Result() Expect(err).NotTo(HaveOccurred()) + Expect(add).To(BeTrue()) exists, err := client.CFExists(ctx, "testcf1", "item1").Result() Expect(err).NotTo(HaveOccurred()) - Expect(exists).To(BeEquivalentTo(int64(1))) + Expect(exists).To(BeTrue()) info, err := client.CFInfo(ctx, "testcf1").Result() Expect(err).NotTo(HaveOccurred()) - Expect(info).To(BeAssignableToTypeOf(map[string]int64{})) - Expect(info["Number of items inserted"]).To(BeEquivalentTo(int64(1))) + Expect(info).To(BeAssignableToTypeOf(redis.CFInfo{})) + Expect(info.NumItemsInserted).To(BeEquivalentTo(int64(1))) }) It("should CFAddNX", Label("cuckoo", "cfaddnx"), func() { - err := client.CFAddNX(ctx, "testcf1", "item1").Err() + add, err := client.CFAddNX(ctx, "testcf1", "item1").Result() Expect(err).NotTo(HaveOccurred()) + Expect(add).To(BeTrue()) exists, err := client.CFExists(ctx, "testcf1", "item1").Result() Expect(err).NotTo(HaveOccurred()) - Expect(exists).To(BeEquivalentTo(int64(1))) + Expect(exists).To(BeTrue()) result, err := client.CFAddNX(ctx, "testcf1", "item1").Result() Expect(err).NotTo(HaveOccurred()) - Expect(result).To(BeEquivalentTo(int64(0))) + Expect(result).To(BeFalse()) info, err := client.CFInfo(ctx, "testcf1").Result() Expect(err).NotTo(HaveOccurred()) - Expect(info).To(BeAssignableToTypeOf(map[string]int64{})) - Expect(info["Number of items inserted"]).To(BeEquivalentTo(int64(1))) + Expect(info).To(BeAssignableToTypeOf(redis.CFInfo{})) + Expect(info.NumItemsInserted).To(BeEquivalentTo(int64(1))) }) - It("should CFInCFCountsert", Label("cuckoo", "cfinsert"), func() { + It("should CFCount", Label("cuckoo", "cfcount"), func() { err := client.CFAdd(ctx, "testcf1", "item1").Err() cnt, err := client.CFCount(ctx, "testcf1", "item1").Result() Expect(err).NotTo(HaveOccurred()) @@ -215,14 +225,15 @@ var _ = Describe("Probabilistic commands", Label("probabilistic"), func() { exists, err := client.CFExists(ctx, "testcf1", "item1").Result() Expect(err).NotTo(HaveOccurred()) - Expect(exists).To(BeEquivalentTo(int64(1))) + Expect(exists).To(BeTrue()) - err = client.CFDel(ctx, "testcf1", "item1").Err() + del, err := client.CFDel(ctx, "testcf1", "item1").Result() Expect(err).NotTo(HaveOccurred()) + Expect(del).To(BeTrue()) exists, err = client.CFExists(ctx, "testcf1", "item1").Result() Expect(err).NotTo(HaveOccurred()) - Expect(exists).To(BeEquivalentTo(int64(0))) + Expect(exists).To(BeFalse()) }) It("should CFInfo and CFReserve", Label("cuckoo", "cfinfo", "cfreserve"), func() { @@ -231,7 +242,7 @@ var _ = Describe("Probabilistic commands", Label("probabilistic"), func() { result, err := client.CFInfo(ctx, "testcf1").Result() Expect(err).NotTo(HaveOccurred()) - Expect(result).To(BeAssignableToTypeOf(map[string]int64{})) + Expect(result).To(BeAssignableToTypeOf(redis.CFInfo{})) }) It("should CFInfo and CFReserveArgs", Label("cuckoo", "cfinfo", "cfreserveargs"), func() { @@ -247,10 +258,10 @@ var _ = Describe("Probabilistic commands", Label("probabilistic"), func() { result, err := client.CFInfo(ctx, "testcf1").Result() Expect(err).NotTo(HaveOccurred()) - Expect(result).To(BeAssignableToTypeOf(map[string]int64{})) - Expect(result["Bucket size"]).To(BeEquivalentTo(int64(3))) - Expect(result["Max iterations"]).To(BeEquivalentTo(int64(15))) - Expect(result["Expansion rate"]).To(BeEquivalentTo(int64(2))) + Expect(result).To(BeAssignableToTypeOf(redis.CFInfo{})) + Expect(result.BucketSize).To(BeEquivalentTo(int64(3))) + Expect(result.MaxIteration).To(BeEquivalentTo(int64(15))) + Expect(result.ExpansionRate).To(BeEquivalentTo(int64(2))) }) It("should CFInsert", Label("cuckoo", "cfinsert"), func() { @@ -301,10 +312,10 @@ var _ = Describe("Probabilistic commands", Label("probabilistic"), func() { result, err := client.CFMExists(ctx, "testcf1", "item1", "item2", "item3", "item4").Result() Expect(err).NotTo(HaveOccurred()) Expect(len(result)).To(BeEquivalentTo(4)) - Expect(result[0]).To(BeEquivalentTo(int64(1))) - Expect(result[1]).To(BeEquivalentTo(int64(1))) - Expect(result[2]).To(BeEquivalentTo(int64(1))) - Expect(result[3]).To(BeEquivalentTo(int64(0))) + Expect(result[0]).To(BeTrue()) + Expect(result[1]).To(BeTrue()) + Expect(result[2]).To(BeTrue()) + Expect(result[3]).To(BeFalse()) }) }) @@ -330,13 +341,9 @@ var _ = Describe("Probabilistic commands", Label("probabilistic"), func() { info, err := client.CMSInfo(ctx, "testcms1").Result() Expect(err).NotTo(HaveOccurred()) - fmt.Println() - fmt.Println() - fmt.Println(info) - - Expect(info).To(BeAssignableToTypeOf(map[string]int64{})) - Expect(info["width"]).To(BeEquivalentTo(int64(5))) - Expect(info["depth"]).To(BeEquivalentTo(int64(10))) + Expect(info).To(BeAssignableToTypeOf(redis.CMSInfo{})) + Expect(info.Width).To(BeEquivalentTo(int64(5))) + Expect(info.Depth).To(BeEquivalentTo(int64(10))) }) It("should CMSInitByProb", Label("cms", "cmsinitbyprob"), func() { @@ -345,7 +352,7 @@ var _ = Describe("Probabilistic commands", Label("probabilistic"), func() { info, err := client.CMSInfo(ctx, "testcms1").Result() Expect(err).NotTo(HaveOccurred()) - Expect(info).To(BeAssignableToTypeOf(map[string]int64{})) + Expect(info).To(BeAssignableToTypeOf(redis.CMSInfo{})) }) It("should CMSMerge, CMSMergeWithWeight and CMSQuery", Label("cms", "cmsmerge", "cmsquery"), func() { From 118f85d1a36c73f808483df21d6ae286f2472e14 Mon Sep 17 00:00:00 2001 From: Elena Kolevska Date: Mon, 17 Jul 2023 20:59:26 +0100 Subject: [PATCH 08/15] Adds tidigest commands (tdigest.merge missing) --- probabilistic.go | 436 +++++++++++++++++++++++++++++++++++------- probabilistic_test.go | 122 ++++++++++++ 2 files changed, 486 insertions(+), 72 deletions(-) diff --git a/probabilistic.go b/probabilistic.go index da3c3fd37..52fbcf427 100644 --- a/probabilistic.go +++ b/probabilistic.go @@ -7,46 +7,64 @@ import ( ) type ProbabilisticCmdble interface { - BFAdd(ctx context.Context, key, item interface{}) *IntCmd + BFAdd(ctx context.Context, key, element interface{}) *IntCmd BFCard(ctx context.Context, key string) *IntCmd - BFExists(ctx context.Context, key, item interface{}) *IntCmd + BFExists(ctx context.Context, key, element interface{}) *IntCmd BFInfo(ctx context.Context, key string) *BFInfoCmd BFInfoArg(ctx context.Context, key string, option BFInfo) *BFInfoCmd - BFInsert(ctx context.Context, key string, options *BFReserveOptions, items ...interface{}) *IntSliceCmd - BFMAdd(ctx context.Context, key string, items ...interface{}) *IntSliceCmd - BFMExists(ctx context.Context, key string, items ...interface{}) *IntSliceCmd + BFInsert(ctx context.Context, key string, options *BFReserveOptions, elements ...interface{}) *IntSliceCmd + BFMAdd(ctx context.Context, key string, elements ...interface{}) *IntSliceCmd + BFMExists(ctx context.Context, key string, elements ...interface{}) *IntSliceCmd BFReserve(ctx context.Context, key string, errorRate float64, capacity int64) *StatusCmd BFReserveExpansion(ctx context.Context, key string, errorRate float64, capacity, expansion int64) *StatusCmd BFReserveNonScaling(ctx context.Context, key string, errorRate float64, capacity int64) *StatusCmd BFReserveArgs(ctx context.Context, key string, options *BFReserveOptions) *StatusCmd - //TODO Loadchunk and scandump missing + //TODO LoadChunk and ScanDump missing - CFAdd(ctx context.Context, key, item interface{}) *IntCmd - CFAddNX(ctx context.Context, key, item interface{}) *IntCmd - CFCount(ctx context.Context, key, item interface{}) *IntCmd + CFAdd(ctx context.Context, key, element interface{}) *IntCmd + CFAddNX(ctx context.Context, key, element interface{}) *IntCmd + CFCount(ctx context.Context, key, element interface{}) *IntCmd CFDel(ctx context.Context, key string) *IntCmd - CFExists(ctx context.Context, key, item interface{}) *IntCmd + CFExists(ctx context.Context, key, element interface{}) *IntCmd CFInfo(ctx context.Context, key string) *CFInfoCmd + CFInsert(ctx context.Context, key string, options *CFInsertOptions, elements ...interface{}) *IntSliceCmd + CFInsertNx(ctx context.Context, key string, options *CFInsertOptions, elements ...interface{}) *IntSliceCmd + CFMExists(ctx context.Context, key string, elements ...interface{}) *IntSliceCmd CFReserve(ctx context.Context, key string, capacity int64) *StatusCmd - CFInsert(ctx context.Context, key string, options *CFInsertOptions, items ...interface{}) *IntSliceCmd - CFInsertNx(ctx context.Context, key string, options *CFInsertOptions, items ...interface{}) *IntSliceCmd - CFMExists(ctx context.Context, key string, items ...interface{}) *IntSliceCmd + //TODO LoadChunk and ScanDump missing - CMSIncrBy(ctx context.Context, key string, items ...interface{}) *IntSliceCmd + CMSIncrBy(ctx context.Context, key string, elements ...interface{}) *IntSliceCmd CMSInfo(ctx context.Context, key string) *CMSInfoCmd CMSInitByDim(ctx context.Context, key string, width, height int64) *StatusCmd CMSInitByProb(ctx context.Context, key string, errorRate, probability float64) *StatusCmd CMSMerge(ctx context.Context, destKey string, sourceKeys ...string) *StatusCmd CMSMergeWithWeight(ctx context.Context, destKey string, sourceKeys map[string]int) *StatusCmd - CMSQuery(ctx context.Context, key string, items ...interface{}) *IntSliceCmd + CMSQuery(ctx context.Context, key string, elements ...interface{}) *IntSliceCmd - TOPKAdd(ctx context.Context, key string, items ...interface{}) *StringSliceCmd + TOPKAdd(ctx context.Context, key string, elements ...interface{}) *StringSliceCmd + TOPKCount(ctx context.Context, key string, elements ...interface{}) *IntSliceCmd + TOPKIncrBy(ctx context.Context, key string, elements ...interface{}) *StringSliceCmd + TOPKInfo(ctx context.Context, key string) *TOPKInfoCmd + TOPKList(ctx context.Context, key string) *StringSliceCmd + TOPKListWithCount(ctx context.Context, key string) *MapStringIntCmd + TOPKQuery(ctx context.Context, key string, elements ...interface{}) *BoolSliceCmd TOPKReserve(ctx context.Context, key string, k int) *StatusCmd TOPKReserveWithOptions(ctx context.Context, key string, k int, width, depth int64, decay float64) *StatusCmd - TOPKInfo(ctx context.Context, key string) *TOPKInfoCmd - TOPKQuery(ctx context.Context, key string, items ...interface{}) *BoolSliceCmd - TOPKCount(ctx context.Context, key string, items ...interface{}) *IntSliceCmd - TOPKIncrBy(ctx context.Context, key string, items ...interface{}) *StringSliceCmd + + TDigestAdd(ctx context.Context, key string, elements ...float64) *StatusCmd + TDigestByRank(ctx context.Context, key string, rank ...uint) *FloatSliceCmd + TDigestByRevRank(ctx context.Context, key string, rank ...uint) *FloatSliceCmd + TDigestCDF(ctx context.Context, key string, elements ...float64) *FloatSliceCmd + TDigestCreate(ctx context.Context, key string) *StatusCmd + TDigestCreateWithCompression(ctx context.Context, key string, compression int) *StatusCmd + TDigestInfo(ctx context.Context, key string) *TDigestInfoCmd + TDigestMax(ctx context.Context, key string) *FloatCmd + TDigestMin(ctx context.Context, key string) *FloatCmd + TDigestQuantile(ctx context.Context, key string, elements ...float64) *FloatSliceCmd + TDigestRank(ctx context.Context, key string, values ...float64) *IntSliceCmd + TDigestReset(ctx context.Context, key string) *StatusCmd + TDigestRevRank(ctx context.Context, key string, values ...float64) *IntSliceCmd + TDigestTrimmedMean(ctx context.Context, key string, lowCutQuantile, highCutQuantile float64) *FloatCmd } type BFReserveOptions struct { @@ -87,7 +105,7 @@ func (b BFInfoArgs) String() string { case BFFILTERS: return "filters" case BFITEMS: - return "items" + return "elements" case BFEXPANSION: return "expansion" } @@ -140,8 +158,8 @@ func (c cmdable) BFReserveArgs(ctx context.Context, key string, options *BFReser return cmd } -func (c cmdable) BFAdd(ctx context.Context, key, item interface{}) *BoolCmd { - args := []interface{}{"bf.add", key, item} +func (c cmdable) BFAdd(ctx context.Context, key, element interface{}) *BoolCmd { + args := []interface{}{"bf.add", key, element} cmd := NewBoolCmd(ctx, args...) _ = c(ctx, cmd) return cmd @@ -154,8 +172,8 @@ func (c cmdable) BFCard(ctx context.Context, key string) *IntCmd { return cmd } -func (c cmdable) BFExists(ctx context.Context, key, item string) *BoolCmd { - args := []interface{}{"bf.exists", key, item} +func (c cmdable) BFExists(ctx context.Context, key, element string) *BoolCmd { + args := []interface{}{"bf.exists", key, element} cmd := NewBoolCmd(ctx, args...) _ = c(ctx, cmd) return cmd @@ -228,7 +246,7 @@ func (cmd *BFInfoCmd) readReply(rd *proto.Reader) (err error) { result.Size, err = rd.ReadInt() case "Number of filters": result.NumFilters, err = rd.ReadInt() - case "Number of items inserted": + case "Number of elements inserted": result.NumItemsInserted, err = rd.ReadInt() case "Expansion rate": result.ExpansionRate, err = rd.ReadInt() @@ -252,7 +270,7 @@ func (c cmdable) BFInfoArg(ctx context.Context, key string, option BFInfoArgs) * return cmd } -func (c cmdable) BFInsert(ctx context.Context, key string, options *BFReserveOptions, items ...string) *BoolSliceCmd { +func (c cmdable) BFInsert(ctx context.Context, key string, options *BFReserveOptions, elements ...string) *BoolSliceCmd { args := []interface{}{"bf.insert", key} if options != nil { if options.Error != 0 { @@ -268,8 +286,8 @@ func (c cmdable) BFInsert(ctx context.Context, key string, options *BFReserveOpt args = append(args, "nonscaling") } } - args = append(args, "items") - for _, s := range items { + args = append(args, "elements") + for _, s := range elements { args = append(args, s) } @@ -278,9 +296,9 @@ func (c cmdable) BFInsert(ctx context.Context, key string, options *BFReserveOpt return cmd } -func (c cmdable) BFMAdd(ctx context.Context, key string, items ...string) *BoolSliceCmd { +func (c cmdable) BFMAdd(ctx context.Context, key string, elements ...string) *BoolSliceCmd { args := []interface{}{"bf.madd", key} - for _, s := range items { + for _, s := range elements { args = append(args, s) } cmd := NewBoolSliceCmd(ctx, args...) @@ -288,9 +306,9 @@ func (c cmdable) BFMAdd(ctx context.Context, key string, items ...string) *BoolS return cmd } -func (c cmdable) BFMExists(ctx context.Context, key string, items ...string) *BoolSliceCmd { +func (c cmdable) BFMExists(ctx context.Context, key string, elements ...string) *BoolSliceCmd { args := []interface{}{"bf.mexists", key} - for _, s := range items { + for _, s := range elements { args = append(args, s) } cmd := NewBoolSliceCmd(ctx, args...) @@ -325,36 +343,36 @@ func (c cmdable) CFReserveArgs(ctx context.Context, key string, options *CFReser return cmd } -func (c cmdable) CFAdd(ctx context.Context, key, item string) *BoolCmd { - args := []interface{}{"cf.add", key, item} +func (c cmdable) CFAdd(ctx context.Context, key, element string) *BoolCmd { + args := []interface{}{"cf.add", key, element} cmd := NewBoolCmd(ctx, args...) _ = c(ctx, cmd) return cmd } -func (c cmdable) CFAddNX(ctx context.Context, key, item string) *BoolCmd { - args := []interface{}{"cf.addnx", key, item} +func (c cmdable) CFAddNX(ctx context.Context, key, element string) *BoolCmd { + args := []interface{}{"cf.addnx", key, element} cmd := NewBoolCmd(ctx, args...) _ = c(ctx, cmd) return cmd } -func (c cmdable) CFCount(ctx context.Context, key, item string) *IntCmd { - args := []interface{}{"cf.count", key, item} +func (c cmdable) CFCount(ctx context.Context, key, element string) *IntCmd { + args := []interface{}{"cf.count", key, element} cmd := NewIntCmd(ctx, args...) _ = c(ctx, cmd) return cmd } -func (c cmdable) CFDel(ctx context.Context, key string, item string) *BoolCmd { - args := []interface{}{"cf.del", key, item} +func (c cmdable) CFDel(ctx context.Context, key string, element string) *BoolCmd { + args := []interface{}{"cf.del", key, element} cmd := NewBoolCmd(ctx, args...) _ = c(ctx, cmd) return cmd } -func (c cmdable) CFExists(ctx context.Context, key, item string) *BoolCmd { - args := []interface{}{"cf.exists", key, item} +func (c cmdable) CFExists(ctx context.Context, key, element string) *BoolCmd { + args := []interface{}{"cf.exists", key, element} cmd := NewBoolCmd(ctx, args...) _ = c(ctx, cmd) return cmd @@ -423,9 +441,9 @@ func (cmd *CFInfoCmd) readReply(rd *proto.Reader) (err error) { result.NumBuckets, err = rd.ReadInt() case "Number of filters": result.NumFilters, err = rd.ReadInt() - case "Number of items inserted": + case "Number of elements inserted": result.NumItemsInserted, err = rd.ReadInt() - case "Number of items deleted": + case "Number of elements deleted": result.NumItemsDeleted, err = rd.ReadInt() case "Bucket size": result.BucketSize, err = rd.ReadInt() @@ -454,25 +472,25 @@ func (c cmdable) CFInfo(ctx context.Context, key string) *CFInfoCmd { return cmd } -func (c cmdable) CFInsert(ctx context.Context, key string, options *CFInsertOptions, items ...string) *BoolSliceCmd { +func (c cmdable) CFInsert(ctx context.Context, key string, options *CFInsertOptions, elements ...string) *BoolSliceCmd { args := []interface{}{"cf.insert", key} - args = c.getCfInsertArgs(args, options, items...) + args = c.getCfInsertArgs(args, options, elements...) cmd := NewBoolSliceCmd(ctx, args...) _ = c(ctx, cmd) return cmd } -func (c cmdable) CFInsertNx(ctx context.Context, key string, options *CFInsertOptions, items ...string) *IntSliceCmd { +func (c cmdable) CFInsertNx(ctx context.Context, key string, options *CFInsertOptions, elements ...string) *IntSliceCmd { args := []interface{}{"cf.insertnx", key} - args = c.getCfInsertArgs(args, options, items...) + args = c.getCfInsertArgs(args, options, elements...) cmd := NewIntSliceCmd(ctx, args...) _ = c(ctx, cmd) return cmd } -func (c cmdable) getCfInsertArgs(args []interface{}, options *CFInsertOptions, items ...string) []interface{} { +func (c cmdable) getCfInsertArgs(args []interface{}, options *CFInsertOptions, elements ...string) []interface{} { if options != nil { if options.Capacity != 0 { args = append(args, "capacity", options.Capacity) @@ -481,16 +499,16 @@ func (c cmdable) getCfInsertArgs(args []interface{}, options *CFInsertOptions, i args = append(args, "nocreate") } } - args = append(args, "items") - for _, s := range items { + args = append(args, "elements") + for _, s := range elements { args = append(args, s) } return args } -func (c cmdable) CFMExists(ctx context.Context, key string, items ...string) *BoolSliceCmd { +func (c cmdable) CFMExists(ctx context.Context, key string, elements ...string) *BoolSliceCmd { args := []interface{}{"cf.mexists", key} - for _, s := range items { + for _, s := range elements { args = append(args, s) } cmd := NewBoolSliceCmd(ctx, args...) @@ -502,11 +520,11 @@ func (c cmdable) CFMExists(ctx context.Context, key string, items ...string) *Bo // CMS commands //------------------------------------------- -func (c cmdable) CMSIncrBy(ctx context.Context, key string, items ...interface{}) *IntSliceCmd { - args := make([]interface{}, 2, 2+len(items)) +func (c cmdable) CMSIncrBy(ctx context.Context, key string, elements ...interface{}) *IntSliceCmd { + args := make([]interface{}, 2, 2+len(elements)) args[0] = "cms.incrby" args[1] = key - args = appendArgs(args, items) + args = appendArgs(args, elements) cmd := NewIntSliceCmd(ctx, args...) _ = c(ctx, cmd) @@ -640,9 +658,9 @@ func (c cmdable) CMSMergeWithWeight(ctx context.Context, destKey string, sourceK return cmd } -func (c cmdable) CMSQuery(ctx context.Context, key string, items ...interface{}) *IntSliceCmd { +func (c cmdable) CMSQuery(ctx context.Context, key string, elements ...interface{}) *IntSliceCmd { args := []interface{}{"cms.query", key} - for _, s := range items { + for _, s := range elements { args = append(args, s) } cmd := NewIntSliceCmd(ctx, args...) @@ -652,13 +670,13 @@ func (c cmdable) CMSQuery(ctx context.Context, key string, items ...interface{}) // ------------------------------------------- // TOPK commands -//------------------------------------------- +//-------------------------------------------- -func (c cmdable) TOPKAdd(ctx context.Context, key string, items ...interface{}) *StringSliceCmd { - args := make([]interface{}, 2, 2+len(items)) +func (c cmdable) TOPKAdd(ctx context.Context, key string, elements ...interface{}) *StringSliceCmd { + args := make([]interface{}, 2, 2+len(elements)) args[0] = "topk.add" args[1] = key - args = appendArgs(args, items) + args = appendArgs(args, elements) cmd := NewStringSliceCmd(ctx, args...) _ = c(ctx, cmd) @@ -765,33 +783,33 @@ func (c cmdable) TOPKInfo(ctx context.Context, key string) *TOPKInfoCmd { return cmd } -func (c cmdable) TOPKQuery(ctx context.Context, key string, items ...interface{}) *BoolSliceCmd { - args := make([]interface{}, 2, 2+len(items)) +func (c cmdable) TOPKQuery(ctx context.Context, key string, elements ...interface{}) *BoolSliceCmd { + args := make([]interface{}, 2, 2+len(elements)) args[0] = "topk.query" args[1] = key - args = appendArgs(args, items) + args = appendArgs(args, elements) cmd := NewBoolSliceCmd(ctx, args...) _ = c(ctx, cmd) return cmd } -func (c cmdable) TOPKCount(ctx context.Context, key string, items ...interface{}) *IntSliceCmd { - args := make([]interface{}, 2, 2+len(items)) +func (c cmdable) TOPKCount(ctx context.Context, key string, elements ...interface{}) *IntSliceCmd { + args := make([]interface{}, 2, 2+len(elements)) args[0] = "topk.count" args[1] = key - args = appendArgs(args, items) + args = appendArgs(args, elements) cmd := NewIntSliceCmd(ctx, args...) _ = c(ctx, cmd) return cmd } -func (c cmdable) TOPKIncrBy(ctx context.Context, key string, items ...interface{}) *StringSliceCmd { - args := make([]interface{}, 2, 2+len(items)) +func (c cmdable) TOPKIncrBy(ctx context.Context, key string, elements ...interface{}) *StringSliceCmd { + args := make([]interface{}, 2, 2+len(elements)) args[0] = "topk.incrby" args[1] = key - args = appendArgs(args, items) + args = appendArgs(args, elements) cmd := NewStringSliceCmd(ctx, args...) _ = c(ctx, cmd) @@ -813,3 +831,277 @@ func (c cmdable) TOPKListWithCount(ctx context.Context, key string) *MapStringIn _ = c(ctx, cmd) return cmd } + +// ------------------------------------------- +// t-digest commands +// -------------------------------------------- + +func (c cmdable) TDigestAdd(ctx context.Context, key string, elements ...float64) *StatusCmd { + args := make([]interface{}, 2, 2+len(elements)) + args[0] = "tdigest.add" + args[1] = key + + // Convert floatSlice to []interface{} + interfaceSlice := make([]interface{}, len(elements)) + for i, v := range elements { + interfaceSlice[i] = v + } + + args = append(args, interfaceSlice...) + + cmd := NewStatusCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) TDigestByRank(ctx context.Context, key string, rank ...uint) *FloatSliceCmd { + args := make([]interface{}, 2, 2+len(rank)) + args[0] = "tdigest.byrank" + args[1] = key + + // Convert uint slice to []interface{} + interfaceSlice := make([]interface{}, len(rank)) + for i, v := range rank { + interfaceSlice[i] = v + } + + args = append(args, interfaceSlice...) + + cmd := NewFloatSliceCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) TDigestByRevRank(ctx context.Context, key string, rank ...uint) *FloatSliceCmd { + args := make([]interface{}, 2, 2+len(rank)) + args[0] = "tdigest.byrevrank" + args[1] = key + + // Convert uint slice to []interface{} + interfaceSlice := make([]interface{}, len(rank)) + for i, v := range rank { + interfaceSlice[i] = v + } + + args = append(args, interfaceSlice...) + + cmd := NewFloatSliceCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) TDigestCDF(ctx context.Context, key string, elements ...float64) *FloatSliceCmd { + args := make([]interface{}, 2, 2+len(elements)) + args[0] = "tdigest.cdf" + args[1] = key + + // Convert floatSlice to []interface{} + interfaceSlice := make([]interface{}, len(elements)) + for i, v := range elements { + interfaceSlice[i] = v + } + + args = append(args, interfaceSlice...) + + cmd := NewFloatSliceCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) TDigestCreate(ctx context.Context, key string) *StatusCmd { + args := []interface{}{"tdigest.create", key} + + cmd := NewStatusCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) TDigestCreateWithCompression(ctx context.Context, key string, compression int) *StatusCmd { + args := []interface{}{"tdigest.create", key, "compression", compression} + + cmd := NewStatusCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +type TDigestInfo struct { + Compression int64 + Capacity int64 + MergedNodes int64 + UnmergedNodes int64 + MergedWeight int64 + UnmergedWeight int64 + Observations int64 + TotalCompressions int64 + MemoryUsage int64 +} + +type TDigestInfoCmd struct { + baseCmd + + val TDigestInfo +} + +func NewTDigestInfoCmd(ctx context.Context, args ...interface{}) *TDigestInfoCmd { + return &TDigestInfoCmd{ + baseCmd: baseCmd{ + ctx: ctx, + args: args, + }, + } +} + +func (cmd *TDigestInfoCmd) SetVal(val TDigestInfo) { + cmd.val = val +} + +func (cmd *TDigestInfoCmd) String() string { + return cmdString(cmd, cmd.val) +} + +func (cmd *TDigestInfoCmd) Val() TDigestInfo { + return cmd.val +} + +func (cmd *TDigestInfoCmd) Result() (TDigestInfo, error) { + return cmd.val, cmd.err +} + +func (cmd *TDigestInfoCmd) readReply(rd *proto.Reader) (err error) { + n, err := rd.ReadMapLen() + if err != nil { + return err + } + + var key string + var result TDigestInfo + for f := 0; f < n; f++ { + key, err = rd.ReadString() + if err != nil { + return err + } + + switch key { + case "Compression": + result.Compression, err = rd.ReadInt() + case "Capacity": + result.Capacity, err = rd.ReadInt() + case "Merged nodes": + result.MergedNodes, err = rd.ReadInt() + case "Unmerged nodes": + result.UnmergedNodes, err = rd.ReadInt() + case "Merged weight": + result.MergedWeight, err = rd.ReadInt() + case "Unmerged weight": + result.UnmergedWeight, err = rd.ReadInt() + case "Observations": + result.Observations, err = rd.ReadInt() + case "Total compressions": + result.TotalCompressions, err = rd.ReadInt() + case "Memory usage": + result.MemoryUsage, err = rd.ReadInt() + default: + return fmt.Errorf("redis: tdigest.info unexpected key %s", key) + } + + if err != nil { + return err + } + } + + cmd.val = result + return nil +} + +func (c cmdable) TDigestInfo(ctx context.Context, key string) *TDigestInfoCmd { + args := []interface{}{"tdigest.info", key} + + cmd := NewTDigestInfoCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) TDigestMax(ctx context.Context, key string) *FloatCmd { + args := []interface{}{"tdigest.max", key} + + cmd := NewFloatCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) TDigestMin(ctx context.Context, key string) *FloatCmd { + args := []interface{}{"tdigest.min", key} + + cmd := NewFloatCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) TDigestQuantile(ctx context.Context, key string, elements ...float64) *FloatSliceCmd { + args := make([]interface{}, 2, 2+len(elements)) + args[0] = "tdigest.quantile" + args[1] = key + + // Convert floatSlice to []interface{} + interfaceSlice := make([]interface{}, len(elements)) + for i, v := range elements { + interfaceSlice[i] = v + } + + args = append(args, interfaceSlice...) + + cmd := NewFloatSliceCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} +func (c cmdable) TDigestRank(ctx context.Context, key string, values ...float64) *IntSliceCmd { + args := make([]interface{}, 2, 2+len(values)) + args[0] = "tdigest.rank" + args[1] = key + + // Convert floatSlice to []interface{} + interfaceSlice := make([]interface{}, len(values)) + for i, v := range values { + interfaceSlice[i] = v + } + + args = append(args, interfaceSlice...) + + cmd := NewIntSliceCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) TDigestReset(ctx context.Context, key string) *StatusCmd { + args := []interface{}{"tdigest.reset", key} + + cmd := NewStatusCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) TDigestRevRank(ctx context.Context, key string, values ...float64) *IntSliceCmd { + args := make([]interface{}, 2, 2+len(values)) + args[0] = "tdigest.revrank" + args[1] = key + + // Convert floatSlice to []interface{} + interfaceSlice := make([]interface{}, len(values)) + for i, v := range values { + interfaceSlice[i] = v + } + + args = append(args, interfaceSlice...) + + cmd := NewIntSliceCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) TDigestTrimmedMean(ctx context.Context, key string, lowCutQuantile, highCutQuantile float64) *FloatCmd { + args := []interface{}{"tdigest.trimmed_mean", key, lowCutQuantile, highCutQuantile} + + cmd := NewFloatCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} diff --git a/probabilistic_test.go b/probabilistic_test.go index 6a661ab05..448328249 100644 --- a/probabilistic_test.go +++ b/probabilistic_test.go @@ -5,6 +5,7 @@ import ( . "github.com/bsm/ginkgo/v2" . "github.com/bsm/gomega" "github.com/redis/go-redis/v9" + "math" ) var _ = Describe("Probabilistic commands", Label("probabilistic"), func() { @@ -476,4 +477,125 @@ var _ = Describe("Probabilistic commands", Label("probabilistic"), func() { }) }) + + Describe("t-digest", Label("tdigest"), func() { + It("should TDigestCreate, TDigestAdd, TDigestQuantile, TDigestCDF, TDigestMerge, TDigestInfo", Label("tdigest", "tdigestcreate", "tdigestadd", "tdigestquantile", "tdigestcdf", "tdigestmerge", "tdigestinfo"), func() { + err := client.TDigestCreate(ctx, "tdigest1").Err() + Expect(err).NotTo(HaveOccurred()) + + info, err := client.TDigestInfo(ctx, "tdigest1").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(info.Observations).To(BeEquivalentTo(int64(0))) + + // Test with empty sketch + byRank, err := client.TDigestByRank(ctx, "tdigest1", 0, 1, 2, 3).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(len(byRank)).To(BeEquivalentTo(4)) + + byRevRank, err := client.TDigestByRevRank(ctx, "tdigest1", 0, 1, 2).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(len(byRevRank)).To(BeEquivalentTo(3)) + + cdf, err := client.TDigestCDF(ctx, "tdigest1", 15, 35, 70).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(len(cdf)).To(BeEquivalentTo(3)) + + max, err := client.TDigestMax(ctx, "tdigest1").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(math.IsNaN(max)).To(BeTrue()) + + min, err := client.TDigestMin(ctx, "tdigest1").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(math.IsNaN(min)).To(BeTrue()) + + quantile, err := client.TDigestQuantile(ctx, "tdigest1", 0.1, 0.2).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(len(quantile)).To(BeEquivalentTo(2)) + + rank, err := client.TDigestRank(ctx, "tdigest1", 10, 20).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(len(rank)).To(BeEquivalentTo(2)) + + revRank, err := client.TDigestRevRank(ctx, "tdigest1", 10, 20).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(len(revRank)).To(BeEquivalentTo(2)) + + trimmedMean, err := client.TDigestTrimmedMean(ctx, "tdigest1", 0.1, 0.6).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(math.IsNaN(trimmedMean)).To(BeTrue()) + + // Add elements + err = client.TDigestAdd(ctx, "tdigest1", 10, 20, 30, 40, 50, 60, 70, 80, 90, 100).Err() + Expect(err).NotTo(HaveOccurred()) + + info, err = client.TDigestInfo(ctx, "tdigest1").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(info.Observations).To(BeEquivalentTo(int64(10))) + + byRank, err = client.TDigestByRank(ctx, "tdigest1", 0, 1, 2).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(len(byRank)).To(BeEquivalentTo(3)) + Expect(byRank[0]).To(BeEquivalentTo(float64(10))) + Expect(byRank[1]).To(BeEquivalentTo(float64(20))) + Expect(byRank[2]).To(BeEquivalentTo(float64(30))) + + byRevRank, err = client.TDigestByRevRank(ctx, "tdigest1", 0, 1, 2).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(len(byRevRank)).To(BeEquivalentTo(3)) + Expect(byRevRank[0]).To(BeEquivalentTo(float64(100))) + Expect(byRevRank[1]).To(BeEquivalentTo(float64(90))) + Expect(byRevRank[2]).To(BeEquivalentTo(float64(80))) + + cdf, err = client.TDigestCDF(ctx, "tdigest1", 15, 35, 70).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(len(cdf)).To(BeEquivalentTo(3)) + Expect(cdf[0]).To(BeEquivalentTo(float64(0.1))) + Expect(cdf[1]).To(BeEquivalentTo(float64(0.3))) + Expect(cdf[2]).To(BeEquivalentTo(float64(0.65))) + + max, err = client.TDigestMax(ctx, "tdigest1").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(max).To(BeEquivalentTo(float64(100))) + + min, err = client.TDigestMin(ctx, "tdigest1").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(min).To(BeEquivalentTo(float64(10))) + + quantile, err = client.TDigestQuantile(ctx, "tdigest1", 0.1, 0.2).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(len(quantile)).To(BeEquivalentTo(2)) + Expect(quantile[0]).To(BeEquivalentTo(float64(20))) + Expect(quantile[1]).To(BeEquivalentTo(float64(30))) + + rank, err = client.TDigestRank(ctx, "tdigest1", 10, 20).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(len(rank)).To(BeEquivalentTo(2)) + Expect(rank[0]).To(BeEquivalentTo(int64(0))) + Expect(rank[1]).To(BeEquivalentTo(int64(1))) + + revRank, err = client.TDigestRevRank(ctx, "tdigest1", 10, 20).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(len(revRank)).To(BeEquivalentTo(2)) + Expect(revRank[0]).To(BeEquivalentTo(int64(9))) + Expect(revRank[1]).To(BeEquivalentTo(int64(8))) + + trimmedMean, err = client.TDigestTrimmedMean(ctx, "tdigest1", 0.1, 0.6).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(trimmedMean).To(BeEquivalentTo(float64(40))) + + reset, err := client.TDigestReset(ctx, "tdigest1").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(reset).To(BeEquivalentTo("OK")) + + }) + + It("should TDigestCreateWithCompression", Label("tdigest", "tcreatewithcompression"), func() { + err := client.TDigestCreateWithCompression(ctx, "tdigest1", 2000).Err() + Expect(err).NotTo(HaveOccurred()) + + info, err := client.TDigestInfo(ctx, "tdigest1").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(info.Compression).To(BeEquivalentTo(int64(2000))) + }) + }) }) From 7e978e9c5ecfa6e9c8fd76a6dc903214106dc83e Mon Sep 17 00:00:00 2001 From: Elena Kolevska Date: Wed, 19 Jul 2023 15:18:16 +0100 Subject: [PATCH 09/15] Cleanup --- commands.go | 2 ++ probabilistic.go | 52 +++++++++++++++++++++---------------------- probabilistic_test.go | 2 +- 3 files changed, 29 insertions(+), 27 deletions(-) diff --git a/commands.go b/commands.go index 34f4d2c22..bf7966fb9 100644 --- a/commands.go +++ b/commands.go @@ -504,6 +504,8 @@ type Cmdable interface { ACLLogReset(ctx context.Context) *StatusCmd ModuleLoadex(ctx context.Context, conf *ModuleLoadexConfig) *StringCmd + + ProbabilisticCmdable } type StatefulCmdable interface { diff --git a/probabilistic.go b/probabilistic.go index 52fbcf427..1a4ba173b 100644 --- a/probabilistic.go +++ b/probabilistic.go @@ -6,30 +6,30 @@ import ( "github.com/redis/go-redis/v9/internal/proto" ) -type ProbabilisticCmdble interface { - BFAdd(ctx context.Context, key, element interface{}) *IntCmd +type ProbabilisticCmdable interface { + BFAdd(ctx context.Context, key, element interface{}) *BoolCmd BFCard(ctx context.Context, key string) *IntCmd - BFExists(ctx context.Context, key, element interface{}) *IntCmd + BFExists(ctx context.Context, key, element interface{}) *BoolCmd BFInfo(ctx context.Context, key string) *BFInfoCmd - BFInfoArg(ctx context.Context, key string, option BFInfo) *BFInfoCmd - BFInsert(ctx context.Context, key string, options *BFReserveOptions, elements ...interface{}) *IntSliceCmd - BFMAdd(ctx context.Context, key string, elements ...interface{}) *IntSliceCmd - BFMExists(ctx context.Context, key string, elements ...interface{}) *IntSliceCmd + BFInfoArg(ctx context.Context, key string, option BFInfoArgs) *BFInfoCmd + BFInsert(ctx context.Context, key string, options *BFReserveOptions, elements ...interface{}) *BoolSliceCmd + BFMAdd(ctx context.Context, key string, elements ...interface{}) *BoolSliceCmd + BFMExists(ctx context.Context, key string, elements ...interface{}) *BoolSliceCmd BFReserve(ctx context.Context, key string, errorRate float64, capacity int64) *StatusCmd BFReserveExpansion(ctx context.Context, key string, errorRate float64, capacity, expansion int64) *StatusCmd BFReserveNonScaling(ctx context.Context, key string, errorRate float64, capacity int64) *StatusCmd BFReserveArgs(ctx context.Context, key string, options *BFReserveOptions) *StatusCmd //TODO LoadChunk and ScanDump missing - CFAdd(ctx context.Context, key, element interface{}) *IntCmd - CFAddNX(ctx context.Context, key, element interface{}) *IntCmd + CFAdd(ctx context.Context, key, element interface{}) *BoolCmd + CFAddNX(ctx context.Context, key, element interface{}) *BoolCmd CFCount(ctx context.Context, key, element interface{}) *IntCmd - CFDel(ctx context.Context, key string) *IntCmd - CFExists(ctx context.Context, key, element interface{}) *IntCmd + CFDel(ctx context.Context, key string, element interface{}) *BoolCmd + CFExists(ctx context.Context, key, element interface{}) *BoolCmd CFInfo(ctx context.Context, key string) *CFInfoCmd - CFInsert(ctx context.Context, key string, options *CFInsertOptions, elements ...interface{}) *IntSliceCmd + CFInsert(ctx context.Context, key string, options *CFInsertOptions, elements ...interface{}) *BoolSliceCmd CFInsertNx(ctx context.Context, key string, options *CFInsertOptions, elements ...interface{}) *IntSliceCmd - CFMExists(ctx context.Context, key string, elements ...interface{}) *IntSliceCmd + CFMExists(ctx context.Context, key string, elements ...interface{}) *BoolSliceCmd CFReserve(ctx context.Context, key string, capacity int64) *StatusCmd //TODO LoadChunk and ScanDump missing @@ -172,7 +172,7 @@ func (c cmdable) BFCard(ctx context.Context, key string) *IntCmd { return cmd } -func (c cmdable) BFExists(ctx context.Context, key, element string) *BoolCmd { +func (c cmdable) BFExists(ctx context.Context, key, element interface{}) *BoolCmd { args := []interface{}{"bf.exists", key, element} cmd := NewBoolCmd(ctx, args...) _ = c(ctx, cmd) @@ -270,7 +270,7 @@ func (c cmdable) BFInfoArg(ctx context.Context, key string, option BFInfoArgs) * return cmd } -func (c cmdable) BFInsert(ctx context.Context, key string, options *BFReserveOptions, elements ...string) *BoolSliceCmd { +func (c cmdable) BFInsert(ctx context.Context, key string, options *BFReserveOptions, elements ...interface{}) *BoolSliceCmd { args := []interface{}{"bf.insert", key} if options != nil { if options.Error != 0 { @@ -296,7 +296,7 @@ func (c cmdable) BFInsert(ctx context.Context, key string, options *BFReserveOpt return cmd } -func (c cmdable) BFMAdd(ctx context.Context, key string, elements ...string) *BoolSliceCmd { +func (c cmdable) BFMAdd(ctx context.Context, key string, elements ...interface{}) *BoolSliceCmd { args := []interface{}{"bf.madd", key} for _, s := range elements { args = append(args, s) @@ -306,7 +306,7 @@ func (c cmdable) BFMAdd(ctx context.Context, key string, elements ...string) *Bo return cmd } -func (c cmdable) BFMExists(ctx context.Context, key string, elements ...string) *BoolSliceCmd { +func (c cmdable) BFMExists(ctx context.Context, key string, elements ...interface{}) *BoolSliceCmd { args := []interface{}{"bf.mexists", key} for _, s := range elements { args = append(args, s) @@ -343,35 +343,35 @@ func (c cmdable) CFReserveArgs(ctx context.Context, key string, options *CFReser return cmd } -func (c cmdable) CFAdd(ctx context.Context, key, element string) *BoolCmd { +func (c cmdable) CFAdd(ctx context.Context, key, element interface{}) *BoolCmd { args := []interface{}{"cf.add", key, element} cmd := NewBoolCmd(ctx, args...) _ = c(ctx, cmd) return cmd } -func (c cmdable) CFAddNX(ctx context.Context, key, element string) *BoolCmd { +func (c cmdable) CFAddNX(ctx context.Context, key, element interface{}) *BoolCmd { args := []interface{}{"cf.addnx", key, element} cmd := NewBoolCmd(ctx, args...) _ = c(ctx, cmd) return cmd } -func (c cmdable) CFCount(ctx context.Context, key, element string) *IntCmd { +func (c cmdable) CFCount(ctx context.Context, key, element interface{}) *IntCmd { args := []interface{}{"cf.count", key, element} cmd := NewIntCmd(ctx, args...) _ = c(ctx, cmd) return cmd } -func (c cmdable) CFDel(ctx context.Context, key string, element string) *BoolCmd { +func (c cmdable) CFDel(ctx context.Context, key string, element interface{}) *BoolCmd { args := []interface{}{"cf.del", key, element} cmd := NewBoolCmd(ctx, args...) _ = c(ctx, cmd) return cmd } -func (c cmdable) CFExists(ctx context.Context, key, element string) *BoolCmd { +func (c cmdable) CFExists(ctx context.Context, key, element interface{}) *BoolCmd { args := []interface{}{"cf.exists", key, element} cmd := NewBoolCmd(ctx, args...) _ = c(ctx, cmd) @@ -472,7 +472,7 @@ func (c cmdable) CFInfo(ctx context.Context, key string) *CFInfoCmd { return cmd } -func (c cmdable) CFInsert(ctx context.Context, key string, options *CFInsertOptions, elements ...string) *BoolSliceCmd { +func (c cmdable) CFInsert(ctx context.Context, key string, options *CFInsertOptions, elements ...interface{}) *BoolSliceCmd { args := []interface{}{"cf.insert", key} args = c.getCfInsertArgs(args, options, elements...) @@ -481,7 +481,7 @@ func (c cmdable) CFInsert(ctx context.Context, key string, options *CFInsertOpti return cmd } -func (c cmdable) CFInsertNx(ctx context.Context, key string, options *CFInsertOptions, elements ...string) *IntSliceCmd { +func (c cmdable) CFInsertNx(ctx context.Context, key string, options *CFInsertOptions, elements ...interface{}) *IntSliceCmd { args := []interface{}{"cf.insertnx", key} args = c.getCfInsertArgs(args, options, elements...) @@ -490,7 +490,7 @@ func (c cmdable) CFInsertNx(ctx context.Context, key string, options *CFInsertOp return cmd } -func (c cmdable) getCfInsertArgs(args []interface{}, options *CFInsertOptions, elements ...string) []interface{} { +func (c cmdable) getCfInsertArgs(args []interface{}, options *CFInsertOptions, elements ...interface{}) []interface{} { if options != nil { if options.Capacity != 0 { args = append(args, "capacity", options.Capacity) @@ -506,7 +506,7 @@ func (c cmdable) getCfInsertArgs(args []interface{}, options *CFInsertOptions, e return args } -func (c cmdable) CFMExists(ctx context.Context, key string, elements ...string) *BoolSliceCmd { +func (c cmdable) CFMExists(ctx context.Context, key string, elements ...interface{}) *BoolSliceCmd { args := []interface{}{"cf.mexists", key} for _, s := range elements { args = append(args, s) diff --git a/probabilistic_test.go b/probabilistic_test.go index 448328249..5bb4b58f8 100644 --- a/probabilistic_test.go +++ b/probabilistic_test.go @@ -8,7 +8,7 @@ import ( "math" ) -var _ = Describe("Probabilistic commands", Label("probabilistic"), func() { +var _ = FDescribe("Probabilistic commands", Label("probabilistic"), func() { ctx := context.TODO() var client *redis.Client From 303d1ef6c36a76868bf08d69d4f4b6341e6ce528 Mon Sep 17 00:00:00 2001 From: Elena Kolevska Date: Wed, 19 Jul 2023 16:10:35 +0100 Subject: [PATCH 10/15] More cleanups --- probabilistic.go | 35 ++++++++++++++++++++++------------- probabilistic_test.go | 42 ++++++++++++++++++++++++++++-------------- 2 files changed, 50 insertions(+), 27 deletions(-) diff --git a/probabilistic.go b/probabilistic.go index 1a4ba173b..65ccfb18d 100644 --- a/probabilistic.go +++ b/probabilistic.go @@ -12,7 +12,7 @@ type ProbabilisticCmdable interface { BFExists(ctx context.Context, key, element interface{}) *BoolCmd BFInfo(ctx context.Context, key string) *BFInfoCmd BFInfoArg(ctx context.Context, key string, option BFInfoArgs) *BFInfoCmd - BFInsert(ctx context.Context, key string, options *BFReserveOptions, elements ...interface{}) *BoolSliceCmd + BFInsert(ctx context.Context, key string, options *BFInsertOptions, elements ...interface{}) *BoolSliceCmd BFMAdd(ctx context.Context, key string, elements ...interface{}) *BoolSliceCmd BFMExists(ctx context.Context, key string, elements ...interface{}) *BoolSliceCmd BFReserve(ctx context.Context, key string, errorRate float64, capacity int64) *StatusCmd @@ -67,6 +67,14 @@ type ProbabilisticCmdable interface { TDigestTrimmedMean(ctx context.Context, key string, lowCutQuantile, highCutQuantile float64) *FloatCmd } +type BFInsertOptions struct { + Capacity int64 + Error float64 + Expansion int64 + NonScaling bool + NoCreate bool +} + type BFReserveOptions struct { Capacity int64 Error float64 @@ -246,7 +254,7 @@ func (cmd *BFInfoCmd) readReply(rd *proto.Reader) (err error) { result.Size, err = rd.ReadInt() case "Number of filters": result.NumFilters, err = rd.ReadInt() - case "Number of elements inserted": + case "Number of items inserted": result.NumItemsInserted, err = rd.ReadInt() case "Expansion rate": result.ExpansionRate, err = rd.ReadInt() @@ -270,26 +278,27 @@ func (c cmdable) BFInfoArg(ctx context.Context, key string, option BFInfoArgs) * return cmd } -func (c cmdable) BFInsert(ctx context.Context, key string, options *BFReserveOptions, elements ...interface{}) *BoolSliceCmd { +func (c cmdable) BFInsert(ctx context.Context, key string, options *BFInsertOptions, elements ...interface{}) *BoolSliceCmd { args := []interface{}{"bf.insert", key} if options != nil { - if options.Error != 0 { - args = append(args, "error", options.Error) - } if options.Capacity != 0 { args = append(args, "capacity", options.Capacity) } + if options.Error != 0 { + args = append(args, "error", options.Error) + } if options.Expansion != 0 { args = append(args, "expansion", options.Expansion) } + if options.NoCreate { + args = append(args, "nocreate") + } if options.NonScaling { args = append(args, "nonscaling") } } - args = append(args, "elements") - for _, s := range elements { - args = append(args, s) - } + args = append(args, "items") + args = append(args, elements...) cmd := NewBoolSliceCmd(ctx, args...) _ = c(ctx, cmd) @@ -441,9 +450,9 @@ func (cmd *CFInfoCmd) readReply(rd *proto.Reader) (err error) { result.NumBuckets, err = rd.ReadInt() case "Number of filters": result.NumFilters, err = rd.ReadInt() - case "Number of elements inserted": + case "Number of items inserted": result.NumItemsInserted, err = rd.ReadInt() - case "Number of elements deleted": + case "Number of items deleted": result.NumItemsDeleted, err = rd.ReadInt() case "Bucket size": result.BucketSize, err = rd.ReadInt() @@ -499,7 +508,7 @@ func (c cmdable) getCfInsertArgs(args []interface{}, options *CFInsertOptions, e args = append(args, "nocreate") } } - args = append(args, "elements") + args = append(args, "items") for _, s := range elements { args = append(args, s) } diff --git a/probabilistic_test.go b/probabilistic_test.go index 5bb4b58f8..68c639dcf 100644 --- a/probabilistic_test.go +++ b/probabilistic_test.go @@ -81,19 +81,33 @@ var _ = FDescribe("Probabilistic commands", Label("probabilistic"), func() { err := client.BFReserve(ctx, "testbf1", 0.001, 2000).Err() Expect(err).NotTo(HaveOccurred()) - result, err := client.BFInfoArg(ctx, "testbf1", redis.BFInfoArgs(redis.BFCAPACITY)).Result() + result, err := client.BFInfoArg(ctx, "testbf1", redis.BFCAPACITY).Result() Expect(err).NotTo(HaveOccurred()) Expect(result.Capacity).To(BeEquivalentTo(int64(2000))) }) It("should BFInsert", Label("bloom", "bfinsert"), func() { - options := &redis.BFReserveOptions{ + options := &redis.BFInsertOptions{ Capacity: 2000, Error: 0.001, Expansion: 3, NonScaling: false, + NoCreate: true, } + resultInsert, err := client.BFInsert(ctx, "testbf1", options, "item1").Result() + Expect(err).To(HaveOccurred()) + Expect(err).To(MatchError("ERR not found")) + + options = &redis.BFInsertOptions{ + Capacity: 2000, + Error: 0.001, + Expansion: 3, + NonScaling: false, + NoCreate: false, + } + + resultInsert, err = client.BFInsert(ctx, "testbf1", options, "item1").Result() Expect(err).NotTo(HaveOccurred()) Expect(len(resultInsert)).To(BeEquivalentTo(1)) @@ -124,7 +138,7 @@ var _ = FDescribe("Probabilistic commands", Label("probabilistic"), func() { It("should BFMExists", Label("bloom", "bfmexists"), func() { exist, err := client.BFMExists(ctx, "testbf1", "item1", "item2", "item3").Result() Expect(err).NotTo(HaveOccurred()) - Expect(len(exist)).To(Equal(int(3))) + Expect(len(exist)).To(Equal(3)) Expect(exist[0]).To(BeFalse()) Expect(exist[1]).To(BeFalse()) Expect(exist[2]).To(BeFalse()) @@ -135,7 +149,7 @@ var _ = FDescribe("Probabilistic commands", Label("probabilistic"), func() { exist, err = client.BFMExists(ctx, "testbf1", "item1", "item2", "item3", "item4").Result() Expect(err).NotTo(HaveOccurred()) - Expect(len(exist)).To(Equal(int(4))) + Expect(len(exist)).To(Equal(4)) Expect(exist[0]).To(BeTrue()) Expect(exist[1]).To(BeTrue()) Expect(exist[2]).To(BeTrue()) @@ -426,7 +440,7 @@ var _ = FDescribe("Probabilistic commands", Label("probabilistic"), func() { resultQuery, err := client.TOPKQuery(ctx, "topk1", "item1", "item2", 4, 3).Result() Expect(err).NotTo(HaveOccurred()) - Expect(len(resultQuery)).To(BeEquivalentTo(int(4))) + Expect(len(resultQuery)).To(BeEquivalentTo(4)) Expect(resultQuery[0]).To(BeTrue()) Expect(resultQuery[1]).To(BeTrue()) Expect(resultQuery[2]).To(BeFalse()) @@ -434,30 +448,30 @@ var _ = FDescribe("Probabilistic commands", Label("probabilistic"), func() { resultCount, err := client.TOPKCount(ctx, "topk1", "item1", "item2", "item3").Result() Expect(err).NotTo(HaveOccurred()) - Expect(len(resultCount)).To(BeEquivalentTo(int(3))) + Expect(len(resultCount)).To(BeEquivalentTo(3)) Expect(resultCount[0]).To(BeEquivalentTo(int64(2))) Expect(resultCount[1]).To(BeEquivalentTo(int64(1))) Expect(resultCount[2]).To(BeEquivalentTo(int64(0))) resultIncr, err := client.TOPKIncrBy(ctx, "topk1", "item1", 5, "item2", 10).Result() Expect(err).NotTo(HaveOccurred()) - Expect(len(resultIncr)).To(BeEquivalentTo(int(2))) + Expect(len(resultIncr)).To(BeEquivalentTo(2)) resultCount, err = client.TOPKCount(ctx, "topk1", "item1", "item2", "item3").Result() Expect(err).NotTo(HaveOccurred()) - Expect(len(resultCount)).To(BeEquivalentTo(int(3))) + Expect(len(resultCount)).To(BeEquivalentTo(3)) Expect(resultCount[0]).To(BeEquivalentTo(int64(7))) Expect(resultCount[1]).To(BeEquivalentTo(int64(11))) Expect(resultCount[2]).To(BeEquivalentTo(int64(0))) resultList, err := client.TOPKList(ctx, "topk1").Result() Expect(err).NotTo(HaveOccurred()) - Expect(len(resultList)).To(BeEquivalentTo(int(3))) + Expect(len(resultList)).To(BeEquivalentTo(3)) Expect(resultList).To(ContainElements("item2", "item1", "3")) resultListWithCount, err := client.TOPKListWithCount(ctx, "topk1").Result() Expect(err).NotTo(HaveOccurred()) - Expect(len(resultListWithCount)).To(BeEquivalentTo(int(3))) + Expect(len(resultListWithCount)).To(BeEquivalentTo(3)) Expect(resultListWithCount["3"]).To(BeEquivalentTo(int64(1))) Expect(resultListWithCount["item1"]).To(BeEquivalentTo(int64(7))) Expect(resultListWithCount["item2"]).To(BeEquivalentTo(int64(11))) @@ -473,7 +487,7 @@ var _ = FDescribe("Probabilistic commands", Label("probabilistic"), func() { Expect(resultInfo.K).To(BeEquivalentTo(int64(3))) Expect(resultInfo.Width).To(BeEquivalentTo(int64(1500))) Expect(resultInfo.Depth).To(BeEquivalentTo(int64(8))) - Expect(resultInfo.Decay).To(BeEquivalentTo(float64(0.5))) + Expect(resultInfo.Decay).To(BeEquivalentTo(0.5)) }) }) @@ -549,9 +563,9 @@ var _ = FDescribe("Probabilistic commands", Label("probabilistic"), func() { cdf, err = client.TDigestCDF(ctx, "tdigest1", 15, 35, 70).Result() Expect(err).NotTo(HaveOccurred()) Expect(len(cdf)).To(BeEquivalentTo(3)) - Expect(cdf[0]).To(BeEquivalentTo(float64(0.1))) - Expect(cdf[1]).To(BeEquivalentTo(float64(0.3))) - Expect(cdf[2]).To(BeEquivalentTo(float64(0.65))) + Expect(cdf[0]).To(BeEquivalentTo(0.1)) + Expect(cdf[1]).To(BeEquivalentTo(0.3)) + Expect(cdf[2]).To(BeEquivalentTo(0.65)) max, err = client.TDigestMax(ctx, "tdigest1").Result() Expect(err).NotTo(HaveOccurred()) From d600f838607844759bd9203fcf8859e0c17c91ba Mon Sep 17 00:00:00 2001 From: Elena Kolevska Date: Thu, 20 Jul 2023 11:18:40 +0100 Subject: [PATCH 11/15] Adds TDigestMerge --- probabilistic.go | 26 ++++++++++++++++++++++++++ probabilistic_test.go | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/probabilistic.go b/probabilistic.go index 65ccfb18d..f859b9315 100644 --- a/probabilistic.go +++ b/probabilistic.go @@ -1038,6 +1038,32 @@ func (c cmdable) TDigestMax(ctx context.Context, key string) *FloatCmd { return cmd } +type TDigestMergeOptions struct { + Compression int64 + Override bool +} + +func (c cmdable) TDigestMerge(ctx context.Context, destKey string, options *TDigestMergeOptions, sourceKeys ...string) *StatusCmd { + args := []interface{}{"tdigest.merge", destKey, len(sourceKeys)} + + for _, sourceKey := range sourceKeys { + args = append(args, sourceKey) + } + + if options != nil { + if options.Compression != 0 { + args = append(args, "COMPRESSION", options.Compression) + } + if options.Override { + args = append(args, "OVERRIDE") + } + } + + cmd := NewStatusCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + func (c cmdable) TDigestMin(ctx context.Context, key string) *FloatCmd { args := []interface{}{"tdigest.min", key} diff --git a/probabilistic_test.go b/probabilistic_test.go index 68c639dcf..2a3a55eb8 100644 --- a/probabilistic_test.go +++ b/probabilistic_test.go @@ -493,7 +493,7 @@ var _ = FDescribe("Probabilistic commands", Label("probabilistic"), func() { }) Describe("t-digest", Label("tdigest"), func() { - It("should TDigestCreate, TDigestAdd, TDigestQuantile, TDigestCDF, TDigestMerge, TDigestInfo", Label("tdigest", "tdigestcreate", "tdigestadd", "tdigestquantile", "tdigestcdf", "tdigestmerge", "tdigestinfo"), func() { + It("should TDigestAdd, TDigestCreate, TDigestInfo, TDigestByRank, TDigestByRevRank, TDigestCDF, TDigestMax, TDigestMin, TDigestQuantile, TDigestRank, TDigestRevRank, TDigestTrimmedMean, TDigestReset, ", Label("tdigest", "tdigestadd", "tdigestcreate", "tdigestinfo", "tdigestbyrank", "tdigestbyrevrank", "tdigestcdf", "tdigestmax", "tdigestmin", "tdigestquantile", "tdigestrank", "tdigestrevrank", "tdigesttrimmedmean", "tdigestreset"), func() { err := client.TDigestCreate(ctx, "tdigest1").Err() Expect(err).NotTo(HaveOccurred()) @@ -611,5 +611,38 @@ var _ = FDescribe("Probabilistic commands", Label("probabilistic"), func() { Expect(err).NotTo(HaveOccurred()) Expect(info.Compression).To(BeEquivalentTo(int64(2000))) }) + + FIt("should TDigestMerge", Label("tdigest", "tmerge"), func() { + err := client.TDigestCreate(ctx, "tdigest1").Err() + Expect(err).NotTo(HaveOccurred()) + err = client.TDigestAdd(ctx, "tdigest1", 10, 20, 30, 40, 50, 60, 70, 80, 90, 100).Err() + Expect(err).NotTo(HaveOccurred()) + + err = client.TDigestCreate(ctx, "tdigest2").Err() + Expect(err).NotTo(HaveOccurred()) + err = client.TDigestAdd(ctx, "tdigest2", 15, 25, 35, 45, 55, 65, 75, 85, 95, 105).Err() + Expect(err).NotTo(HaveOccurred()) + + err = client.TDigestCreate(ctx, "tdigest3").Err() + Expect(err).NotTo(HaveOccurred()) + err = client.TDigestAdd(ctx, "tdigest3", 50, 60, 70, 80, 90, 100, 110, 120, 130, 140).Err() + Expect(err).NotTo(HaveOccurred()) + + options := &redis.TDigestMergeOptions{ + Compression: 1000, + Override: false, + } + err = client.TDigestMerge(ctx, "tdigest1", options, "tdigest2", "tdigest3").Err() + Expect(err).NotTo(HaveOccurred()) + + info, err := client.TDigestInfo(ctx, "tdigest1").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(info.Observations).To(BeEquivalentTo(int64(30))) + Expect(info.Compression).To(BeEquivalentTo(int64(1000))) + + max, err := client.TDigestMax(ctx, "tdigest1").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(max).To(BeEquivalentTo(float64(140))) + }) }) }) From 15a9c8102164acc52dabbb3ec685f16f03178ecf Mon Sep 17 00:00:00 2001 From: Elena Kolevska Date: Fri, 21 Jul 2023 11:13:28 +0100 Subject: [PATCH 12/15] Applies fixes after review --- probabilistic.go | 106 ++++++++++++++++++++---------------------- probabilistic_test.go | 27 ++++++----- 2 files changed, 63 insertions(+), 70 deletions(-) diff --git a/probabilistic.go b/probabilistic.go index f859b9315..91990b948 100644 --- a/probabilistic.go +++ b/probabilistic.go @@ -6,10 +6,10 @@ import ( "github.com/redis/go-redis/v9/internal/proto" ) -type ProbabilisticCmdable interface { - BFAdd(ctx context.Context, key, element interface{}) *BoolCmd +type probabilisticCmdable interface { + BFAdd(ctx context.Context, key string, element interface{}) *BoolCmd BFCard(ctx context.Context, key string) *IntCmd - BFExists(ctx context.Context, key, element interface{}) *BoolCmd + BFExists(ctx context.Context, key string, element interface{}) *BoolCmd BFInfo(ctx context.Context, key string) *BFInfoCmd BFInfoArg(ctx context.Context, key string, option BFInfoArgs) *BFInfoCmd BFInsert(ctx context.Context, key string, options *BFInsertOptions, elements ...interface{}) *BoolSliceCmd @@ -21,11 +21,11 @@ type ProbabilisticCmdable interface { BFReserveArgs(ctx context.Context, key string, options *BFReserveOptions) *StatusCmd //TODO LoadChunk and ScanDump missing - CFAdd(ctx context.Context, key, element interface{}) *BoolCmd - CFAddNX(ctx context.Context, key, element interface{}) *BoolCmd - CFCount(ctx context.Context, key, element interface{}) *IntCmd + CFAdd(ctx context.Context, key string, element interface{}) *BoolCmd + CFAddNX(ctx context.Context, key string, element interface{}) *BoolCmd + CFCount(ctx context.Context, key string, element interface{}) *IntCmd CFDel(ctx context.Context, key string, element interface{}) *BoolCmd - CFExists(ctx context.Context, key, element interface{}) *BoolCmd + CFExists(ctx context.Context, key string, element interface{}) *BoolCmd CFInfo(ctx context.Context, key string) *CFInfoCmd CFInsert(ctx context.Context, key string, options *CFInsertOptions, elements ...interface{}) *BoolSliceCmd CFInsertNx(ctx context.Context, key string, options *CFInsertOptions, elements ...interface{}) *IntSliceCmd @@ -41,15 +41,15 @@ type ProbabilisticCmdable interface { CMSMergeWithWeight(ctx context.Context, destKey string, sourceKeys map[string]int) *StatusCmd CMSQuery(ctx context.Context, key string, elements ...interface{}) *IntSliceCmd - TOPKAdd(ctx context.Context, key string, elements ...interface{}) *StringSliceCmd - TOPKCount(ctx context.Context, key string, elements ...interface{}) *IntSliceCmd - TOPKIncrBy(ctx context.Context, key string, elements ...interface{}) *StringSliceCmd - TOPKInfo(ctx context.Context, key string) *TOPKInfoCmd - TOPKList(ctx context.Context, key string) *StringSliceCmd - TOPKListWithCount(ctx context.Context, key string) *MapStringIntCmd - TOPKQuery(ctx context.Context, key string, elements ...interface{}) *BoolSliceCmd - TOPKReserve(ctx context.Context, key string, k int) *StatusCmd - TOPKReserveWithOptions(ctx context.Context, key string, k int, width, depth int64, decay float64) *StatusCmd + TopKAdd(ctx context.Context, key string, elements ...interface{}) *StringSliceCmd + TopKCount(ctx context.Context, key string, elements ...interface{}) *IntSliceCmd + TopKIncrBy(ctx context.Context, key string, elements ...interface{}) *StringSliceCmd + TopKInfo(ctx context.Context, key string) *TopKInfoCmd + TopKList(ctx context.Context, key string) *StringSliceCmd + TopKListWithCount(ctx context.Context, key string) *MapStringIntCmd + TopKQuery(ctx context.Context, key string, elements ...interface{}) *BoolSliceCmd + TopKReserve(ctx context.Context, key string, k int) *StatusCmd + TopKReserveWithOptions(ctx context.Context, key string, k int, width, depth int64, decay float64) *StatusCmd TDigestAdd(ctx context.Context, key string, elements ...float64) *StatusCmd TDigestByRank(ctx context.Context, key string, rank ...uint) *FloatSliceCmd @@ -166,7 +166,7 @@ func (c cmdable) BFReserveArgs(ctx context.Context, key string, options *BFReser return cmd } -func (c cmdable) BFAdd(ctx context.Context, key, element interface{}) *BoolCmd { +func (c cmdable) BFAdd(ctx context.Context, key string, element interface{}) *BoolCmd { args := []interface{}{"bf.add", key, element} cmd := NewBoolCmd(ctx, args...) _ = c(ctx, cmd) @@ -180,7 +180,7 @@ func (c cmdable) BFCard(ctx context.Context, key string) *IntCmd { return cmd } -func (c cmdable) BFExists(ctx context.Context, key, element interface{}) *BoolCmd { +func (c cmdable) BFExists(ctx context.Context, key string, element interface{}) *BoolCmd { args := []interface{}{"bf.exists", key, element} cmd := NewBoolCmd(ctx, args...) _ = c(ctx, cmd) @@ -307,9 +307,7 @@ func (c cmdable) BFInsert(ctx context.Context, key string, options *BFInsertOpti func (c cmdable) BFMAdd(ctx context.Context, key string, elements ...interface{}) *BoolSliceCmd { args := []interface{}{"bf.madd", key} - for _, s := range elements { - args = append(args, s) - } + args = append(args, elements...) cmd := NewBoolSliceCmd(ctx, args...) _ = c(ctx, cmd) return cmd @@ -317,9 +315,8 @@ func (c cmdable) BFMAdd(ctx context.Context, key string, elements ...interface{} func (c cmdable) BFMExists(ctx context.Context, key string, elements ...interface{}) *BoolSliceCmd { args := []interface{}{"bf.mexists", key} - for _, s := range elements { - args = append(args, s) - } + args = append(args, elements...) + cmd := NewBoolSliceCmd(ctx, args...) _ = c(ctx, cmd) return cmd @@ -352,21 +349,21 @@ func (c cmdable) CFReserveArgs(ctx context.Context, key string, options *CFReser return cmd } -func (c cmdable) CFAdd(ctx context.Context, key, element interface{}) *BoolCmd { +func (c cmdable) CFAdd(ctx context.Context, key string, element interface{}) *BoolCmd { args := []interface{}{"cf.add", key, element} cmd := NewBoolCmd(ctx, args...) _ = c(ctx, cmd) return cmd } -func (c cmdable) CFAddNX(ctx context.Context, key, element interface{}) *BoolCmd { +func (c cmdable) CFAddNX(ctx context.Context, key string, element interface{}) *BoolCmd { args := []interface{}{"cf.addnx", key, element} cmd := NewBoolCmd(ctx, args...) _ = c(ctx, cmd) return cmd } -func (c cmdable) CFCount(ctx context.Context, key, element interface{}) *IntCmd { +func (c cmdable) CFCount(ctx context.Context, key string, element interface{}) *IntCmd { args := []interface{}{"cf.count", key, element} cmd := NewIntCmd(ctx, args...) _ = c(ctx, cmd) @@ -380,7 +377,7 @@ func (c cmdable) CFDel(ctx context.Context, key string, element interface{}) *Bo return cmd } -func (c cmdable) CFExists(ctx context.Context, key, element interface{}) *BoolCmd { +func (c cmdable) CFExists(ctx context.Context, key string, element interface{}) *BoolCmd { args := []interface{}{"cf.exists", key, element} cmd := NewBoolCmd(ctx, args...) _ = c(ctx, cmd) @@ -509,9 +506,8 @@ func (c cmdable) getCfInsertArgs(args []interface{}, options *CFInsertOptions, e } } args = append(args, "items") - for _, s := range elements { - args = append(args, s) - } + args = append(args, elements...) + return args } @@ -678,10 +674,10 @@ func (c cmdable) CMSQuery(ctx context.Context, key string, elements ...interface } // ------------------------------------------- -// TOPK commands +// TopK commands //-------------------------------------------- -func (c cmdable) TOPKAdd(ctx context.Context, key string, elements ...interface{}) *StringSliceCmd { +func (c cmdable) TopKAdd(ctx context.Context, key string, elements ...interface{}) *StringSliceCmd { args := make([]interface{}, 2, 2+len(elements)) args[0] = "topk.add" args[1] = key @@ -692,7 +688,7 @@ func (c cmdable) TOPKAdd(ctx context.Context, key string, elements ...interface{ return cmd } -func (c cmdable) TOPKReserve(ctx context.Context, key string, k int) *StatusCmd { +func (c cmdable) TopKReserve(ctx context.Context, key string, k int) *StatusCmd { args := []interface{}{"topk.reserve", key, k} cmd := NewStatusCmd(ctx, args...) @@ -700,7 +696,7 @@ func (c cmdable) TOPKReserve(ctx context.Context, key string, k int) *StatusCmd return cmd } -func (c cmdable) TOPKReserveWithOptions(ctx context.Context, key string, k int, width, depth int64, decay float64) *StatusCmd { +func (c cmdable) TopKReserveWithOptions(ctx context.Context, key string, k int, width, depth int64, decay float64) *StatusCmd { args := []interface{}{"topk.reserve", key, k, width, depth, decay} cmd := NewStatusCmd(ctx, args...) @@ -708,21 +704,21 @@ func (c cmdable) TOPKReserveWithOptions(ctx context.Context, key string, k int, return cmd } -type TOPKInfo struct { +type TopKInfo struct { K int64 Width int64 Depth int64 Decay float64 } -type TOPKInfoCmd struct { +type TopKInfoCmd struct { baseCmd - val TOPKInfo + val TopKInfo } -func NewTOPKInfoCmd(ctx context.Context, args ...interface{}) *TOPKInfoCmd { - return &TOPKInfoCmd{ +func NewTopKInfoCmd(ctx context.Context, args ...interface{}) *TopKInfoCmd { + return &TopKInfoCmd{ baseCmd: baseCmd{ ctx: ctx, args: args, @@ -730,30 +726,30 @@ func NewTOPKInfoCmd(ctx context.Context, args ...interface{}) *TOPKInfoCmd { } } -func (cmd *TOPKInfoCmd) SetVal(val TOPKInfo) { +func (cmd *TopKInfoCmd) SetVal(val TopKInfo) { cmd.val = val } -func (cmd *TOPKInfoCmd) String() string { +func (cmd *TopKInfoCmd) String() string { return cmdString(cmd, cmd.val) } -func (cmd *TOPKInfoCmd) Val() TOPKInfo { +func (cmd *TopKInfoCmd) Val() TopKInfo { return cmd.val } -func (cmd *TOPKInfoCmd) Result() (TOPKInfo, error) { +func (cmd *TopKInfoCmd) Result() (TopKInfo, error) { return cmd.val, cmd.err } -func (cmd *TOPKInfoCmd) readReply(rd *proto.Reader) (err error) { +func (cmd *TopKInfoCmd) readReply(rd *proto.Reader) (err error) { n, err := rd.ReadMapLen() if err != nil { return err } var key string - var result TOPKInfo + var result TopKInfo for f := 0; f < n; f++ { key, err = rd.ReadString() if err != nil { @@ -782,17 +778,15 @@ func (cmd *TOPKInfoCmd) readReply(rd *proto.Reader) (err error) { return nil } -func (c cmdable) TOPKInfo(ctx context.Context, key string) *TOPKInfoCmd { - args := make([]interface{}, 2, 2) - args[0] = "topk.info" - args[1] = key +func (c cmdable) TopKInfo(ctx context.Context, key string) *TopKInfoCmd { + args := []interface{}{"topk.info", key} - cmd := NewTOPKInfoCmd(ctx, args...) + cmd := NewTopKInfoCmd(ctx, args...) _ = c(ctx, cmd) return cmd } -func (c cmdable) TOPKQuery(ctx context.Context, key string, elements ...interface{}) *BoolSliceCmd { +func (c cmdable) TopKQuery(ctx context.Context, key string, elements ...interface{}) *BoolSliceCmd { args := make([]interface{}, 2, 2+len(elements)) args[0] = "topk.query" args[1] = key @@ -803,7 +797,7 @@ func (c cmdable) TOPKQuery(ctx context.Context, key string, elements ...interfac return cmd } -func (c cmdable) TOPKCount(ctx context.Context, key string, elements ...interface{}) *IntSliceCmd { +func (c cmdable) TopKCount(ctx context.Context, key string, elements ...interface{}) *IntSliceCmd { args := make([]interface{}, 2, 2+len(elements)) args[0] = "topk.count" args[1] = key @@ -814,7 +808,7 @@ func (c cmdable) TOPKCount(ctx context.Context, key string, elements ...interfac return cmd } -func (c cmdable) TOPKIncrBy(ctx context.Context, key string, elements ...interface{}) *StringSliceCmd { +func (c cmdable) TopKIncrBy(ctx context.Context, key string, elements ...interface{}) *StringSliceCmd { args := make([]interface{}, 2, 2+len(elements)) args[0] = "topk.incrby" args[1] = key @@ -825,7 +819,7 @@ func (c cmdable) TOPKIncrBy(ctx context.Context, key string, elements ...interfa return cmd } -func (c cmdable) TOPKList(ctx context.Context, key string) *StringSliceCmd { +func (c cmdable) TopKList(ctx context.Context, key string) *StringSliceCmd { args := []interface{}{"topk.list", key} cmd := NewStringSliceCmd(ctx, args...) @@ -833,7 +827,7 @@ func (c cmdable) TOPKList(ctx context.Context, key string) *StringSliceCmd { return cmd } -func (c cmdable) TOPKListWithCount(ctx context.Context, key string) *MapStringIntCmd { +func (c cmdable) TopKListWithCount(ctx context.Context, key string) *MapStringIntCmd { args := []interface{}{"topk.list", key, "withcount"} cmd := NewMapStringIntCmd(ctx, args...) diff --git a/probabilistic_test.go b/probabilistic_test.go index 2a3a55eb8..0e1639041 100644 --- a/probabilistic_test.go +++ b/probabilistic_test.go @@ -426,19 +426,19 @@ var _ = FDescribe("Probabilistic commands", Label("probabilistic"), func() { }) Describe("TopK", Label("topk"), func() { - It("should TopKReserve, TOPKInfo, TOPKAdd, TOPKQuery, TOPKCount, TOPKIncrBy, TOPKList, TOPKListWithCount", Label("topk", "topkreserve", "topkinfo", "topkadd", "topkquery", "topkcount", "topkincrby", "topklist", "topklistwithcount"), func() { - err := client.TOPKReserve(ctx, "topk1", 3).Err() + It("should TopKReserve, TopKInfo, TopKAdd, TopKQuery, TopKCount, TopKIncrBy, TopKList, TopKListWithCount", Label("topk", "topkreserve", "topkinfo", "topkadd", "topkquery", "topkcount", "topkincrby", "topklist", "topklistwithcount"), func() { + err := client.TopKReserve(ctx, "topk1", 3).Err() Expect(err).NotTo(HaveOccurred()) - resultInfo, err := client.TOPKInfo(ctx, "topk1").Result() + resultInfo, err := client.TopKInfo(ctx, "topk1").Result() Expect(err).NotTo(HaveOccurred()) Expect(resultInfo.K).To(BeEquivalentTo(int64(3))) - resultAdd, err := client.TOPKAdd(ctx, "topk1", "item1", "item2", 3, "item1").Result() + resultAdd, err := client.TopKAdd(ctx, "topk1", "item1", "item2", 3, "item1").Result() Expect(err).NotTo(HaveOccurred()) Expect(len(resultAdd)).To(BeEquivalentTo(int64(4))) - resultQuery, err := client.TOPKQuery(ctx, "topk1", "item1", "item2", 4, 3).Result() + resultQuery, err := client.TopKQuery(ctx, "topk1", "item1", "item2", 4, 3).Result() Expect(err).NotTo(HaveOccurred()) Expect(len(resultQuery)).To(BeEquivalentTo(4)) Expect(resultQuery[0]).To(BeTrue()) @@ -446,30 +446,30 @@ var _ = FDescribe("Probabilistic commands", Label("probabilistic"), func() { Expect(resultQuery[2]).To(BeFalse()) Expect(resultQuery[3]).To(BeTrue()) - resultCount, err := client.TOPKCount(ctx, "topk1", "item1", "item2", "item3").Result() + resultCount, err := client.TopKCount(ctx, "topk1", "item1", "item2", "item3").Result() Expect(err).NotTo(HaveOccurred()) Expect(len(resultCount)).To(BeEquivalentTo(3)) Expect(resultCount[0]).To(BeEquivalentTo(int64(2))) Expect(resultCount[1]).To(BeEquivalentTo(int64(1))) Expect(resultCount[2]).To(BeEquivalentTo(int64(0))) - resultIncr, err := client.TOPKIncrBy(ctx, "topk1", "item1", 5, "item2", 10).Result() + resultIncr, err := client.TopKIncrBy(ctx, "topk1", "item1", 5, "item2", 10).Result() Expect(err).NotTo(HaveOccurred()) Expect(len(resultIncr)).To(BeEquivalentTo(2)) - resultCount, err = client.TOPKCount(ctx, "topk1", "item1", "item2", "item3").Result() + resultCount, err = client.TopKCount(ctx, "topk1", "item1", "item2", "item3").Result() Expect(err).NotTo(HaveOccurred()) Expect(len(resultCount)).To(BeEquivalentTo(3)) Expect(resultCount[0]).To(BeEquivalentTo(int64(7))) Expect(resultCount[1]).To(BeEquivalentTo(int64(11))) Expect(resultCount[2]).To(BeEquivalentTo(int64(0))) - resultList, err := client.TOPKList(ctx, "topk1").Result() + resultList, err := client.TopKList(ctx, "topk1").Result() Expect(err).NotTo(HaveOccurred()) Expect(len(resultList)).To(BeEquivalentTo(3)) Expect(resultList).To(ContainElements("item2", "item1", "3")) - resultListWithCount, err := client.TOPKListWithCount(ctx, "topk1").Result() + resultListWithCount, err := client.TopKListWithCount(ctx, "topk1").Result() Expect(err).NotTo(HaveOccurred()) Expect(len(resultListWithCount)).To(BeEquivalentTo(3)) Expect(resultListWithCount["3"]).To(BeEquivalentTo(int64(1))) @@ -477,12 +477,11 @@ var _ = FDescribe("Probabilistic commands", Label("probabilistic"), func() { Expect(resultListWithCount["item2"]).To(BeEquivalentTo(int64(11))) }) - It("should TOPKReserveWithOptions", Label("topk", "topkreservewithoptions"), func() { - //&redis.TOPKReserveOptions{Width: 1500, Depth: 8, Decay: 0.5} - err := client.TOPKReserveWithOptions(ctx, "topk1", 3, 1500, 8, 0.5).Err() + It("should TopKReserveWithOptions", Label("topk", "topkreservewithoptions"), func() { + err := client.TopKReserveWithOptions(ctx, "topk1", 3, 1500, 8, 0.5).Err() Expect(err).NotTo(HaveOccurred()) - resultInfo, err := client.TOPKInfo(ctx, "topk1").Result() + resultInfo, err := client.TopKInfo(ctx, "topk1").Result() Expect(err).NotTo(HaveOccurred()) Expect(resultInfo.K).To(BeEquivalentTo(int64(3))) Expect(resultInfo.Width).To(BeEquivalentTo(int64(1500))) From 4ea0a06df86bd25fcbab2509b314e8fb7d5f1449 Mon Sep 17 00:00:00 2001 From: Elena Kolevska Date: Fri, 21 Jul 2023 12:11:39 +0100 Subject: [PATCH 13/15] Specifies number sizes --- probabilistic.go | 24 ++++++++++++------------ probabilistic_test.go | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/probabilistic.go b/probabilistic.go index 91990b948..5df9cbd26 100644 --- a/probabilistic.go +++ b/probabilistic.go @@ -38,7 +38,7 @@ type probabilisticCmdable interface { CMSInitByDim(ctx context.Context, key string, width, height int64) *StatusCmd CMSInitByProb(ctx context.Context, key string, errorRate, probability float64) *StatusCmd CMSMerge(ctx context.Context, destKey string, sourceKeys ...string) *StatusCmd - CMSMergeWithWeight(ctx context.Context, destKey string, sourceKeys map[string]int) *StatusCmd + CMSMergeWithWeight(ctx context.Context, destKey string, sourceKeys map[string]int64) *StatusCmd CMSQuery(ctx context.Context, key string, elements ...interface{}) *IntSliceCmd TopKAdd(ctx context.Context, key string, elements ...interface{}) *StringSliceCmd @@ -48,15 +48,15 @@ type probabilisticCmdable interface { TopKList(ctx context.Context, key string) *StringSliceCmd TopKListWithCount(ctx context.Context, key string) *MapStringIntCmd TopKQuery(ctx context.Context, key string, elements ...interface{}) *BoolSliceCmd - TopKReserve(ctx context.Context, key string, k int) *StatusCmd - TopKReserveWithOptions(ctx context.Context, key string, k int, width, depth int64, decay float64) *StatusCmd + TopKReserve(ctx context.Context, key string, k int64) *StatusCmd + TopKReserveWithOptions(ctx context.Context, key string, k int64, width, depth int64, decay float64) *StatusCmd TDigestAdd(ctx context.Context, key string, elements ...float64) *StatusCmd - TDigestByRank(ctx context.Context, key string, rank ...uint) *FloatSliceCmd - TDigestByRevRank(ctx context.Context, key string, rank ...uint) *FloatSliceCmd + TDigestByRank(ctx context.Context, key string, rank ...uint64) *FloatSliceCmd + TDigestByRevRank(ctx context.Context, key string, rank ...uint64) *FloatSliceCmd TDigestCDF(ctx context.Context, key string, elements ...float64) *FloatSliceCmd TDigestCreate(ctx context.Context, key string) *StatusCmd - TDigestCreateWithCompression(ctx context.Context, key string, compression int) *StatusCmd + TDigestCreateWithCompression(ctx context.Context, key string, compression int64) *StatusCmd TDigestInfo(ctx context.Context, key string) *TDigestInfoCmd TDigestMax(ctx context.Context, key string) *FloatCmd TDigestMin(ctx context.Context, key string) *FloatCmd @@ -638,7 +638,7 @@ func (c cmdable) CMSMerge(ctx context.Context, destKey string, sourceKeys ...str return cmd } -func (c cmdable) CMSMergeWithWeight(ctx context.Context, destKey string, sourceKeys map[string]int) *StatusCmd { +func (c cmdable) CMSMergeWithWeight(ctx context.Context, destKey string, sourceKeys map[string]int64) *StatusCmd { args := make([]interface{}, 0, 4+(len(sourceKeys)*2+1)) args = append(args, "cms.merge", destKey, len(sourceKeys)) @@ -688,7 +688,7 @@ func (c cmdable) TopKAdd(ctx context.Context, key string, elements ...interface{ return cmd } -func (c cmdable) TopKReserve(ctx context.Context, key string, k int) *StatusCmd { +func (c cmdable) TopKReserve(ctx context.Context, key string, k int64) *StatusCmd { args := []interface{}{"topk.reserve", key, k} cmd := NewStatusCmd(ctx, args...) @@ -696,7 +696,7 @@ func (c cmdable) TopKReserve(ctx context.Context, key string, k int) *StatusCmd return cmd } -func (c cmdable) TopKReserveWithOptions(ctx context.Context, key string, k int, width, depth int64, decay float64) *StatusCmd { +func (c cmdable) TopKReserveWithOptions(ctx context.Context, key string, k int64, width, depth int64, decay float64) *StatusCmd { args := []interface{}{"topk.reserve", key, k, width, depth, decay} cmd := NewStatusCmd(ctx, args...) @@ -857,7 +857,7 @@ func (c cmdable) TDigestAdd(ctx context.Context, key string, elements ...float64 return cmd } -func (c cmdable) TDigestByRank(ctx context.Context, key string, rank ...uint) *FloatSliceCmd { +func (c cmdable) TDigestByRank(ctx context.Context, key string, rank ...uint64) *FloatSliceCmd { args := make([]interface{}, 2, 2+len(rank)) args[0] = "tdigest.byrank" args[1] = key @@ -875,7 +875,7 @@ func (c cmdable) TDigestByRank(ctx context.Context, key string, rank ...uint) *F return cmd } -func (c cmdable) TDigestByRevRank(ctx context.Context, key string, rank ...uint) *FloatSliceCmd { +func (c cmdable) TDigestByRevRank(ctx context.Context, key string, rank ...uint64) *FloatSliceCmd { args := make([]interface{}, 2, 2+len(rank)) args[0] = "tdigest.byrevrank" args[1] = key @@ -919,7 +919,7 @@ func (c cmdable) TDigestCreate(ctx context.Context, key string) *StatusCmd { return cmd } -func (c cmdable) TDigestCreateWithCompression(ctx context.Context, key string, compression int) *StatusCmd { +func (c cmdable) TDigestCreateWithCompression(ctx context.Context, key string, compression int64) *StatusCmd { args := []interface{}{"tdigest.create", key, "compression", compression} cmd := NewStatusCmd(ctx, args...) diff --git a/probabilistic_test.go b/probabilistic_test.go index 0e1639041..f15250a57 100644 --- a/probabilistic_test.go +++ b/probabilistic_test.go @@ -407,7 +407,7 @@ var _ = FDescribe("Probabilistic commands", Label("probabilistic"), func() { Expect(result[1]).To(BeEquivalentTo(int64(4))) Expect(result[2]).To(BeEquivalentTo(int64(3))) - sourceSketches := map[string]int{ + sourceSketches := map[string]int64{ "cms1": 1, "cms2": 2, } From aa44fbc2073b9946278d827293783ca8deb9adb9 Mon Sep 17 00:00:00 2001 From: Elena Kolevska Date: Fri, 21 Jul 2023 12:12:33 +0100 Subject: [PATCH 14/15] Missed file in commit --- commands.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands.go b/commands.go index bf7966fb9..41f8d3ae3 100644 --- a/commands.go +++ b/commands.go @@ -505,7 +505,7 @@ type Cmdable interface { ModuleLoadex(ctx context.Context, conf *ModuleLoadexConfig) *StringCmd - ProbabilisticCmdable + probabilisticCmdable } type StatefulCmdable interface { From 43a58cd6527eaa25aa4ce1bf1f28dda995501e20 Mon Sep 17 00:00:00 2001 From: Elena Kolevska Date: Sat, 22 Jul 2023 13:57:11 +0100 Subject: [PATCH 15/15] Improves API for BFInfo with args --- probabilistic.go | 70 +++++++++++++++++++++---------------------- probabilistic_test.go | 31 +++++++++++++++---- 2 files changed, 59 insertions(+), 42 deletions(-) diff --git a/probabilistic.go b/probabilistic.go index 5df9cbd26..d84f67c08 100644 --- a/probabilistic.go +++ b/probabilistic.go @@ -11,7 +11,11 @@ type probabilisticCmdable interface { BFCard(ctx context.Context, key string) *IntCmd BFExists(ctx context.Context, key string, element interface{}) *BoolCmd BFInfo(ctx context.Context, key string) *BFInfoCmd - BFInfoArg(ctx context.Context, key string, option BFInfoArgs) *BFInfoCmd + BFInfoCapacity(ctx context.Context, key string) *BFInfoCmd + BFInfoSize(ctx context.Context, key string) *BFInfoCmd + BFInfoFilters(ctx context.Context, key string) *BFInfoCmd + BFInfoItems(ctx context.Context, key string) *BFInfoCmd + BFInfoExpansion(ctx context.Context, key string) *BFInfoCmd BFInsert(ctx context.Context, key string, options *BFInsertOptions, elements ...interface{}) *BoolSliceCmd BFMAdd(ctx context.Context, key string, elements ...interface{}) *BoolSliceCmd BFMExists(ctx context.Context, key string, elements ...interface{}) *BoolSliceCmd @@ -94,32 +98,6 @@ type CFInsertOptions struct { NoCreate bool } -type BFInfoArgs int - -const ( - BFCAPACITY BFInfoArgs = iota - BFSIZE - BFFILTERS - BFITEMS - BFEXPANSION -) - -func (b BFInfoArgs) String() string { - switch b { - case BFCAPACITY: - return "capacity" - case BFSIZE: - return "size" - case BFFILTERS: - return "filters" - case BFITEMS: - return "elements" - case BFEXPANSION: - return "expansion" - } - return "" -} - // ------------------------------------------- // Bloom filter commands //------------------------------------------- @@ -195,11 +173,11 @@ func (c cmdable) BFInfo(ctx context.Context, key string) *BFInfoCmd { } type BFInfo struct { - Capacity int64 - Size int64 - NumFilters int64 - NumItemsInserted int64 - ExpansionRate int64 + Capacity int64 + Size int64 + Filters int64 + ItemsInserted int64 + ExpansionRate int64 } type BFInfoCmd struct { @@ -253,9 +231,9 @@ func (cmd *BFInfoCmd) readReply(rd *proto.Reader) (err error) { case "Size": result.Size, err = rd.ReadInt() case "Number of filters": - result.NumFilters, err = rd.ReadInt() + result.Filters, err = rd.ReadInt() case "Number of items inserted": - result.NumItemsInserted, err = rd.ReadInt() + result.ItemsInserted, err = rd.ReadInt() case "Expansion rate": result.ExpansionRate, err = rd.ReadInt() default: @@ -271,8 +249,28 @@ func (cmd *BFInfoCmd) readReply(rd *proto.Reader) (err error) { return nil } -func (c cmdable) BFInfoArg(ctx context.Context, key string, option BFInfoArgs) *BFInfoCmd { - args := []interface{}{"bf.info", key, option.String()} +func (c cmdable) BFInfoCapacity(ctx context.Context, key string) *BFInfoCmd { + return c.bFInfoArg(ctx, key, "capacity") +} + +func (c cmdable) BFInfoSize(ctx context.Context, key string) *BFInfoCmd { + return c.bFInfoArg(ctx, key, "size") +} + +func (c cmdable) BFInfoFilters(ctx context.Context, key string) *BFInfoCmd { + return c.bFInfoArg(ctx, key, "filters") +} + +func (c cmdable) BFInfoItems(ctx context.Context, key string) *BFInfoCmd { + return c.bFInfoArg(ctx, key, "items") +} + +func (c cmdable) BFInfoExpansion(ctx context.Context, key string) *BFInfoCmd { + return c.bFInfoArg(ctx, key, "expansion") +} + +func (c cmdable) bFInfoArg(ctx context.Context, key, option string) *BFInfoCmd { + args := []interface{}{"bf.info", key, option} cmd := NewBFInfoCmd(ctx, args...) _ = c(ctx, cmd) return cmd diff --git a/probabilistic_test.go b/probabilistic_test.go index f15250a57..0a3b34d54 100644 --- a/probabilistic_test.go +++ b/probabilistic_test.go @@ -8,7 +8,7 @@ import ( "math" ) -var _ = FDescribe("Probabilistic commands", Label("probabilistic"), func() { +var _ = Describe("Probabilistic commands", Label("probabilistic"), func() { ctx := context.TODO() var client *redis.Client @@ -32,7 +32,7 @@ var _ = FDescribe("Probabilistic commands", Label("probabilistic"), func() { Expect(err).NotTo(HaveOccurred()) Expect(resultInfo).To(BeAssignableToTypeOf(redis.BFInfo{})) - Expect(resultInfo.NumItemsInserted).To(BeEquivalentTo(int64(1))) + Expect(resultInfo.ItemsInserted).To(BeEquivalentTo(int64(1))) }) It("should BFCard", Label("bloom", "bfcard"), func() { @@ -77,13 +77,32 @@ var _ = FDescribe("Probabilistic commands", Label("probabilistic"), func() { Expect(result.Capacity).To(BeEquivalentTo(int64(2000))) }) - It("should BFInfoArg", Label("bloom", "bfinfoarg"), func() { + It("should BFInfoCapacity, BFInfoSize, BFInfoFilters, BFInfoItems, BFInfoExpansion, ", Label("bloom", "bfinfocapacity", "bfinfosize", "bfinfofilters", "bfinfoitems", "bfinfoexpansion"), func() { err := client.BFReserve(ctx, "testbf1", 0.001, 2000).Err() Expect(err).NotTo(HaveOccurred()) - result, err := client.BFInfoArg(ctx, "testbf1", redis.BFCAPACITY).Result() + result, err := client.BFInfoCapacity(ctx, "testbf1").Result() Expect(err).NotTo(HaveOccurred()) Expect(result.Capacity).To(BeEquivalentTo(int64(2000))) + + result, err = client.BFInfoItems(ctx, "testbf1").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(result.ItemsInserted).To(BeEquivalentTo(int64(0))) + + result, err = client.BFInfoSize(ctx, "testbf1").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(result.Size).To(BeEquivalentTo(int64(4056))) + + err = client.BFReserveExpansion(ctx, "testbf2", 0.001, 2000, 3).Err() + Expect(err).NotTo(HaveOccurred()) + + result, err = client.BFInfoFilters(ctx, "testbf2").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(result.Filters).To(BeEquivalentTo(int64(1))) + + result, err = client.BFInfoExpansion(ctx, "testbf2").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(result.ExpansionRate).To(BeEquivalentTo(int64(3))) }) It("should BFInsert", Label("bloom", "bfinsert"), func() { @@ -132,7 +151,7 @@ var _ = FDescribe("Probabilistic commands", Label("probabilistic"), func() { Expect(err).NotTo(HaveOccurred()) Expect(resultInfo).To(BeAssignableToTypeOf(redis.BFInfo{})) - Expect(resultInfo.NumItemsInserted).To(BeEquivalentTo(int64(3))) + Expect(resultInfo.ItemsInserted).To(BeEquivalentTo(int64(3))) }) It("should BFMExists", Label("bloom", "bfmexists"), func() { @@ -611,7 +630,7 @@ var _ = FDescribe("Probabilistic commands", Label("probabilistic"), func() { Expect(info.Compression).To(BeEquivalentTo(int64(2000))) }) - FIt("should TDigestMerge", Label("tdigest", "tmerge"), func() { + It("should TDigestMerge", Label("tdigest", "tmerge"), func() { err := client.TDigestCreate(ctx, "tdigest1").Err() Expect(err).NotTo(HaveOccurred()) err = client.TDigestAdd(ctx, "tdigest1", 10, 20, 30, 40, 50, 60, 70, 80, 90, 100).Err()