Skip to content

Commit

Permalink
Support KEEPTTL via ValueOperations.
Browse files Browse the repository at this point in the history
  • Loading branch information
ykardziyaka committed Nov 14, 2023
1 parent 9eadebd commit 44a2ca9
Show file tree
Hide file tree
Showing 6 changed files with 242 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,15 @@ public Mono<Boolean> set(K key, V value, Duration timeout) {
stringCommands.set(rawKey(key), rawValue(value), Expiration.from(timeout), SetOption.UPSERT));
}

@Override
public Mono<Boolean> set(K key, V value, boolean keepTtl) {

Assert.notNull(key, "Key must not be null");

Expiration expiration = keepTtl ? Expiration.keepTtl() : Expiration.persistent();
return createMono(stringCommands -> stringCommands.set(rawKey(key), rawValue(value), expiration, SetOption.UPSERT));
}

@Override
public Mono<Boolean> setIfAbsent(K key, V value) {

Expand Down Expand Up @@ -115,6 +124,16 @@ public Mono<Boolean> setIfPresent(K key, V value, Duration timeout) {
stringCommands.set(rawKey(key), rawValue(value), Expiration.from(timeout), SetOption.SET_IF_PRESENT));
}

@Override
public Mono<Boolean> setIfPresent(K key, V value, boolean keepTtl) {

Assert.notNull(key, "Key must not be null");

Expiration expiration = keepTtl ? Expiration.keepTtl() : Expiration.persistent();
return createMono(
stringCommands -> stringCommands.set(rawKey(key), rawValue(value), expiration, SetOption.SET_IF_PRESENT));
}

@Override
public Mono<Boolean> multiSet(Map<? extends K, ? extends V> map) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,16 @@ private boolean failsafeInvokePsetEx(RedisConnection connection) {
});
}

@Override
public void set(K key, V value, boolean keepTtl) {

byte[] rawKey = rawKey(key);
byte[] rawValue = rawValue(value);

Expiration expiration = keepTtl ? Expiration.keepTtl() : Expiration.persistent();
execute(connection -> connection.set(rawKey, rawValue, expiration, SetOption.upsert()));
}

