From 2c2833c2b88b860122cb5953690409d04967e93e Mon Sep 17 00:00:00 2001 From: xh3b4sd Date: Wed, 27 Sep 2023 16:35:30 +0200 Subject: [PATCH] enable multi deletions with Sorted.Delete.Index --- pkg/conformance/client_single_sorted_test.go | 28 +++++++++++++++----- pkg/fake/sorted_delete.go | 2 +- pkg/sorted/delete.go | 18 +++++++------ pkg/sorted/interface.go | 8 +++--- 4 files changed, 36 insertions(+), 20 deletions(-) diff --git a/pkg/conformance/client_single_sorted_test.go b/pkg/conformance/client_single_sorted_test.go index a5f8f3e..d26c6a1 100644 --- a/pkg/conformance/client_single_sorted_test.go +++ b/pkg/conformance/client_single_sorted_test.go @@ -35,28 +35,42 @@ func Test_Client_Single_Sorted_Create_Order(t *testing.T) { } { - err := cli.Sorted().Create().Index("ssk", "foo", 0.8, "a", "b") + err = cli.Sorted().Create().Index("ssk", "foo", 0.8, "a", "b") if err != nil { t.Fatal(err) } - } - - { - err := cli.Sorted().Create().Index("ssk", "bar", 0.7, "c", "d") + err = cli.Sorted().Create().Index("ssk", "bar", 0.7, "c", "d") if err != nil { t.Fatal(err) } } { - err := cli.Sorted().Create().Index("ssk", "baz", 0.6, "c", "d") + err = cli.Sorted().Create().Index("ssk", "baz", 0.6, "a") + if !sorted.IsAlreadyExistsError(err) { + t.Fatal("expected", "alreadyExistsError", "got", err) + } + err = cli.Sorted().Create().Index("ssk", "baz", 0.6, "b", "z") + if !sorted.IsAlreadyExistsError(err) { + t.Fatal("expected", "alreadyExistsError", "got", err) + } + err = cli.Sorted().Create().Index("ssk", "baz", 0.6, "a", "b") + if !sorted.IsAlreadyExistsError(err) { + t.Fatal("expected", "alreadyExistsError", "got", err) + } + err = cli.Sorted().Create().Index("ssk", "baz", 0.6, "c", "d") + if !sorted.IsAlreadyExistsError(err) { + t.Fatal("expected", "alreadyExistsError", "got", err) + } + err = cli.Sorted().Create().Index("ssk", "baz", 0.7, "z") if !sorted.IsAlreadyExistsError(err) { t.Fatal("expected", "alreadyExistsError", "got", err) } } + // Ensure deleting multiple values with index mappings can be deleted at once. { - err := cli.Sorted().Delete().Index("ssk", "bar") + err := cli.Sorted().Delete().Index("ssk", "foo", "bar") if err != nil { t.Fatal(err) } diff --git a/pkg/fake/sorted_delete.go b/pkg/fake/sorted_delete.go index 49d677a..b14bed9 100644 --- a/pkg/fake/sorted_delete.go +++ b/pkg/fake/sorted_delete.go @@ -16,7 +16,7 @@ func (d *SortedDelete) Clean(key string) error { return nil } -func (d *SortedDelete) Index(key string, val string) error { +func (d *SortedDelete) Index(key string, val ...string) error { if d.FakeIndex != nil { return d.FakeIndex() } diff --git a/pkg/sorted/delete.go b/pkg/sorted/delete.go index 3171744..c69390b 100644 --- a/pkg/sorted/delete.go +++ b/pkg/sorted/delete.go @@ -15,7 +15,6 @@ const deleteCleanScript = ` return 0 ` -// TODO conformance tests for multiple deletions in one call const deleteIndexScript = ` for i = 1, #ARGV do local sco = redis.call("ZSCORE", KEYS[1], ARGV[i]) @@ -53,8 +52,8 @@ func (d *delete) Clean(key string) error { var arg []interface{} { - arg = append(arg, prefix.WithKeys(d.prefix, key)) - arg = append(arg, prefix.WithKeys(d.prefix, index.New(key))) + arg = append(arg, prefix.WithKeys(d.prefix, key)) // KEYS[1] + arg = append(arg, prefix.WithKeys(d.prefix, index.New(key))) // KEYS[2] } _, err := redis.Int(d.deleteCleanScript.Do(con, arg...)) @@ -65,7 +64,7 @@ func (d *delete) Clean(key string) error { return nil } -func (d *delete) Index(key string, val string) error { +func (d *delete) Index(key string, val ...string) error { con := d.pool.Get() defer con.Close() @@ -73,7 +72,10 @@ func (d *delete) Index(key string, val string) error { { arg = append(arg, prefix.WithKeys(d.prefix, key)) // KEYS[1] arg = append(arg, prefix.WithKeys(d.prefix, index.New(key))) // KEYS[2] - arg = append(arg, val) // ARGV[1] + + for _, x := range val { + arg = append(arg, x) + } } _, err := redis.Int(d.deleteIndexScript.Do(con, arg...)) @@ -116,9 +118,9 @@ func (d *delete) Score(key string, sco float64) error { var arg []interface{} { - arg = append(arg, prefix.WithKeys(d.prefix, key)) - arg = append(arg, prefix.WithKeys(d.prefix, index.New(key))) - arg = append(arg, sco) + arg = append(arg, prefix.WithKeys(d.prefix, key)) // KEYS[1] + arg = append(arg, prefix.WithKeys(d.prefix, index.New(key))) // KEYS[2] + arg = append(arg, sco) // ARGV[1] } _, err := redis.Int(d.deleteScoreScript.Do(con, arg...)) diff --git a/pkg/sorted/interface.go b/pkg/sorted/interface.go index 3e15171..38723df 100644 --- a/pkg/sorted/interface.go +++ b/pkg/sorted/interface.go @@ -29,10 +29,10 @@ type Delete interface { // Clean removes the sorted set under key including the derived indeizes. Clean(key string) error - // Index deletes the element identified by value within the specified sorted - // set. Note that indices associated with the underlying element are purged - // automatically as well. - Index(key string, val string) error + // Index deletes the elements identified by the given values within the + // specified sorted set. Note that indices associated with the underlying + // elements are purged automatically as well. + Index(key string, val ...string) error // Limit cuts off all older elements from the sorted set under key resulting // in a sorted set that contains the latest lim amount of elements. Consider