diff --git a/go/api/base_client.go b/go/api/base_client.go index 12ad2489aa..7d2eb58b90 100644 --- a/go/api/base_client.go +++ b/go/api/base_client.go @@ -7011,3 +7011,71 @@ func (client *baseClient) Time() ([]string, error) { } return handleStringArrayResponse(result) } + +// Returns the difference between the first sorted set and all the successive sorted sets.
+// To get the elements with their scores, see `ZDiffWithScores` +// When in cluster mode, all `keys` must map to the same hash slot. +// Valkey 6.2 and above. +// +// See [valkey.io] for details. +// +// Parameters: +// +// keys - The keys of the sorted sets. +// +// Return value: +// +// An array of elements representing the difference between the sorted sets. +// If the first `key` does not exist, it is treated as an empty sorted set, and the +// command returns an empty array. +// +// Example: +// +// zAddResult1, err := client.ZAdd(key1, membersScores1) +// zAddResult2, err := client.ZAdd(key2, membersScores2) +// zDiffResult, err := client.ZDiff([]string{key1, key2}) +// fmt.Println(zDiffResult) // Output: {"one", "three"} +// +// [valkey.io]: https://valkey.io/commands/zdiff/ +func (client *baseClient) ZDiff(keys []string) ([]string, error) { + args := append([]string{}, strconv.Itoa(len(keys))) + result, err := client.executeCommand(C.ZDiff, append(args, keys...)) + if err != nil { + return nil, err + } + return handleStringArrayResponse(result) +} + +// Returns the difference between the first sorted set and all the successive sorted sets. +// When in cluster mode, all `keys` must map to the same hash slot. +// Valkey 6.2 and above. +// +// See [valkey.io] for details. +// +// Parameters: +// +// keys - The keys of the sorted sets. +// +// Return value: +// +// A `Map` of elements and their scores representing the difference between the sorted sets. +// If the first `key` does not exist, it is treated as an empty sorted set, and the +// command returns an empty `Map`. +// +// Example: +// +// zAddResult1, err := client.ZAdd(key1, membersScores1) +// zAddResult2, err := client.ZAdd(key2, membersScores2) +// zDiffResultWithScores, err := client.ZDiffWithScores([]string{key1, key2}) +// fmt.Println(zDiffResultWithScores) // Output: {"one": 1.0, "three": 3.0} +// +// [valkey.io]: https://valkey.io/commands/zdiff/ +func (client *baseClient) ZDiffWithScores(keys []string) (map[string]float64, error) { + args := append([]string{}, strconv.Itoa(len(keys))) + args = append(args, keys...) + result, err := client.executeCommand(C.ZDiff, append(args, options.WithScores)) + if err != nil { + return nil, err + } + return handleStringDoubleMapResponse(result) +} diff --git a/go/api/options/constants.go b/go/api/options/constants.go index 45913c5b5c..156f367af6 100644 --- a/go/api/options/constants.go +++ b/go/api/options/constants.go @@ -9,6 +9,7 @@ const ( WithScore string = "WITHSCORE" // Valkey API keyword for the with score option for zrank and zrevrank commands. NoScores string = "NOSCORES" // Valkey API keyword for the no scores option for zscan command. WithValues string = "WITHVALUES" // Valkey API keyword to query hash values along their names in `HRANDFIELD`. + WithScores string = "WITHSCORES" // Valkey API keyword for the with scores option for zdiff command. ) type InfBoundary string diff --git a/go/api/sorted_set_commands.go b/go/api/sorted_set_commands.go index 4babb17c55..ca6924be62 100644 --- a/go/api/sorted_set_commands.go +++ b/go/api/sorted_set_commands.go @@ -70,4 +70,8 @@ type SortedSetCommands interface { ZRemRangeByRank(key string, start int64, stop int64) (int64, error) ZRemRangeByScore(key string, rangeQuery options.RangeByScore) (int64, error) + + ZDiff(keys []string) ([]string, error) + + ZDiffWithScores(keys []string) (map[string]float64, error) } diff --git a/go/integTest/shared_commands_test.go b/go/integTest/shared_commands_test.go index 9104f844eb..a77ef0e0e8 100644 --- a/go/integTest/shared_commands_test.go +++ b/go/integTest/shared_commands_test.go @@ -7694,3 +7694,73 @@ func (suite *GlideTestSuite) TestBitFieldRO_MultipleGets() { assert.Equal(suite.T(), []int64{value1, value2}, []int64{getRO[0].Value(), getRO[1].Value()}) }) } + +func (suite *GlideTestSuite) TestZDiff() { + suite.runWithDefaultClients(func(client api.BaseClient) { + suite.SkipIfServerVersionLowerThanBy("6.2.0") + t := suite.T() + key1 := "{testKey}:1-" + uuid.NewString() + key2 := "{testKey}:2-" + uuid.NewString() + key3 := "{testKey}:3-" + uuid.NewString() + nonExistentKey := "{testKey}:4-" + uuid.NewString() + + membersScores1 := map[string]float64{ + "one": 1.0, + "two": 2.0, + "three": 3.0, + } + + membersScores2 := map[string]float64{ + "two": 2.0, + } + + membersScores3 := map[string]float64{ + "one": 1.0, + "two": 2.0, + "three": 3.0, + "four": 4.0, + } + + zAddResult1, err := client.ZAdd(key1, membersScores1) + assert.NoError(t, err) + assert.Equal(t, int64(3), zAddResult1) + zAddResult2, err := client.ZAdd(key2, membersScores2) + assert.NoError(t, err) + assert.Equal(t, int64(1), zAddResult2) + zAddResult3, err := client.ZAdd(key3, membersScores3) + assert.NoError(t, err) + assert.Equal(t, int64(4), zAddResult3) + + zDiffResult, err := client.ZDiff([]string{key1, key2}) + assert.NoError(t, err) + assert.Equal(t, []string{"one", "three"}, zDiffResult) + zDiffResult, err = client.ZDiff([]string{key1, key3}) + assert.NoError(t, err) + assert.Equal(t, []string{}, zDiffResult) + zDiffResult, err = client.ZDiff([]string{nonExistentKey, key3}) + assert.NoError(t, err) + assert.Equal(t, []string{}, zDiffResult) + + zDiffResultWithScores, err := client.ZDiffWithScores([]string{key1, key2}) + assert.NoError(t, err) + assert.Equal(t, map[string]float64{"one": 1.0, "three": 3.0}, zDiffResultWithScores) + zDiffResultWithScores, err = client.ZDiffWithScores([]string{key1, key3}) + assert.NoError(t, err) + assert.Equal(t, map[string]float64{}, zDiffResultWithScores) + zDiffResultWithScores, err = client.ZDiffWithScores([]string{nonExistentKey, key3}) + assert.NoError(t, err) + assert.Equal(t, map[string]float64{}, zDiffResultWithScores) + + // Key exists, but it is not a set + setResult, err := client.Set(nonExistentKey, "bar") + assert.Equal(t, setResult, "OK") + + zDiffResult, err = client.ZDiff([]string{nonExistentKey, key2}) + assert.NotNil(t, err) + assert.IsType(t, &errors.RequestError{}, err) + + zDiffResultWithScores, err = client.ZDiffWithScores([]string{nonExistentKey, key2}) + assert.NotNil(t, err) + assert.IsType(t, &errors.RequestError{}, err) + }) +}