@Override
public Boolean setIfAbsent(K key, V value) {

Expand Down Expand Up @@ -320,6 +330,16 @@ public Boolean setIfPresent(K key, V value, long timeout, TimeUnit unit) {
return execute(connection -> connection.set(rawKey, rawValue, expiration, SetOption.ifPresent()));
}

@Override
public Boolean setIfPresent(K key, V value, boolean keepTtl) {

byte[] rawKey = rawKey(key);
byte[] rawValue = rawValue(value);

Expiration expiration = keepTtl ? Expiration.keepTtl() : Expiration.persistent();
return execute(connection -> connection.set(rawKey, rawValue, expiration, SetOption.ifPresent()));
}

@Override
public void set(K key, V value, long offset) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,16 @@ public interface ReactiveValueOperations<K, V> {
*/
Mono<Boolean> set(K key, V value, Duration timeout);

/**
* Set {@code value} for {@code key}.
*
* @param key must not be {@literal null}.
* @param value
* @param keepTtl whether to retain TTL associated with the key.
* @see <a href="https://redis.io/commands/set">Redis Documentation: SET</a>
*/
Mono<Boolean> set(K key, V value, boolean keepTtl);

/**
* Set {@code key} to hold the string {@code value} if {@code key} is absent.
*
Expand Down Expand Up @@ -98,6 +108,16 @@ public interface ReactiveValueOperations<K, V> {
*/
Mono<Boolean> setIfPresent(K key, V value, Duration timeout);

/**
* Set {@code key} to hold the string {@code value} if {@code key} is present.
*
* @param key must not be {@literal null}.
* @param value
* @param keepTtl whether to retain TTL associated with the key.
* @see <a href="https://redis.io/commands/set">Redis Documentation: SET</a>
*/
Mono<Boolean> setIfPresent(K key, V value, boolean keepTtl);

/**
* Set multiple keys to multiple values using key-value pairs provided in {@code tuple}.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,16 @@ default void set(K key, V value, Duration timeout) {
}
}

/**
* Set {@code value} for {@code key}.
*
* @param key must not be {@literal null}.
* @param value must not be {@literal null}.
* @param keepTtl whether to retain TTL associated with the key.
* @see <a href="https://redis.io/commands/set">Redis Documentation: SET</a>
*/
void set(K key, V value, boolean keepTtl);

/**
* Set {@code key} to hold the string {@code value} if {@code key} is absent.
*
Expand Down Expand Up @@ -175,6 +185,19 @@ default Boolean setIfPresent(K key, V value, Duration timeout) {
return setIfPresent(key, value, timeout.getSeconds(), TimeUnit.SECONDS);
}

/**
* Set {@code key} to hold the string {@code value} if {@code key} is present.
*
* @param key must not be {@literal null}.
* @param value must not be {@literal null}.
* @param keepTtl whether to retain TTL associated with the key.
* @return command result indicating if the key has been set.
* @throws IllegalArgumentException if either {@code key} or {@code value} is not present.
* @see <a href="https://redis.io/commands/set">Redis Documentation: SET</a>
*/
@Nullable
Boolean setIfPresent(K key, V value, boolean keepTtl);

/**
* Set multiple keys to multiple values using key-value pairs provided in {@code tuple}.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,50 @@ void set() {
valueOperations.get(key).as(StepVerifier::create).expectNext(value).verifyComplete();
}

@ParameterizedRedisTest // GH-2084
void setWithKeepTtl() {

K key = keyFactory.instance();
V value1 = valueFactory.instance();
V value2 = valueFactory.instance();

valueOperations.set(key, value1, Duration.ofMillis(5500)).as(StepVerifier::create) //
.expectNext(true) //
.verifyComplete();
valueOperations.set(key, value2, true).as(StepVerifier::create) //
.expectNext(true) //
.verifyComplete();

valueOperations.get(key).as(StepVerifier::create) //
.expectNext(value2) //
.verifyComplete();
redisTemplate.getExpire(key).as(StepVerifier::create) //
.assertNext(actual -> assertThat(actual).isBetween(Duration.ofMillis(1), Duration.ofSeconds(6))) //
.verifyComplete();
}

@ParameterizedRedisTest // GH-2084
void setWithoutKeepTtl() {

K key = keyFactory.instance();
V value1 = valueFactory.instance();
V value2 = valueFactory.instance();

valueOperations.set(key, value1, Duration.ofMillis(5500)).as(StepVerifier::create) //
.expectNext(true) //
.verifyComplete();
valueOperations.set(key, value2, false).as(StepVerifier::create) //
.expectNext(true) //
.verifyComplete();

valueOperations.get(key).as(StepVerifier::create) //
.expectNext(value2) //
.verifyComplete();
redisTemplate.getExpire(key).as(StepVerifier::create) //
.assertNext(actual -> assertThat(actual).isZero()) //
.verifyComplete();
}

@ParameterizedRedisTest // DATAREDIS-602
void setWithExpiry() {

Expand Down Expand Up @@ -186,6 +230,58 @@ void setIfPresentWithExpiry() {
}).verifyComplete();
}

@ParameterizedRedisTest // GH-2084
void setIfPresentWithKeepTtl() {

K key = keyFactory.instance();
V value1 = valueFactory.instance();
V value2 = valueFactory.instance();

valueOperations.setIfPresent(key, value1, true).as(StepVerifier::create) //
.expectNext(false) //
.verifyComplete();
valueOperations.set(key, value1, Duration.ofMillis(5500)).as(StepVerifier::create) //
.expectNext(true) //
.verifyComplete();

valueOperations.setIfPresent(key, value2, true).as(StepVerifier::create) //
.expectNext(true) //
.verifyComplete();

valueOperations.get(key).as(StepVerifier::create) //
.expectNext(value2) //
.verifyComplete();
redisTemplate.getExpire(key).as(StepVerifier::create) //
.assertNext(actual -> assertThat(actual).isBetween(Duration.ofMillis(1), Duration.ofSeconds(6))) //
.verifyComplete();
}

@ParameterizedRedisTest // GH-2084
void setIfPresentWithoutKeepTtl() {

K key = keyFactory.instance();
V value1 = valueFactory.instance();
V value2 = valueFactory.instance();

valueOperations.setIfPresent(key, value1, false).as(StepVerifier::create) //
.expectNext(false) //
.verifyComplete();
valueOperations.set(key, value1, Duration.ofMillis(5500)).as(StepVerifier::create) //
.expectNext(true) //
.verifyComplete();

valueOperations.setIfPresent(key, value2, false).as(StepVerifier::create) //
.expectNext(true) //
.verifyComplete();

valueOperations.get(key).as(StepVerifier::create) //
.expectNext(value2) //
.verifyComplete();
redisTemplate.getExpire(key).as(StepVerifier::create) //
.assertNext(actual -> assertThat(actual).isZero()) //
.verifyComplete();
}

@ParameterizedRedisTest // DATAREDIS-602
void multiSet() {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,37 @@ void testSetWithExpirationWithTimeUnitMilliseconds() {
await().atMost(Duration.ofMillis(500L)).until(() -> !redisTemplate.hasKey(key));
}

@ParameterizedRedisTest // GH-2084
void testSetWithKeepTtl() {

K key = keyFactory.instance();
V value1 = valueFactory.instance();
V value2 = valueFactory.instance();

valueOps.set(key, value1, Duration.ofMillis(5500));
valueOps.set(key, value2, true);

Long expire = redisTemplate.getExpire(key, TimeUnit.MILLISECONDS);

assertThat(valueOps.get(key)).isEqualTo(value2);
assertThat(expire).isLessThan(TimeUnit.SECONDS.toMillis(6));
assertThat(expire).isGreaterThan(TimeUnit.MILLISECONDS.toMillis(1));
}

@ParameterizedRedisTest // GH-2084
void testSetWithoutKeepTtl() {

K key = keyFactory.instance();
V value1 = valueFactory.instance();
V value2 = valueFactory.instance();

valueOps.set(key, value1, Duration.ofMillis(5500));
valueOps.set(key, value2, false);

assertThat(valueOps.get(key)).isEqualTo(value2);
assertThat(redisTemplate.getExpire(key)).isEqualTo(-1);
}

@ParameterizedRedisTest
void testAppend() {

Expand Down Expand Up @@ -483,6 +514,39 @@ void testSetIfPresentWithExpirationPX() {
assertThat(valueOps.get(key)).isEqualTo(value2);
}

@ParameterizedRedisTest // GH-2084
void testSetIfPresentWithKeepTtl() {

K key = keyFactory.instance();
V value1 = valueFactory.instance();
V value2 = valueFactory.instance();

assertThat(valueOps.setIfPresent(key, value1, true)).isFalse();
valueOps.set(key, value1, Duration.ofMillis(5500));

Long expire = redisTemplate.getExpire(key, TimeUnit.MILLISECONDS);

assertThat(valueOps.setIfPresent(key, value2, true)).isTrue();
assertThat(valueOps.get(key)).isEqualTo(value2);
assertThat(expire).isLessThan(TimeUnit.SECONDS.toMillis(6));
assertThat(expire).isGreaterThan(TimeUnit.MILLISECONDS.toMillis(1));
}

@ParameterizedRedisTest // GH-2084
void testSetIfPresentWithoutKeepTtl() {

K key = keyFactory.instance();
V value1 = valueFactory.instance();
V value2 = valueFactory.instance();

assertThat(valueOps.setIfPresent(key, value1, false)).isFalse();
valueOps.set(key, value1, Duration.ofMillis(5500));

assertThat(valueOps.setIfPresent(key, value2, false)).isTrue();
assertThat(valueOps.get(key)).isEqualTo(value2);
assertThat(redisTemplate.getExpire(key)).isEqualTo(-1);
}

@ParameterizedRedisTest
void testSize() {

Expand Down

0 comments on commit 44a2ca9

Please sign in to comment.