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

SET IFEQ command implemented in Java + tests #2978

Merged
merged 8 commits into from
Feb 3, 2025

Conversation

Maayanshani25
Copy link
Collaborator

@Maayanshani25 Maayanshani25 commented Jan 19, 2025

Issue link

This Pull Request is linked to issue (URL): [/issues/2811]

Description

This pull Request is implemented the IFEQ option in the SET commamnd. Tests were added, and docstring to the command and the related method.

Checklist

Before submitting the PR make sure the following are checked:

  • This Pull Request is related to one issue.
  • Commit message has a detailed description of what changed and why.
  • Tests are added or updated.
  • CHANGELOG.md and documentation files are updated.
  • Destination branch is correct - main or release
  • Create merge commit if merging release branch into main, squash otherwise.

@Maayanshani25 Maayanshani25 requested a review from a team as a code owner January 19, 2025 10:28
@Maayanshani25
Copy link
Collaborator Author

@Yury-Fridlyand
I found the implementation of java a bit different than node.
Do you think it's possible to this the also here? #2909 (comment)

@Yury-Fridlyand Yury-Fridlyand added the java issues and fixes related to the java client label Jan 20, 2025
@Yury-Fridlyand
Copy link
Collaborator

Yury-Fridlyand commented Jan 20, 2025

Java is not so flexible, unfortunately.
But it is still possible to do if you customize the setter in the SetOptions builder. Probably, you can keep exposed ConditionalSet with 2 options, but under the hood have another one with 3 options.
Need to be careful to avoid breaking changes while doing refactoring.
StandaloneSubscriptionConfigurationBuilder is a nice example of a customized builder.

@Maayanshani25
Copy link
Collaborator Author

Maayanshani25 commented Jan 22, 2025

So for now I see two options.

  1. The implementation I did in the pr for now. If the user chooses the conditionalSet ONLY_IF_EQUAL, it makes sure comparisonValue isnt null and push them both to the args.
    If comparisonValue is set but The condionalSet is not ONLY_IF_EQUAL, throws an error

  2. Removing ONLY_IF_EQUAL from conditionalSet options and use it this way:

if (conditionalSet != null) {
            optionArgs.add(conditionalSet.valkeyApi);
} else if (comparisonValue != null) {
            optionArgs.add("IFEQ", comparisonValue);

}

What do you think is better?

@Maayanshani25 Maayanshani25 force-pushed the ifeq-java branch 2 times, most recently from 5b73b9f to 97041b8 Compare January 23, 2025 19:45
@Maayanshani25
Copy link
Collaborator Author

@Yury-Fridlyand
Is it good? anything else or can you approve?

@Yury-Fridlyand
Copy link
Collaborator

LGTM, I applied minor doc updates. Need a second approval.

@ikolomi ikolomi self-requested a review January 28, 2025 09:33
@@ -223,6 +223,12 @@ public interface StringBaseCommands {
* String value = client.set("key", "value", options).get();
* assert value.equals("OK");
* }</pre>
* <pre>{@code
Copy link
Collaborator

Choose a reason for hiding this comment

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

Apparently addition of IFEQ out-dates the @return doc above.
Since it becomes complicated to explain all the implications introduced by the new options, perhaps the return doc string should only mention that the set options affect the return behavior. In case you prefer to keep the full explanation in the return doc, extend it with IFEQ

@@ -235,8 +241,9 @@ public interface StringBaseCommands {
* @param options The Set options.
* @return If the value is successfully set, return <code>"OK"</code>. If value isn't set because
* of {@link ConditionalSet#ONLY_IF_EXISTS} or {@link ConditionalSet#ONLY_IF_DOES_NOT_EXIST}
* conditions, return <code>null</code>. If {@link SetOptionsBuilder#returnOldValue(boolean)}
* is set, return the old value as a <code>String</code>.
* or {@link ConditionalSet#ONLY_IF_EQUAL} conditions, return <code>null</code>. If {@link
Copy link
Collaborator

Choose a reason for hiding this comment

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

same as above

@@ -49,11 +53,52 @@ public enum ConditionalSet {
* Only set the key if it does not already exist. Equivalent to <code>NX</code> in the Valkey
* API.
*/
ONLY_IF_DOES_NOT_EXIST("NX");
ONLY_IF_DOES_NOT_EXIST("NX"),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Here a confusion starts - are these mutual exclusive? You should doc it

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It's not possible for a key to both exist and not exist at the same time, so the user can specify only one condition. In the Valkey API, you can choose SET key value [NX | XX | IFEQ comparison-value].
There is no contradiction between the XX and IFEQ comparison-value conditions but in the API of valkey they chose to apply only one of them.
In Java, it's a bit complicated to enforce this. In Node.js, I created a new type to apply only one of the conditionals, but here it's a bit different. I think it's okay to use the format we did and as Yuri mentioned above:

SetOptions.builder().conditionalSetIfEqualTo("abc").conditionalSet(ONLY_IF_DOES_NOT_EXIST).build(); // should not fail
SetOptions.builder().conditionalSet(ONLY_IF_EQUAL).build(); // should fail

In this approach, the last condition set will be the one that applies.

@ikolomi what do you think?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we need to enforce the mutual exclusiveness by throwing from the builder's setters

* @param value The value to compare.
* @return This builder instance.
*/
public SetOptionsBuilder conditionalSetIfEqualTo(@NonNull String value) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I suspect we want these conditions to be mutual exclusive ? If so, we should enforce it by throwing

Copy link
Collaborator

Choose a reason for hiding this comment

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

``
public SetOptionsBuilder conditionalIfExistst() {
}

public SetOptionsBuilder conditionalIfNotExistst() {
}

public SetOptionsBuilder conditionalIfEqual(@nonnull String value) {
}
``

Lest the methods to override the current value + describe in the docs that the conditions are mutual exclusive

@ikolomi
Copy link
Collaborator

ikolomi commented Jan 28, 2025

@Maayanshani25 please dont forget to squash

@Maayanshani25 Maayanshani25 force-pushed the ifeq-java branch 2 times, most recently from 1becf23 to 9cecbad Compare January 29, 2025 09:15
Signed-off-by: Maayan Shani <[email protected]>
Signed-off-by: Maayan Shani <[email protected]>
* @param value The value to compare.
* @return This builder instance.
*/
public SetOptionsBuilder conditionalSetIfEqualTo(@NonNull String value) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

``
public SetOptionsBuilder conditionalIfExistst() {
}

public SetOptionsBuilder conditionalIfNotExistst() {
}

public SetOptionsBuilder conditionalIfEqual(@nonnull String value) {
}
``

Lest the methods to override the current value + describe in the docs that the conditions are mutual exclusive

@Maayanshani25 Maayanshani25 merged commit 7b77603 into valkey-io:main Feb 3, 2025
14 of 18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
java issues and fixes related to the java client
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants