From 16ed74bb4cfb6060a6a41b8c131468bbb3bf0bb2 Mon Sep 17 00:00:00 2001 From: jbrinkman Date: Tue, 24 Dec 2024 10:42:01 -0500 Subject: [PATCH] add response handler for BZPopMin Signed-off-by: jbrinkman --- go/api/base_client.go | 6 +-- go/api/response_handlers.go | 30 +++++++++++++++ go/api/response_types.go | 13 +++++++ go/api/sorted_set_commands.go | 4 +- go/integTest/shared_commands_test.go | 56 ++++++++++++++-------------- 5 files changed, 77 insertions(+), 32 deletions(-) diff --git a/go/api/base_client.go b/go/api/base_client.go index 3dd6df9b3d..167bb6d9a1 100644 --- a/go/api/base_client.go +++ b/go/api/base_client.go @@ -1371,11 +1371,11 @@ func (client *baseClient) ZPopMaxWithCount(key string, count int64) (map[Result[ return handleStringDoubleMapResponse(result) } -func (client *baseClient) BZPopMin(keys []string, timeoutSecs float64) ([]Result[string], error) { +func (client *baseClient) BZPopMin(keys []string, timeoutSecs float64) (Result[KeyWithMemberAndScore], error) { result, err := client.executeCommand(C.BZPopMin, append(keys, utils.FloatToString(timeoutSecs))) if err != nil { - return nil, err + return CreateNilKeyWithMemberAndScoreResult(), err } - return handleStringArrayOrNullResponse(result) + return handleKeyWithMemberAndScoreResponse(result) } diff --git a/go/api/response_handlers.go b/go/api/response_handlers.go index dd4c2d1f24..4ccb5d9a53 100644 --- a/go/api/response_handlers.go +++ b/go/api/response_handlers.go @@ -397,6 +397,36 @@ func handleStringSetResponse(response *C.struct_CommandResponse) (map[Result[str return slice, nil } +func describe(i interface{}) { + fmt.Printf("(%v, %T)\n", i, i) +} + +func handleKeyWithMemberAndScoreResponse(response *C.struct_CommandResponse) (Result[KeyWithMemberAndScore], error) { + defer C.free_command_response(response) + + describe(response) + typeErr := checkResponseType(response, C.Array, false) + if typeErr != nil { + return CreateNilKeyWithMemberAndScoreResult(), typeErr + } + + return CreateNilKeyWithMemberAndScoreResult(), nil + // 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 + // } + // value, err := handleDoubleResponse(v.map_value) + // if err != nil { + // return nil, err + // } + // m[key] = value + // } + + // return m, nil +} + func handleScanResponse( response *C.struct_CommandResponse, ) (Result[string], []Result[string], error) { diff --git a/go/api/response_types.go b/go/api/response_types.go index 3146032b04..3338f51c05 100644 --- a/go/api/response_types.go +++ b/go/api/response_types.go @@ -7,6 +7,11 @@ type Result[T any] struct { isNil bool } +type KeyWithMemberAndScore struct { + Key, Member string + Score float64 +} + func (result Result[T]) IsNil() bool { return result.isNil } @@ -47,6 +52,14 @@ func CreateNilBoolResult() Result[bool] { return Result[bool]{val: false, isNil: true} } +func CreateKeyWithMemberAndScoreResult(kmsVal KeyWithMemberAndScore) Result[KeyWithMemberAndScore] { + return Result[KeyWithMemberAndScore]{val: kmsVal, isNil: false} +} + +func CreateNilKeyWithMemberAndScoreResult() Result[KeyWithMemberAndScore] { + return Result[KeyWithMemberAndScore]{val: KeyWithMemberAndScore{"", "", 0.0}, isNil: true} +} + // Enum to distinguish value types stored in `ClusterValue` type ValueType int diff --git a/go/api/sorted_set_commands.go b/go/api/sorted_set_commands.go index 1ece0cf04d..2bdc6f7502 100644 --- a/go/api/sorted_set_commands.go +++ b/go/api/sorted_set_commands.go @@ -193,6 +193,6 @@ type SortedSetCommands interface { // [valkey.io]: https://valkey.io/commands/zpopmin/ ZPopMaxWithCount(key string, count int64) (map[Result[string]]Result[float64], error) - // [valkey bzpopmin]: https://valkey.io/commands/bzpopmin/ - BZPopMin(keys []string, timeoutSecs float64) ([]Result[string], error) + // [valkey.io]: https://valkey.io/commands/bzpopmin/ + BZPopMin(keys []string, timeoutSecs float64) (Result[KeyWithMemberAndScore], error) } diff --git a/go/integTest/shared_commands_test.go b/go/integTest/shared_commands_test.go index 0efd3f2045..02525e6f61 100644 --- a/go/integTest/shared_commands_test.go +++ b/go/integTest/shared_commands_test.go @@ -3969,11 +3969,13 @@ func (suite *GlideTestSuite) TestZincrBy() { assert.NotNil(suite.T(), err) assert.IsType(suite.T(), &api.RequestError{}, err) }) +} func (suite *GlideTestSuite) TestBZPopMin() { suite.runWithDefaultClients(func(client api.BaseClient) { key1 := "{listKey}-1-" + uuid.NewString() - // key2 := "{listKey}-2-" + uuid.NewString() + key2 := "{listKey}-2-" + uuid.NewString() + key3 := "{listKey}-2-" + uuid.NewString() // Add elements to key1 zaddResult1, err := client.ZAdd(key1, map[string]float64{"a": 1.0, "b": 1.5}) @@ -3981,34 +3983,34 @@ func (suite *GlideTestSuite) TestBZPopMin() { assert.Equal(suite.T(), int64(2), zaddResult1.Value()) // Add elements to key2 - // zaddResult2, err := client.ZAdd(key2, map[string]float64{"c": 2.0}) - // assert.Nil(suite.T(), err) - // assert.Equal(suite.T(), int64(1), zaddResult2.Value()) - - // // Pop minimum element from key1 and key2 - // bzpopminResult1, err := client.BZPopMin([]string{key1, key2}, 500*time.Millisecond) - // assert.NoError(suite.T(), err) - // assert.Equal(suite.T() []interface{}{key1, "a", 1.0}, bzpopminResult1) - - // // Attempt to pop from non-existent key3 - // bzpopminResult2, err := client.BZPopMin([]string{key3}, 1*time.Second) - // assert.NoError(suite.T() err) - // assert.Nil(suite.T() bzpopminResult2) - - // // Pop minimum element from key2 - // bzpopminResult3, err := client.BZPopMin([]string{key3, key2}, 500*time.Millisecond) - // assert.NoError(suite.T() err) - // assert.Equal(suite.T() []interface{}{key2, "c", 2.0}, bzpopminResult3) - - // // Set key3 to a non-sorted set value - // setResult, err := client.Set(key3, "value") - // assert.NoError(suite.T() err) - // assert.Equal(suite.T() "OK", setResult) + zaddResult2, err := client.ZAdd(key2, map[string]float64{"c": 2.0}) + assert.Nil(suite.T(), err) + assert.Equal(suite.T(), int64(1), zaddResult2.Value()) + + // Pop minimum element from key1 and key2 + bzpopminResult1, err := client.BZPopMin([]string{key1, key2}, float64(500*time.Millisecond)) + assert.Nil(suite.T(), err) + assert.Equal(suite.T(), []interface{}{key1, "a", 1.0}, bzpopminResult1) + + // Attempt to pop from non-existent key3 + bzpopminResult2, err := client.BZPopMin([]string{key3}, float64(1*time.Second)) + assert.Nil(suite.T(), err) + assert.Nil(suite.T(), bzpopminResult2) + + // Pop minimum element from key2 + bzpopminResult3, err := client.BZPopMin([]string{key3, key2}, float64(500*time.Millisecond)) + assert.Nil(suite.T(), err) + assert.Equal(suite.T(), []interface{}{key2, "c", 2.0}, bzpopminResult3) + + // Set key3 to a non-sorted set value + setResult, err := client.Set(key3, "value") + assert.Nil(suite.T(), err) + assert.Equal(suite.T(), "OK", setResult) // // Attempt to pop from key3 which is not a sorted set - // _, err = client.BZPopMin([]string{key3}, 500*time.Millisecond) - // assert.Error(suite.T() err) - // assert.IsType(suite.T() RequestException{}, err) + // _, err = client.BZPopMin([]string{key3}, float64(500*time.Millisecond)) + // assert.Error(suite.T(), err) + // assert.IsType(suite.T(), RequestException{}, err) }) }