Skip to content
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

Node: convert Set commands return type to Set #1299

Merged
merged 5 commits into from
May 7, 2024

Conversation

shohamazon
Copy link
Collaborator

@shohamazon shohamazon commented Apr 17, 2024

Issue #, if available:

Description of changes:
Currently, the way we convert the rust value returning from core to a js value, is by using napi.
Since napi doesn't support sets, commmands with a return type of set, returns an array in node.
This is breaking the GLIDE API, since similar commands in different wrappers return a completely different type.
Until napi will add support for sets, we will convert each of the command to a Set, in the wrapper.

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@shohamazon shohamazon added the node Node.js wrapper label Apr 17, 2024
@shohamazon shohamazon requested a review from a team as a code owner April 17, 2024 15:59
@shohamazon shohamazon changed the title Node: convert Set commands return type to sets Node: convert Set commands return type to Set Apr 17, 2024
@shohamazon shohamazon force-pushed the node_sets branch 2 times, most recently from e466a07 to 036df4d Compare April 17, 2024 16:05
const result = (await this.createWritePromise(
createSMembers(key),
)) as string[];
return new Set(result);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A breaking change for user API
I think we have to document it in changelog and/or release notes.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I documented that in the changelog

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a good practice to highlight those as a breaking change and/or track these changes in another doc
Should be also highlighted in release notes

