Skip to content

Commit

Permalink
Merge fixups
Browse files Browse the repository at this point in the history
Signed-off-by: ikolomi <[email protected]>
  • Loading branch information
ikolomi committed Dec 5, 2024
1 parent 5b9fe12 commit cb67b3c
Show file tree
Hide file tree
Showing 15 changed files with 217 additions and 43 deletions.
1 change: 0 additions & 1 deletion benchmarks/rust/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
/**
* Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0
*/

#[cfg(not(target_env = "msvc"))]
use tikv_jemallocator::Jemalloc;

Expand Down
1 change: 0 additions & 1 deletion glide-core/build.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
/**
* Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0
*/

#[cfg(feature = "socket-layer")]
fn build_protobuf() {
let customization_options = protobuf_codegen::Customize::default()
Expand Down
2 changes: 1 addition & 1 deletion glide-core/redis-rs/redis/src/cluster.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ impl<'a> Input<'a> {
}
}

impl<'a> Routable for Input<'a> {
impl Routable for Input<'_> {
fn arg_idx(&self, idx: usize) -> Option<&[u8]> {
match self {
Input::Slice { cmd: _, routable } => routable.arg_idx(idx),
Expand Down
2 changes: 1 addition & 1 deletion glide-core/redis-rs/redis/src/cluster_routing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1378,7 +1378,7 @@ impl ShardAddrs {
}
}

impl<'a> IntoIterator for &'a ShardAddrs {
impl IntoIterator for &ShardAddrs {
type Item = Arc<String>;
type IntoIter = std::iter::Chain<Once<Arc<String>>, std::vec::IntoIter<Arc<String>>>;

Expand Down
2 changes: 1 addition & 1 deletion glide-core/redis-rs/redis/src/cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ pub struct Iter<'a, T: FromRedisValue> {
cmd: Cmd,
}

impl<'a, T: FromRedisValue> Iterator for Iter<'a, T> {
impl<T: FromRedisValue> Iterator for Iter<'_, T> {
type Item = T;

#[inline]
Expand Down
1 change: 0 additions & 1 deletion glide-core/redis-rs/redis/src/commands/cluster_scan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ use strum_macros::Display;
/// The [[`ScanState`]] struct represents the state of a scan operation in a Redis cluster.
/// It holds information about the current scan state, including the cursor position, scanned slots map,
/// address being scanned, and address's epoch.
const BITS_PER_U64: usize = u64::BITS as usize;
const NUM_OF_SLOTS: usize = SLOT_SIZE as usize;
const BITS_ARRAY_SIZE: usize = NUM_OF_SLOTS / BITS_PER_U64;
Expand Down
4 changes: 2 additions & 2 deletions glide-core/redis-rs/redis/src/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ impl IntoConnectionInfo for ConnectionInfo {
/// - Specifying DB: `redis://127.0.0.1:6379/0`
/// - Enabling TLS: `rediss://127.0.0.1:6379`
/// - Enabling Insecure TLS: `rediss://127.0.0.1:6379/#insecure`
impl<'a> IntoConnectionInfo for &'a str {
impl IntoConnectionInfo for &str {
fn into_connection_info(self) -> RedisResult<ConnectionInfo> {
match parse_redis_url(self) {
Some(u) => u.into_connection_info(),
Expand Down Expand Up @@ -1578,7 +1578,7 @@ impl<'a> PubSub<'a> {
}
}

impl<'a> Drop for PubSub<'a> {
impl Drop for PubSub<'_> {
fn drop(&mut self) {
let _ = self.con.exit_pubsub();
}
Expand Down
4 changes: 2 additions & 2 deletions glide-core/redis-rs/redis/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1443,7 +1443,7 @@ impl ToRedisArgs for String {
}
}

impl<'a> ToRedisArgs for &'a str {
impl ToRedisArgs for &str {
fn write_redis_args<W>(&self, out: &mut W)
where
W: ?Sized + RedisWrite,
Expand All @@ -1465,7 +1465,7 @@ impl<T: ToRedisArgs> ToRedisArgs for Vec<T> {
}
}

impl<'a, T: ToRedisArgs> ToRedisArgs for &'a [T] {
impl<T: ToRedisArgs> ToRedisArgs for &[T] {
fn write_redis_args<W>(&self, out: &mut W)
where
W: ?Sized + RedisWrite,
Expand Down
8 changes: 1 addition & 7 deletions go/api/glide_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,12 @@ func NewGlideClient(config *GlideClientConfiguration) (*GlideClient, error) {
// For example, to return a list of all pub/sub clients:
//
// client.CustomCommand([]string{"CLIENT", "LIST","TYPE", "PUBSUB"})
//
// TODO: Add support for complex return types.
func (client *GlideClient) CustomCommand(args []string) (interface{}, error) {
res, err := client.executeCommand(C.CustomCommand, args)
if err != nil {
return nil, err
}
resString, err := handleStringOrNullResponse(res)
if err != nil {
return nil, err
}
return resString.Value(), err
return handleInterfaceResponse(res)
}

// Sets configuration parameters to the specified values.
Expand Down
96 changes: 96 additions & 0 deletions go/api/response_handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,102 @@ func convertCharArrayToString(response *C.struct_CommandResponse, isNilable bool
return CreateStringResult(string(byteSlice)), nil
}

func handleInterfaceResponse(response *C.struct_CommandResponse) (interface{}, error) {
defer C.free_command_response(response)

return parseInterface(response)
}

func parseInterface(response *C.struct_CommandResponse) (interface{}, error) {
if response == nil {
return nil, nil
}

switch response.response_type {
case C.Null:
return nil, nil
case C.String:
return parseString(response)
case C.Int:
return int64(response.int_value), nil
case C.Float:
return float64(response.float_value), nil
case C.Bool:
return bool(response.bool_value), nil
case C.Array:
return parseArray(response)
case C.Map:
return parseMap(response)
case C.Sets:
return parseSet(response)
}

return nil, &RequestError{"Unexpected return type from Valkey"}
}

func parseString(response *C.struct_CommandResponse) (interface{}, error) {
if response.string_value == nil {
return nil, nil
}
byteSlice := C.GoBytes(unsafe.Pointer(response.string_value), C.int(int64(response.string_value_len)))

// Create Go string from byte slice (preserving null characters)
return string(byteSlice), nil
}

func parseArray(response *C.struct_CommandResponse) (interface{}, error) {
if response.array_value == nil {
return nil, nil
}

var slice []interface{}
for _, v := range unsafe.Slice(response.array_value, response.array_value_len) {
res, err := parseInterface(&v)
if err != nil {
return nil, err
}
slice = append(slice, res)
}
return slice, nil
}

func parseMap(response *C.struct_CommandResponse) (interface{}, error) {
if response.array_value == nil {
return nil, nil
}

value_map := make(map[interface{}]interface{}, response.array_value_len)
for _, v := range unsafe.Slice(response.array_value, response.array_value_len) {
res_key, err := parseInterface(v.map_key)
if err != nil {
return nil, err
}
res_val, err := parseInterface(v.map_value)
if err != nil {
return nil, err
}
value_map[res_key] = res_val
}
return value_map, nil
}

func parseSet(response *C.struct_CommandResponse) (interface{}, error) {
if response.sets_value == nil {
return nil, nil
}

slice := make(map[interface{}]struct{}, response.sets_value_len)
for _, v := range unsafe.Slice(response.sets_value, response.sets_value_len) {
res, err := parseInterface(&v)
if err != nil {
return nil, err
}
slice[res] = struct{}{}
}

return slice, nil
}

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

Expand Down
105 changes: 103 additions & 2 deletions go/integTest/standalone_commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"strings"

"github.com/google/uuid"
"github.com/valkey-io/valkey-glide/go/glide/api"

"github.com/stretchr/testify/assert"
Expand All @@ -21,12 +22,12 @@ func (suite *GlideTestSuite) TestCustomCommandInfo() {
assert.True(suite.T(), strings.Contains(strResult, "# Stats"))
}

func (suite *GlideTestSuite) TestCustomCommandPing() {
func (suite *GlideTestSuite) TestCustomCommandPing_StringResponse() {
client := suite.defaultClient()
result, err := client.CustomCommand([]string{"PING"})

assert.Nil(suite.T(), err)
assert.Equal(suite.T(), "PONG", result)
assert.Equal(suite.T(), "PONG", result.(string))
}

func (suite *GlideTestSuite) TestCustomCommandClientInfo() {
Expand All @@ -44,6 +45,106 @@ func (suite *GlideTestSuite) TestCustomCommandClientInfo() {
assert.True(suite.T(), strings.Contains(strResult, fmt.Sprintf("name=%s", clientName)))
}

func (suite *GlideTestSuite) TestCustomCommandGet_NullResponse() {
client := suite.defaultClient()
key := uuid.New().String()
result, err := client.CustomCommand([]string{"GET", key})

assert.Nil(suite.T(), err)
assert.Equal(suite.T(), nil, result)
}

func (suite *GlideTestSuite) TestCustomCommandDel_LongResponse() {
client := suite.defaultClient()
key := uuid.New().String()
suite.verifyOK(client.Set(key, "value"))
result, err := client.CustomCommand([]string{"DEL", key})

assert.Nil(suite.T(), err)
assert.Equal(suite.T(), int64(1), result.(int64))
}

func (suite *GlideTestSuite) TestCustomCommandHExists_BoolResponse() {
client := suite.defaultClient()
fields := map[string]string{"field1": "value1"}
key := uuid.New().String()

res1, err := client.HSet(key, fields)
assert.Nil(suite.T(), err)
assert.Equal(suite.T(), int64(1), res1.Value())

result, err := client.CustomCommand([]string{"HEXISTS", key, "field1"})

assert.Nil(suite.T(), err)
assert.Equal(suite.T(), true, result.(bool))
}

func (suite *GlideTestSuite) TestCustomCommandIncrByFloat_FloatResponse() {
client := suite.defaultClient()
key := uuid.New().String()

result, err := client.CustomCommand([]string{"INCRBYFLOAT", key, fmt.Sprintf("%f", 0.1)})

assert.Nil(suite.T(), err)
assert.Equal(suite.T(), float64(0.1), result.(float64))
}

func (suite *GlideTestSuite) TestCustomCommandMGet_ArrayResponse() {
clientName := "TEST_CLIENT_NAME"
config := api.NewGlideClientConfiguration().
WithAddress(&api.NodeAddress{Port: suite.standalonePorts[0]}).
WithClientName(clientName)
client := suite.client(config)

key1 := uuid.New().String()
key2 := uuid.New().String()
key3 := uuid.New().String()
oldValue := uuid.New().String()
value := uuid.New().String()
suite.verifyOK(client.Set(key1, oldValue))
keyValueMap := map[string]string{
key1: value,
key2: value,
}
suite.verifyOK(client.MSet(keyValueMap))
keys := []string{key1, key2, key3}
values := []interface{}{value, value, nil}
result, err := client.CustomCommand(append([]string{"MGET"}, keys...))

assert.Nil(suite.T(), err)
assert.Equal(suite.T(), values, result.([]interface{}))
}

func (suite *GlideTestSuite) TestCustomCommandConfigGet_MapResponse() {
client := suite.defaultClient()

if suite.serverVersion < "7.0.0" {
suite.T().Skip("This feature is added in version 7")
}
configMap := map[string]string{"timeout": "1000", "maxmemory": "1GB"}
result, err := client.ConfigSet(configMap)
assert.Nil(suite.T(), err)
assert.Equal(suite.T(), "OK", result.Value())

result2, err := client.CustomCommand([]string{"CONFIG", "GET", "timeout", "maxmemory"})
assert.Nil(suite.T(), err)
assert.Equal(suite.T(), map[interface{}]interface{}{"timeout": "1000", "maxmemory": "1073741824"}, result2)
}

func (suite *GlideTestSuite) TestCustomCommandConfigSMembers_SetResponse() {
client := suite.defaultClient()
key := uuid.NewString()
members := []string{"member1", "member2", "member3"}

res1, err := client.SAdd(key, members)
assert.Nil(suite.T(), err)
assert.Equal(suite.T(), int64(3), res1.Value())

result2, err := client.CustomCommand([]string{"SMEMBERS", key})
assert.Nil(suite.T(), err)
assert.Equal(suite.T(), map[interface{}]struct{}{"member1": {}, "member2": {}, "member3": {}}, result2)
}

func (suite *GlideTestSuite) TestCustomCommand_invalidCommand() {
client := suite.defaultClient()
result, err := client.CustomCommand([]string{"pewpew"})
Expand Down
12 changes: 6 additions & 6 deletions go/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ use std::{
ffi::{c_void, CString},
mem,
os::raw::{c_char, c_double, c_long, c_ulong},
ptr,
};
use tokio::runtime::Builder;
use tokio::runtime::Runtime;
Expand Down Expand Up @@ -56,7 +55,6 @@ pub struct CommandResponse {
/// Below two values are related to each other.
/// `sets_value` represents the set of CommandResponse.
/// `sets_value_len` represents the length of the set.
#[derivative(Default(value = "std::ptr::null_mut()"))]
sets_value: *mut CommandResponse,
sets_value_len: c_long,
}
Expand All @@ -68,12 +66,14 @@ impl Default for CommandResponse {
int_value: 0,
float_value: 0.0,
bool_value: false,
string_value: ptr::null_mut(),
string_value: std::ptr::null_mut(),
string_value_len: 0,
array_value: ptr::null_mut(),
array_value: std::ptr::null_mut(),
array_value_len: 0,
map_key: ptr::null_mut(),
map_value: ptr::null_mut(),
map_key: std::ptr::null_mut(),
map_value: std::ptr::null_mut(),
sets_value: std::ptr::null_mut(),
sets_value_len: 0,
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions node/rust-client/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use glide_core::Telemetry;
use redis::GlideConnectionOptions;
/**
* Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0
*/
use glide_core::Telemetry;
use redis::GlideConnectionOptions;

#[cfg(not(target_env = "msvc"))]
use tikv_jemallocator::Jemalloc;
Expand Down
Loading

0 comments on commit cb67b3c

Please sign in to comment.