Skip to content

Commit

Permalink
Go: Add ZPopMin and ZPopMax (valkey-io#2850)
Browse files Browse the repository at this point in the history
* Go: Add ZPopMin and ZPopMax

Signed-off-by: TJ Zhang <[email protected]>
  • Loading branch information
tjzhang-BQ authored Dec 24, 2024
1 parent 7de14df commit fe9f9ed
Show file tree
Hide file tree
Showing 5 changed files with 208 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
* Go: Add `ZIncrBy` command ([#2830](https://github.com/valkey-io/valkey-glide/pull/2830))
* Go: Add `SScan` and `SMove` ([#2789](https://github.com/valkey-io/valkey-glide/issues/2789))
* Go: Add `ZADD` ([#2813](https://github.com/valkey-io/valkey-glide/issues/2813))
* Go: Add `ZPopMin` and `ZPopMax` ([#2850](https://github.com/valkey-io/valkey-glide/pull/2850))

#### Breaking Changes

Expand Down
32 changes: 32 additions & 0 deletions go/api/base_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -1316,3 +1316,35 @@ func (client *baseClient) ZIncrBy(key string, increment float64, member string)

return handleDoubleResponse(result)
}

func (client *baseClient) ZPopMin(key string) (map[Result[string]]Result[float64], error) {
result, err := client.executeCommand(C.ZPopMin, []string{key})
if err != nil {
return nil, err
}
return handleStringDoubleMapResponse(result)
}

func (client *baseClient) ZPopMinWithCount(key string, count int64) (map[Result[string]]Result[float64], error) {
result, err := client.executeCommand(C.ZPopMin, []string{key, utils.IntToString(count)})
if err != nil {
return nil, err
}
return handleStringDoubleMapResponse(result)
}

func (client *baseClient) ZPopMax(key string) (map[Result[string]]Result[float64], error) {
result, err := client.executeCommand(C.ZPopMax, []string{key})
if err != nil {
return nil, err
}
return handleStringDoubleMapResponse(result)
}

func (client *baseClient) ZPopMaxWithCount(key string, count int64) (map[Result[string]]Result[float64], error) {
result, err := client.executeCommand(C.ZPopMax, []string{key, utils.IntToString(count)})
if err != nil {
return nil, err
}
return handleStringDoubleMapResponse(result)
}
24 changes: 24 additions & 0 deletions go/api/response_handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,30 @@ func handleBooleanArrayResponse(response *C.struct_CommandResponse) ([]Result[bo
return slice, nil
}

func handleStringDoubleMapResponse(response *C.struct_CommandResponse) (map[Result[string]]Result[float64], error) {
defer C.free_command_response(response)

typeErr := checkResponseType(response, C.Map, false)
if typeErr != nil {
return nil, typeErr
}

m := make(map[Result[string]]Result[float64], response.array_value_len)
for _, v := range unsafe.Slice(response.array_value, response.array_value_len) {
key, err := convertCharArrayToString(v.map_key, true)
if err != nil {
return nil, err
}
typeErr := checkResponseType(v.map_value, C.Float, false)
if typeErr != nil {
return nil, typeErr
}
value := CreateFloat64Result(float64(v.map_value.float_value))
m[key] = value
}
return m, nil
}

func handleStringToStringMapResponse(response *C.struct_CommandResponse) (map[Result[string]]Result[string], error) {
defer C.free_command_response(response)

Expand Down
82 changes: 82 additions & 0 deletions go/api/sorted_set_commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,4 +110,86 @@ type SortedSetCommands interface {
//
// [valkey.io]: https://valkey.io/commands/zincrby/
ZIncrBy(key string, increment float64, member string) (Result[float64], error)

// Removes and returns the member with the lowest score from the sorted set
// stored at the specified `key`.
//
// see [valkey.io] for details.
//
// Parameters:
// key - The key of the sorted set.
//
// Return value:
// A map containing the removed member and its corresponding score.
// If `key` doesn't exist, it will be treated as an empty sorted set and the
// command returns an empty map.
//
// Example:
// res, err := client.zpopmin("mySortedSet")
// fmt.Println(res.Value()) // Output: map["member1":5.0]
//
// [valkey.io]: https://valkey.io/commands/zpopmin/
ZPopMin(key string) (map[Result[string]]Result[float64], error)

// Removes and returns up to `count` members with the lowest scores from the sorted set
// stored at the specified `key`.
//
// see [valkey.io] for details.
//
// Parameters:
// key - The key of the sorted set.
// count - The number of members to remove.
//
// Return value:
// A map containing the removed members and their corresponding scores.
// If `key` doesn't exist, it will be treated as an empty sorted set and the
// command returns an empty map.
//
// Example:
// res, err := client.ZPopMinWithCount("mySortedSet", 2)
// fmt.Println(res.Value()) // Output: map["member1":5.0, "member2":6.0]
//
// [valkey.io]: https://valkey.io/commands/zpopmin/
ZPopMinWithCount(key string, count int64) (map[Result[string]]Result[float64], error)

// Removes and returns the member with the highest score from the sorted set stored at the
// specified `key`.
//
// see [valkey.io] for details.
//
// Parameters:
// key - The key of the sorted set.
//
// Return value:
// A map containing the removed member and its corresponding score.
// If `key` doesn't exist, it will be treated as an empty sorted set and the
// command returns an empty map.
//
// Example:
// res, err := client.zpopmax("mySortedSet")
// fmt.Println(res.Value()) // Output: map["member2":8.0]
//
// [valkey.io]: https://valkey.io/commands/zpopmin/
ZPopMax(key string) (map[Result[string]]Result[float64], error)

// Removes and returns up to `count` members with the highest scores from the sorted set
// stored at the specified `key`.
//
// see [valkey.io] for details.
//
// Parameters:
// key - The key of the sorted set.
// count - The number of members to remove.
//
// Return value:
// A map containing the removed members and their corresponding scores.
// If `key` doesn't exist, it will be treated as an empty sorted set and the
// command returns an empty map.
//
// Example:
// res, err := client.ZPopMaxWithCount("mySortedSet", 2)
// fmt.Println(res.Value()) // Output: map["member1":5.0, "member2":6.0]
//
// [valkey.io]: https://valkey.io/commands/zpopmin/
ZPopMaxWithCount(key string, count int64) (map[Result[string]]Result[float64], error)
}
69 changes: 69 additions & 0 deletions go/integTest/shared_commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3970,3 +3970,72 @@ func (suite *GlideTestSuite) TestZincrBy() {
assert.IsType(suite.T(), &api.RequestError{}, err)
})
}

func (suite *GlideTestSuite) TestZPopMin() {
suite.runWithDefaultClients(func(client api.BaseClient) {
key1 := uuid.New().String()
key2 := uuid.New().String()
memberScoreMap := map[string]float64{
"one": 1.0,
"two": 2.0,
"three": 3.0,
}

res, err := client.ZAdd(key1, memberScoreMap)
assert.Nil(suite.T(), err)
assert.Equal(suite.T(), int64(3), res.Value())

res2, err := client.ZPopMin(key1)
assert.Nil(suite.T(), err)
assert.Len(suite.T(), res2, 1)
assert.Equal(suite.T(), float64(1.0), res2[api.CreateStringResult("one")].Value())

res3, err := client.ZPopMinWithCount(key1, 2)
assert.Nil(suite.T(), err)
assert.Len(suite.T(), res3, 2)
assert.Equal(suite.T(), float64(2.0), res3[api.CreateStringResult("two")].Value())
assert.Equal(suite.T(), float64(3.0), res3[api.CreateStringResult("three")].Value())

// non sorted set key
_, err = client.Set(key2, "test")
assert.Nil(suite.T(), err)

_, err = client.ZPopMin(key2)
assert.NotNil(suite.T(), err)
assert.IsType(suite.T(), &api.RequestError{}, err)
})
}

func (suite *GlideTestSuite) TestZPopMax() {
suite.runWithDefaultClients(func(client api.BaseClient) {
key1 := uuid.New().String()
key2 := uuid.New().String()
memberScoreMap := map[string]float64{
"one": 1.0,
"two": 2.0,
"three": 3.0,
}
res, err := client.ZAdd(key1, memberScoreMap)
assert.Nil(suite.T(), err)
assert.Equal(suite.T(), int64(3), res.Value())

res2, err := client.ZPopMax(key1)
assert.Nil(suite.T(), err)
assert.Len(suite.T(), res2, 1)
assert.Equal(suite.T(), float64(3.0), res2[api.CreateStringResult("three")].Value())

res3, err := client.ZPopMaxWithCount(key1, 2)
assert.Nil(suite.T(), err)
assert.Len(suite.T(), res3, 2)
assert.Equal(suite.T(), float64(2.0), res3[api.CreateStringResult("two")].Value())
assert.Equal(suite.T(), float64(1.0), res3[api.CreateStringResult("one")].Value())

// non sorted set key
_, err = client.Set(key2, "test")
assert.Nil(suite.T(), err)

_, err = client.ZPopMax(key2)
assert.NotNil(suite.T(), err)
assert.IsType(suite.T(), &api.RequestError{}, err)
})
}

0 comments on commit fe9f9ed

Please sign in to comment.