node/src/RedisClusterClient.ts Outdated Show resolved Hide resolved
@@ -143,7 +143,7 @@ export async function transactionTest(
baseTransaction.sismember(key7, "bar");
args.push(true);
baseTransaction.smembers(key7);
args.push(["bar"]);
args.push(new Set(["bar"]));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a test for spopcount

Copy link
Collaborator

@barshaul barshaul left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a different from the user perspective that some of the API defined with 'async' and some not, or defining the function with async is only a matter of wrapping the function with a promise?
@avifenesh

node/src/BaseClient.ts Outdated Show resolved Hide resolved
@@ -1271,23 +1278,28 @@ export class BaseClient {
*
* @param key - The key of the set.
* @param count - The count of the elements to pop from the set.
* @returns A list of popped elements will be returned depending on the set's length.
* If `key` does not exist, empty list will be returned.
* @returns A set containing the popped elements, depending on the set's length.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

emphasize set

@@ -102,7 +102,23 @@ export class RedisClient extends BaseClient {
* If the transaction failed due to a WATCH command, `exec` will return `null`.
*/
public exec(transaction: Transaction): Promise<ReturnType[] | null> {
return this.createWritePromise(transaction.commands);
return this.createWritePromise(transaction.commands).then(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This block is repeated in both clients - can you move it to a function?

CHANGELOG.md Outdated
@@ -8,6 +8,7 @@
* Node: Added ZRANGE command ([#1115](https://github.com/aws/glide-for-redis/pull/1115))
* Python: Added RENAME command ([#1252](https://github.com/aws/glide-for-redis/pull/1252))
* Python: Added APPEND command ([#1152](https://github.com/aws/glide-for-redis/pull/1152))
* Node: When receiving SPOP with count, SMEMBERS convert result to Set ([#1299](https://github.com/aws/glide-for-redis/pull/1299))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be under breaking changes section

@@ -102,7 +102,23 @@ export class RedisClient extends BaseClient {
* If the transaction failed due to a WATCH command, `exec` will return `null`.
*/
public exec(transaction: Transaction): Promise<ReturnType[] | null> {
return this.createWritePromise(transaction.commands);
return this.createWritePromise(transaction.commands).then(
(result: unknown) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is it unknown? can't you do (result: ReturnType[] | null)?

@@ -115,8 +115,16 @@ export class BaseTransaction<T extends BaseTransaction<T>> {
* @internal
*/
readonly commands: redis_request.Command[] = [];
readonly set_commands_indexes: number[] = [];
Copy link
Collaborator

@barshaul barshaul May 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be clear that it is for internal usage. Please add a documentation and mark it with @internal too.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

still missing documentation

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

weird, I remember adding it

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: nodejs naming convention is lowerCamelCase
setCommandsIndexes

node/src/Transaction.ts Outdated Show resolved Hide resolved
node/src/Transaction.ts Outdated Show resolved Hide resolved
Copy link
Collaborator

@barshaul barshaul left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

round

CHANGELOG.md Outdated
#### Fixes
* Python: Fix typing error "‘type’ object is not subscriptable" ([#1203](https://github.com/aws/glide-for-redis/pull/1203))
* Core: Fixed blocking commands to use the specified timeout from the command argument ([#1283](https://github.com/aws/glide-for-redis/pull/1283))

### Breaking Change
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Breaking Changes

CHANGELOG.md Outdated
#### Fixes
* Python: Fix typing error "‘type’ object is not subscriptable" ([#1203](https://github.com/aws/glide-for-redis/pull/1203))
* Core: Fixed blocking commands to use the specified timeout from the command argument ([#1283](https://github.com/aws/glide-for-redis/pull/1283))

### Breaking Change
* Node: When receiving SPOP with count, SMEMBERS convert result to Set ([#1299](https://github.com/aws/glide-for-redis/pull/1299))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed smembers and spopCount functions to return Set instead of <?>

protected processResultWithSetCommands<ReturnType>(
result: ReturnType[] | null,
setCommandsIndexes: number[],
): (ReturnType | Set<string>)[] | null {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add Set to ReturnType

@avifenesh
Copy link
Collaborator

Is there a different from the user perspective that some of the API defined with 'async' and some not, or defining the function with async is only a matter of wrapping the function with a promise? @avifenesh

@barshaul Please explain your question, not sure i understood.
A promise is wrapper for callback, async is a wrapper for promise. kind of.
If you return promise, from the user perspective it doesn't matter if it by defining a function as async or by explicitly returning a promise. For the end user its the same. If this is what you meant.
But its better to keep it consistent since it easier to understand as a reader.

@avifenesh
Copy link
Collaborator

Im sorry if im too late and i dont know if its actually possible, but why we dont try to instead of changing to set in the commands themself, to hook them on the way back from the core and convert the response to set base on the command?
It could be less changes, easier to add all command that are sets commands to this list already, without keep tracking the implementation of each in the future, and easier to change when napi will start giving support to sets.

@shohamazon
Copy link
Collaborator Author

Im sorry if im too late and i dont know if its actually possible, but why we dont try to instead of changing to set in the commands themself, to hook them on the way back from the core and convert the response to set base on the command? It could be less changes, easier to add all command that are sets commands to this list already, without keep tracking the implementation of each in the future, and easier to change when napi will start giving support to sets.

I don't think I fully understand where you intend to add the conversion

@barshaul
Copy link
Collaborator

barshaul commented May 6, 2024

Im sorry if im too late and i dont know if its actually possible, but why we dont try to instead of changing to set in the commands themself, to hook them on the way back from the core and convert the response to set base on the command? It could be less changes, easier to add all command that are sets commands to this list already, without keep tracking the implementation of each in the future, and easier to change when napi will start giving support to sets.

I don't think I fully understand where you intend to add the conversion

there isn't an option with napi to convert to nodejs set type.

Is there a different from the user perspective that some of the API defined with 'async' and some not, or defining the function with async is only a matter of wrapping the function with a promise? @avifenesh

@barshaul Please explain your question, not sure i understood. A promise is wrapper for callback, async is a wrapper for promise. kind of. If you return promise, from the user perspective it doesn't matter if it by defining a function as async or by explicitly returning a promise. For the end user its the same. If this is what you meant. But its better to keep it consistent since it easier to understand as a reader.

nvm, it was on outdated code

@barshaul
Copy link
Collaborator

barshaul commented May 6, 2024

Im sorry if im too late and i dont know if its actually possible, but why we dont try to instead of changing to set in the commands themself, to hook them on the way back from the core and convert the response to set base on the command? It could be less changes, easier to add all command that are sets commands to this list already, without keep tracking the implementation of each in the future, and easier to change when napi will start giving support to sets.

I'm unsure where exactly do you mean to add this hook, but when the nodejs wrapper receives a response from the core, it only contains the response value, not the command name.

result as ReturnType[];

for (const index of setCommandsIndexes) {
modifiedResult[index] = new Set(modifiedResult[index] as string[]);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just to confirm that there is no commands that return a Set of not-a-string

Comment on lines 1222 to 1227
return this.createWritePromise<string[]>(createSMembers(key)).then(
(result: string[]) => {
const resultSet: Set<string> = new Set<string>(result);
return resultSet;
},
);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make a function which converts result to set and call it in then.
BTW, can you refer the Set constructor here?
Something like

return this.createWritePromise<string[]>(createSMembers(key)).then(Set<string>::new);

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nope 😕

@@ -102,7 +102,14 @@ export class RedisClient extends BaseClient {
* If the transaction failed due to a WATCH command, `exec` will return `null`.
*/
public exec(transaction: Transaction): Promise<ReturnType[] | null> {
return this.createWritePromise(transaction.commands);
return this.createWritePromise<ReturnType[] | null>(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be there set as a return type too?

Copy link
Collaborator Author

@shohamazon shohamazon May 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is, I didnt see that before

node/src/RedisClusterClient.ts Show resolved Hide resolved
CHANGELOG.md Outdated
#### Fixes
* Python: Fix typing error "‘type’ object is not subscriptable" ([#1203](https://github.com/aws/glide-for-redis/pull/1203))
* Core: Fixed blocking commands to use the specified timeout from the command argument ([#1283](https://github.com/aws/glide-for-redis/pull/1283))

### Breaking Changes
* Node: Changed SMEMBERS and SPOP with count functions to return Set instead of string [] ([#1299](https://github.com/aws/glide-for-redis/pull/1299))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

string [] -> string[]
please use the functions' name and not the redis command name (SMEMBERS -> smembers, SPOP with count ->spopCount)

*/
protected addAndReturn(
command: redis_request.Command,
is_set: boolean = false,
Copy link
Collaborator

@barshaul barshaul May 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is_set -> shouldConvertToSet (note: nodejs naming convention is lowerCamelCase)

is_set: boolean = false,
): T {
if (is_set) {
// If the command is marked as a Set command, its index within the transaction is recorded for conversion.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The command's index within the transaction is saved for later conversion of its response to a Set type

Copy link
Collaborator

@barshaul barshaul left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see inline comments

@shohamazon shohamazon merged commit 279cfc9 into valkey-io:main May 7, 2024
12 checks passed
@shohamazon shohamazon deleted the node_sets branch May 7, 2024 12:02
tjzhang-BQ pushed a commit to Bit-Quill/valkey-glide that referenced this pull request May 8, 2024
cyip10 pushed a commit to Bit-Quill/valkey-glide that referenced this pull request Jun 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
node Node.js wrapper
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants