diff --git a/go/api/connection_management_cluster_commands.go b/go/api/connection_management_cluster_commands.go index 175134f92e..af97de393d 100644 --- a/go/api/connection_management_cluster_commands.go +++ b/go/api/connection_management_cluster_commands.go @@ -15,4 +15,6 @@ type ConnectionManagementClusterCommands interface { PingWithOptions(pingOptions options.ClusterPingOptions) (string, error) EchoWithOptions(echoOptions options.ClusterEchoOptions) (ClusterValue[string], error) + + ClientIdWithOptions(routeOptions options.RouteOption) (ClusterValue[int64], error) } diff --git a/go/api/glide_cluster_client.go b/go/api/glide_cluster_client.go index 9ef021d6f9..d9d3f107f0 100644 --- a/go/api/glide_cluster_client.go +++ b/go/api/glide_cluster_client.go @@ -372,3 +372,48 @@ func (client *GlideClusterClient) EchoWithOptions(echoOptions options.ClusterEch } return createClusterSingleValue[string](data), nil } + +// Gets the current connection id. +// The command will be routed a random node, unless `Route` in `routeOptions` is provided. +// +// Parameters: +// +// route - Specifies the routing configuration for the command. The client will route the +// command to the nodes defined by route. +// +// Return value: +// +// The id of the client. +// +// Example: +// +// route := config.Route(config.RandomRoute) +// opts = options.RouteOption{Route: route} +// response, err = client.ClientIdWithOptions(opts) +// if err != nil { +// // handle error +// } +// for node, data := range response { +// fmt.Printf("%s node returned %s\n", node, data) +// } +// +// [valkey.io]: https://valkey.io/commands/client-id/ +func (client *GlideClusterClient) ClientIdWithOptions(opts options.RouteOption) (ClusterValue[int64], error) { + response, err := client.executeCommandWithRoute(C.ClientId, []string{}, opts.Route) + if err != nil { + return createEmptyClusterValue[int64](), err + } + if opts.Route != nil && + (opts.Route).IsMultiNode() { + data, err := handleStringIntMapResponse(response) + if err != nil { + return createEmptyClusterValue[int64](), err + } + return createClusterMultiValue[int64](data), nil + } + data, err := handleIntResponse(response) + if err != nil { + return createEmptyClusterValue[int64](), err + } + return createClusterSingleValue[int64](data), nil +} diff --git a/go/api/response_handlers.go b/go/api/response_handlers.go index e1030e0b7d..115dabbd34 100644 --- a/go/api/response_handlers.go +++ b/go/api/response_handlers.go @@ -1249,3 +1249,30 @@ func handleTimeClusterResponse(response *C.struct_CommandResponse) (ClusterValue } return createClusterSingleValue(data), nil } + +func handleStringIntMapResponse(response *C.struct_CommandResponse) (map[string]int64, error) { + defer C.free_command_response(response) + + typeErr := checkResponseType(response, C.Map, false) + if typeErr != nil { + return nil, typeErr + } + + data, err := parseMap(response) + if err != nil { + return nil, err + } + aMap := data.(map[string]interface{}) + + converted, err := mapConverter[int64]{ + nil, false, + }.convert(aMap) + if err != nil { + return nil, err + } + result, ok := converted.(map[string]int64) + if !ok { + return nil, &errors.RequestError{Msg: fmt.Sprintf("unexpected type of map: %T", converted)} + } + return result, nil +} diff --git a/go/integTest/cluster_commands_test.go b/go/integTest/cluster_commands_test.go index d6da52bf18..0ab60d1064 100644 --- a/go/integTest/cluster_commands_test.go +++ b/go/integTest/cluster_commands_test.go @@ -298,3 +298,28 @@ func (suite *GlideTestSuite) TestEchoCluster() { assert.Contains(t, strings.ToLower(messages), strings.ToLower("hello")) } } + +func (suite *GlideTestSuite) TestClientIdCluster() { + client := suite.defaultClusterClient() + t := suite.T() + + // ClientId with option or with multiple options without route + opts := options.RouteOption{Route: nil} + response, err := client.ClientIdWithOptions(opts) + assert.NoError(t, err) + assert.True(t, response.IsSingleValue()) + + // same sections with random route + route := config.Route(config.RandomRoute) + opts = options.RouteOption{Route: route} + response, err = client.ClientIdWithOptions(opts) + assert.NoError(t, err) + assert.True(t, response.IsSingleValue()) + + // default sections, multi node route + route = config.Route(config.AllPrimaries) + opts = options.RouteOption{Route: route} + response, err = client.ClientIdWithOptions(opts) + assert.NoError(t, err) + assert.True(t, response.IsMultiValue()) +}