-
Notifications
You must be signed in to change notification settings - Fork 53
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Go: Implementing Hash commands #2226
Go: Implementing Hash commands #2226
Conversation
5da6299
to
184a6a4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for providing this PR!, in general it looks good
My major concerns are:
- Some of the methods implemented are "swallowing" errors (for example:
HStrLen
does not return NULL by Redis, and yet we assume thatnull
is valid and we convert it into0
while we should return an error to the caller - The Rust code assumes valid strings are returned from redis/valkey, while this is not the case. Do not use
String
. Assume that a "string" is&[u8]
orVec<u8>
9ed4260
to
3f9ec9d
Compare
go/api/commands.go
Outdated
// See [valkey.io] for details. | ||
// | ||
// For example: | ||
// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To have docs aligned and common style
// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@janhavigupta007 I've removed.
go/src/lib.rs
Outdated
let (vec_ptr, len) = convert_vec_to_pointer(result); | ||
let (vec_elements_len_ptr, _) = convert_vec_to_pointer(vec_elements_len); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please confirm that we're not leaking memory there, especially on an error
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1. Also, I'm curious to know why convert_vec_to_pointer
uses mem::forget
.
70723d9
to
420f031
Compare
f476f8e
to
14200f1
Compare
go/src/lib.rs
Outdated
if !array_value.is_null() { | ||
let len = array_value_len as usize; | ||
let vec = unsafe { Vec::from_raw_parts(array_value, len, len) }; | ||
let elem_len = unsafe { Vec::from_raw_parts(array_elements_len, len, len) }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
array_elements_len is a pointer, so it could be null here.
go/api/response_handlers.go
Outdated
numElements := int(response.array_value_len) | ||
if len(lengths) != numElements { | ||
// Handle inconsistent array lengths (just in case) | ||
return nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Return an error, don't hide it with nil
14200f1
to
4e776c1
Compare
go/api/response_handlers.go
Outdated
@@ -31,6 +32,12 @@ func handleStringOrNullResponse(response *C.struct_CommandResponse) string { | |||
return handleStringResponse(response) | |||
} | |||
|
|||
// handleBooleanResponse converts a C struct_CommandResponse's bool_value to a Go bool. | |||
func handleBooleanResponse(response *C.struct_CommandResponse) bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we have the methods consistent please?
E.g.:
Either
- getXXXResponse returns XXX OR
- getXXXResponse returns XXX, err
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ravisi21 It's done.
go/src/lib.rs
Outdated
let result = map | ||
.into_iter() | ||
.flat_map(|(key, value)| { | ||
let key = <Vec<u8>>::from_redis_value(&key) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems like reducing a redis::Value to always a string.
That may serve a specific purpose now of Map<String, String>, but I dont think that would be a right implementation.
We should try to convert the redis::Value to CommandResponse so that the generic nature is maintained.
We are working towards that as you can check in the PR: #2289
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey, I did not forget about this PR. I am waiting for this PR: #2289 to be merged as it fixes basic data exchanging between Rust <-> Go
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM if all other comments are addressed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Signed-off-by: umit <[email protected]>
ae02a9a
to
632d990
Compare
go/api/commands.go
Outdated
// See [valkey.io] for details. | ||
// | ||
// For example: | ||
// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
// | ||
// For example: | ||
// payload, err := client.HGet("my_hash", "field1") | ||
// // payload equals "value" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we also show what my_hash contains in order to be clear on how "value" is being returned.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@janhavigupta007 I've added my_hash
values in the comment.
go/api/commands.go
Outdated
// For every field that does not exist in the hash, a null value is returned. | ||
// If key does not exist, it is treated as an empty hash, and it returns an array of null values. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the value is not present, an empty string would be returned as string can't be null in GO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@janhavigupta007 I've updated the message according to your comment.
go/api/commands.go
Outdated
// For example: | ||
// num1, err := client.HLen("myHash") | ||
// // num1 equals 3 | ||
// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@janhavigupta007 It's done.
go/api/commands.go
Outdated
// For example: | ||
// exists, err := client.HExists("my_hash", "field1") | ||
// // exists equals true | ||
// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@janhavigupta007 It's done.
} | ||
|
||
func (client *baseClient) MSetNX(keyValueMap map[string]string) (bool, error) { | ||
result, err := client.executeCommand(C.MSetNX, utils.MapToString(keyValueMap)) | ||
if err != nil { | ||
return false, err | ||
} | ||
return handleBooleanResponse(result), nil | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In some functions, extra spaces are added and somewhere it's not. Let's keep it consistent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@janhavigupta007 I've updated with extra spaces. The separate return statement on a new line is generally considered better practice in Go.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this something that can be handled by gofmt
?
go/api/response_handlers.go
Outdated
|
||
result := make(map[string]string, response.array_value_len) | ||
values := unsafe.Slice(response.array_value, response.array_value_len) | ||
|
||
for _, v := range values { | ||
key := convertCharArrayToString(v.map_key.string_value, v.map_key.string_value_len) | ||
value := convertCharArrayToString(v.map_value.string_value, v.map_value.string_value_len) | ||
m[key] = value | ||
result[key] = value | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason we are modifying this? Also, please retain the ordering of the functions so that it can only reflect the changes made and it will be easier for review.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@janhavigupta007 The function was updated during the rebase operation. I revert it and added null response check.
go/api/base_client.go
Outdated
res, err := handleStringToStringMapResponse(result) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return res, nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can directly return handleStringToStringMapResponse(result)
here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@janhavigupta007 It's done.
go/api/base_client.go
Outdated
func (client *baseClient) HMGet(key string, fields []string) ([]string, error) { | ||
result, err := client.executeCommand(C.HMGet, append([]string{key}, fields...)) | ||
if err != nil { | ||
return []string{}, err |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please return nil, err
from here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@janhavigupta007 It's fixed.
Signed-off-by: umit <[email protected]>
@@ -146,63 +147,71 @@ func (client *baseClient) Set(key string, value string) (string, error) { | |||
if err != nil { | |||
return "", err | |||
} | |||
return handleStringResponse(result), nil | |||
|
|||
return handleStringResponse(result) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for fixing this 👍
} | ||
|
||
func (client *baseClient) MSetNX(keyValueMap map[string]string) (bool, error) { | ||
result, err := client.executeCommand(C.MSetNX, utils.MapToString(keyValueMap)) | ||
if err != nil { | ||
return false, err | ||
} | ||
return handleBooleanResponse(result), nil | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this something that can be handled by gofmt
?
Implement Valkey Hash Commands
This PR implements the following Valkey hash commands: