Skip to content

Commit

Permalink
Go: add command SInterStore (valkey-io#2779)
Browse files Browse the repository at this point in the history
* Go: add command SInterStore

Signed-off-by: TJ Zhang <[email protected]>
  • Loading branch information
tjzhang-BQ authored Dec 12, 2024
1 parent 636f0ee commit b347ef8
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#### Changes
* Java: bump `netty` version ([#2795](https://github.com/valkey-io/valkey-glide/pull/2795))
* Java: Bump protobuf (protoc) version ([#2796](https://github.com/valkey-io/valkey-glide/pull/2796), [#2800](https://github.com/valkey-io/valkey-glide/pull/2800))
* Go: Add `SInterStore` ([#2779](https://github.com/valkey-io/valkey-glide/issues/2779))

#### Breaking Changes

Expand Down
9 changes: 9 additions & 0 deletions go/api/base_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,15 @@ func (client *baseClient) SInter(keys []string) (map[Result[string]]struct{}, er
return handleStringSetResponse(result)
}

func (client *baseClient) SInterStore(destination string, keys []string) (Result[int64], error) {
result, err := client.executeCommand(C.SInterStore, append([]string{destination}, keys...))
if err != nil {
return CreateNilInt64Result(), err
}

return handleLongResponse(result)
}

func (client *baseClient) SInterCard(keys []string) (Result[int64], error) {
result, err := client.executeCommand(C.SInterCard, append([]string{strconv.Itoa(len(keys))}, keys...))
if err != nil {
Expand Down
23 changes: 23 additions & 0 deletions go/api/set_commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,29 @@ type SetCommands interface {
// [valkey.io]: https://valkey.io/commands/sinter/
SInter(keys []string) (map[Result[string]]struct{}, error)

// Stores the members of the intersection of all given sets specified by `keys` into a new set at `destination`
//
// Note: When in cluster mode, `destination` and all `keys` must map to the same hash slot.
//
// See [valkey.io] for details.
//
// Parameters:
// destination - The key of the destination set.
// keys - The keys from which to retrieve the set members.
//
// Return value:
// The number of elements in the resulting set.
//
// Example:
// result, err := client.SInterStore("my_set", []string{"set1", "set2"})
// if err != nil {
// fmt.Println(result)
// }
// // Output: 2 - Two elements were stored at "my_set", and those elements are the intersection of "set1" and "set2".
//
// [valkey.io]: https://valkey.io/commands/sinterstore/
SInterStore(destination string, keys []string) (Result[int64], error)

// SInterCard gets the cardinality of the intersection of all the given sets.
//
// Since:
Expand Down
95 changes: 95 additions & 0 deletions go/integTest/shared_commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1571,6 +1571,101 @@ func (suite *GlideTestSuite) TestSinter_WithNotExistingKeys() {
})
}

func (suite *GlideTestSuite) TestSinterStore() {
suite.runWithDefaultClients(func(client api.BaseClient) {
key1 := "{key}-1-" + uuid.NewString()
key2 := "{key}-2-" + uuid.NewString()
key3 := "{key}-3-" + uuid.NewString()
stringKey := "{key}-4-" + uuid.NewString()
nonExistingKey := "{key}-5-" + uuid.NewString()
memberArray1 := []string{"a", "b", "c"}
memberArray2 := []string{"c", "d", "e"}
t := suite.T()

res1, err := client.SAdd(key1, memberArray1)
assert.NoError(t, err)
assert.Equal(t, int64(3), res1.Value())

res2, err := client.SAdd(key2, memberArray2)
assert.NoError(t, err)
assert.Equal(t, int64(3), res2.Value())

// store in new key
res3, err := client.SInterStore(key3, []string{key1, key2})
assert.NoError(t, err)
assert.Equal(t, int64(1), res3.Value())

res4, err := client.SMembers(key3)
assert.NoError(t, err)
assert.Len(t, res4, 1)
for key := range res4 {
assert.Equal(t, key.Value(), "c")
}

// overwrite existing set, which is also a source set
res5, err := client.SInterStore(key2, []string{key1, key2})
assert.NoError(t, err)
assert.Equal(t, int64(1), res5.Value())

res6, err := client.SMembers(key2)
assert.NoError(t, err)
assert.Len(t, res6, 1)
for key := range res6 {
assert.Equal(t, key.Value(), "c")
}

// source set is the same as the existing set
res7, err := client.SInterStore(key1, []string{key2})
assert.NoError(t, err)
assert.Equal(t, int64(1), res7.Value())

res8, err := client.SMembers(key2)
assert.NoError(t, err)
assert.Len(t, res8, 1)
for key := range res8 {
assert.Equal(t, key.Value(), "c")
}

// intersection with non-existing key
res9, err := client.SInterStore(key1, []string{key2, nonExistingKey})
assert.NoError(t, err)
assert.Equal(t, int64(0), res9.Value())

// check that the key is now empty
members1, err := client.SMembers(key1)
assert.NoError(t, err)
assert.Empty(t, members1)

// invalid argument - key list must not be empty
res10, err := client.SInterStore(key3, []string{})
assert.Equal(suite.T(), int64(0), res10.Value())
assert.NotNil(suite.T(), err)
assert.IsType(suite.T(), &api.RequestError{}, err)

// non-set key
_, err = client.Set(stringKey, "value")
assert.NoError(t, err)

res11, err := client.SInterStore(key3, []string{stringKey})
assert.Equal(suite.T(), int64(0), res11.Value())
assert.NotNil(suite.T(), err)
assert.IsType(suite.T(), &api.RequestError{}, err)

// overwrite the non-set key
res12, err := client.SInterStore(stringKey, []string{key2})
assert.NoError(t, err)
assert.Equal(t, int64(1), res12.Value())

// check that the key is now empty
res13, err := client.SMembers(stringKey)
assert.NoError(t, err)
assert.Len(t, res13, 1)
for key := range res13 {
assert.Equal(t, key.Value(), "c")
}
})
}

func (suite *GlideTestSuite) TestSInterCard() {
suite.SkipIfServerVersionLowerThanBy("7.0.0")

Expand Down

0 comments on commit b347ef8

Please sign in to comment.