-
Notifications
You must be signed in to change notification settings - Fork 71
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
Changes from all commits
77fcf48
d115329
5b172ce
6e66667
137425d
2757f2d
05cd90a
2926889
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -215,14 +215,21 @@ 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 | ||
* SetOptionsBuilder#returnOldValue(boolean)} is set, return the old value as a <code>String | ||
* </code>. | ||
* @example | ||
* <pre>{@code | ||
* SetOptions options = SetOptions.builder().conditionalSet(ONLY_IF_EXISTS).expiry(Seconds(5L)).build(); | ||
* SetOptions options = SetOptions.builder().conditionalSetOnlyIfExists().expiry(Seconds(5L)).build(); | ||
* String value = client.set("key", "value", options).get(); | ||
* assert value.equals("OK"); | ||
* }</pre> | ||
* <pre>{@code | ||
* client.set("key", "value").get(); | ||
* SetOptions options = SetOptions.builder().conditionalSetIfEqualTo("value").build(); | ||
* String value = client.set("key", "newValue", options).get(); | ||
* assert value.equals("OK"); | ||
* }</pre> | ||
*/ | ||
CompletableFuture<String> set(String key, String value, SetOptions options); | ||
|
||
|
@@ -235,8 +242,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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same as above |
||
* SetOptionsBuilder#returnOldValue(boolean)} is set, return the old value as a <code>String | ||
* </code>. | ||
* @example | ||
* <pre>{@code | ||
* SetOptions options = SetOptions.builder().conditionalSet(ONLY_IF_EXISTS).expiry(Seconds(5L)).build(); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,7 @@ | |
import java.util.List; | ||
import lombok.Builder; | ||
import lombok.Getter; | ||
import lombok.NonNull; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
/** | ||
|
@@ -29,6 +30,9 @@ public final class SetOptions { | |
*/ | ||
private final ConditionalSet conditionalSet; | ||
|
||
/** Value to compare when {@link ConditionalSet#ONLY_IF_EQUAL} is set. */ | ||
private final String comparisonValue; | ||
|
||
/** | ||
* Set command to return the old string stored at <code>key</code>, or <code>null</code> if <code> | ||
* key</code> did not exist. An error is returned and <code>SET</code> aborted if the value stored | ||
|
@@ -49,11 +53,71 @@ 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"), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here a confusion starts - are these mutual exclusive? You should doc it There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 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? There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||
/** | ||
* Only set the key if the current value of key equals the {@link SetOptions#comparisonValue}. | ||
* Equivalent to <code>IFEQ comparison-value</code> in the Valkey API. | ||
*/ | ||
ONLY_IF_EQUAL("IFEQ"); | ||
|
||
private final String valkeyApi; | ||
} | ||
|
||
/** | ||
* Builder class for {@link SetOptions}. | ||
* | ||
* <p>Provides methods to set conditions under which a value should be set. | ||
* | ||
* <p>Note: Calling any of these methods will override the existing values of {@code | ||
* conditionalSet} and {@code comparisonValue}, if they are already set. | ||
*/ | ||
public static class SetOptionsBuilder { | ||
/** | ||
Maayanshani25 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* Sets the condition to {@link ConditionalSet#ONLY_IF_EXISTS} for setting the value. | ||
* | ||
* <p>This method overrides any previously set {@code conditionalSet} and {@code | ||
* comparisonValue}. | ||
* | ||
* @return This builder instance | ||
*/ | ||
public SetOptionsBuilder conditionalSetOnlyIfExists() { | ||
this.conditionalSet = ConditionalSet.ONLY_IF_EXISTS; | ||
this.comparisonValue = null; | ||
return this; | ||
} | ||
|
||
/** | ||
* Sets the condition to {@link ConditionalSet#ONLY_IF_DOES_NOT_EXIST} for setting the value. | ||
* | ||
* <p>This method overrides any previously set {@code conditionalSet} and {@code | ||
* comparisonValue}. | ||
* | ||
* @return This builder instance | ||
*/ | ||
public SetOptionsBuilder conditionalSetOnlyIfNotExist() { | ||
this.conditionalSet = ConditionalSet.ONLY_IF_DOES_NOT_EXIST; | ||
this.comparisonValue = null; | ||
return this; | ||
} | ||
|
||
/** | ||
* Sets the condition to {@link ConditionalSet#ONLY_IF_EQUAL} for setting the value. The key | ||
* will be set if the provided comparison value matches the existing value. | ||
* | ||
* <p>This method overrides any previously set {@code conditionalSet} and {@code | ||
* comparisonValue}. | ||
* | ||
* @since Valkey 8.1 and above. | ||
* @param value the value to compare | ||
* @return this builder instance | ||
*/ | ||
public SetOptionsBuilder conditionalSetOnlyIfEqualTo(@NonNull String value) { | ||
this.conditionalSet = ConditionalSet.ONLY_IF_EQUAL; | ||
this.comparisonValue = value; | ||
return this; | ||
} | ||
} | ||
|
||
/** Configuration of value lifetime. */ | ||
public static final class Expiry { | ||
|
||
|
@@ -151,6 +215,9 @@ public String[] toArgs() { | |
List<String> optionArgs = new ArrayList<>(); | ||
if (conditionalSet != null) { | ||
optionArgs.add(conditionalSet.valkeyApi); | ||
if (conditionalSet == ConditionalSet.ONLY_IF_EQUAL) { | ||
optionArgs.add(comparisonValue); | ||
} | ||
} | ||
|
||
if (returnOldValue) { | ||
|
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.
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