Add support for conditional key expiry (XX/NX/LT/GT).
Move ExpirationOptions from Hash to top-level. Closes: #3114 Original Pull Request: #3115
This commit is contained in:
committed by
Christoph Strobl
parent
08d66aa10d
commit
b8d289208e
@@ -31,7 +31,6 @@ import org.springframework.data.geo.GeoResults;
|
||||
import org.springframework.data.geo.Metric;
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.data.redis.RedisSystemException;
|
||||
import org.springframework.data.redis.connection.Hash.FieldExpirationOptions;
|
||||
import org.springframework.data.redis.connection.convert.Converters;
|
||||
import org.springframework.data.redis.connection.convert.ListConverter;
|
||||
import org.springframework.data.redis.connection.convert.MapConverter;
|
||||
@@ -359,13 +358,13 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean expire(byte[] key, long seconds) {
|
||||
return convertAndReturn(delegate.expire(key, seconds), Converters.identityConverter());
|
||||
public Boolean expire(byte[] key, long seconds, ExpirationOptions.Condition condition) {
|
||||
return convertAndReturn(delegate.expire(key, seconds, condition), Converters.identityConverter());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean expireAt(byte[] key, long unixTime) {
|
||||
return convertAndReturn(delegate.expireAt(key, unixTime), Converters.identityConverter());
|
||||
public Boolean expireAt(byte[] key, long unixTime, ExpirationOptions.Condition condition) {
|
||||
return convertAndReturn(delegate.expireAt(key, unixTime, condition), Converters.identityConverter());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1308,13 +1307,13 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean pExpire(byte[] key, long millis) {
|
||||
return convertAndReturn(delegate.pExpire(key, millis), Converters.identityConverter());
|
||||
public Boolean pExpire(byte[] key, long millis, ExpirationOptions.Condition condition) {
|
||||
return convertAndReturn(delegate.pExpire(key, millis, condition), Converters.identityConverter());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean pExpireAt(byte[] key, long unixTimeInMillis) {
|
||||
return convertAndReturn(delegate.pExpireAt(key, unixTimeInMillis), Converters.identityConverter());
|
||||
public Boolean pExpireAt(byte[] key, long unixTimeInMillis, ExpirationOptions.Condition condition) {
|
||||
return convertAndReturn(delegate.pExpireAt(key, unixTimeInMillis, condition), Converters.identityConverter());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1497,13 +1496,13 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean expire(String key, long seconds) {
|
||||
return expire(serialize(key), seconds);
|
||||
public Boolean expire(String key, long seconds, ExpirationOptions.Condition condition) {
|
||||
return expire(serialize(key), seconds, condition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean expireAt(String key, long unixTime) {
|
||||
return expireAt(serialize(key), unixTime);
|
||||
public Boolean expireAt(String key, long unixTime, ExpirationOptions.Condition condition) {
|
||||
return expireAt(serialize(key), unixTime, condition);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -2491,13 +2490,13 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean pExpire(String key, long millis) {
|
||||
return pExpire(serialize(key), millis);
|
||||
public Boolean pExpire(String key, long millis, ExpirationOptions.Condition condition) {
|
||||
return pExpire(serialize(key), millis, condition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean pExpireAt(String key, long unixTimeInMillis) {
|
||||
return pExpireAt(serialize(key), unixTimeInMillis);
|
||||
public Boolean pExpireAt(String key, long unixTimeInMillis, ExpirationOptions.Condition condition) {
|
||||
return pExpireAt(serialize(key), unixTimeInMillis, condition);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -2581,29 +2580,29 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco
|
||||
return convertAndReturn(delegate.hStrLen(key, field), Converters.identityConverter());
|
||||
}
|
||||
|
||||
public @Nullable List<Long> applyExpiration(byte[] key,
|
||||
public @Nullable List<Long> applyHashFieldExpiration(byte[] key,
|
||||
org.springframework.data.redis.core.types.Expiration expiration,
|
||||
FieldExpirationOptions options, byte[]... fields) {
|
||||
return this.delegate.applyExpiration(key, expiration, options, fields);
|
||||
ExpirationOptions options, byte[]... fields) {
|
||||
return this.delegate.applyHashFieldExpiration(key, expiration, options, fields);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> hExpire(byte[] key, long seconds, FieldExpirationOptions.Condition condition, byte[]... fields) {
|
||||
public List<Long> hExpire(byte[] key, long seconds, ExpirationOptions.Condition condition, byte[]... fields) {
|
||||
return this.delegate.hExpire(key, seconds, condition, fields);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> hpExpire(byte[] key, long millis, FieldExpirationOptions.Condition condition, byte[]... fields) {
|
||||
public List<Long> hpExpire(byte[] key, long millis, ExpirationOptions.Condition condition, byte[]... fields) {
|
||||
return this.delegate.hpExpire(key, millis, condition, fields);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> hExpireAt(byte[] key, long unixTime, FieldExpirationOptions.Condition condition, byte[]... fields) {
|
||||
public List<Long> hExpireAt(byte[] key, long unixTime, ExpirationOptions.Condition condition, byte[]... fields) {
|
||||
return this.delegate.hExpireAt(key, unixTime, condition, fields);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> hpExpireAt(byte[] key, long unixTimeInMillis, FieldExpirationOptions.Condition condition,
|
||||
public List<Long> hpExpireAt(byte[] key, long unixTimeInMillis, ExpirationOptions.Condition condition,
|
||||
byte[]... fields) {
|
||||
return this.delegate.hpExpireAt(key, unixTimeInMillis, condition, fields);
|
||||
}
|
||||
@@ -2630,27 +2629,27 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco
|
||||
|
||||
public @Nullable List<Long> applyExpiration(String key,
|
||||
org.springframework.data.redis.core.types.Expiration expiration,
|
||||
FieldExpirationOptions options, String... fields) {
|
||||
return applyExpiration(serialize(key), expiration, options, serializeMulti(fields));
|
||||
ExpirationOptions options, String... fields) {
|
||||
return this.applyHashFieldExpiration(serialize(key), expiration, options, serializeMulti(fields));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> hExpire(String key, long seconds, FieldExpirationOptions.Condition condition, String... fields) {
|
||||
public List<Long> hExpire(String key, long seconds, ExpirationOptions.Condition condition, String... fields) {
|
||||
return hExpire(serialize(key), seconds, condition, serializeMulti(fields));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> hpExpire(String key, long millis, FieldExpirationOptions.Condition condition, String... fields) {
|
||||
public List<Long> hpExpire(String key, long millis, ExpirationOptions.Condition condition, String... fields) {
|
||||
return hpExpire(serialize(key), millis, condition, serializeMulti(fields));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> hExpireAt(String key, long unixTime, FieldExpirationOptions.Condition condition, String... fields) {
|
||||
public List<Long> hExpireAt(String key, long unixTime, ExpirationOptions.Condition condition, String... fields) {
|
||||
return hExpireAt(serialize(key), unixTime, condition, serializeMulti(fields));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> hpExpireAt(String key, long unixTimeInMillis, FieldExpirationOptions.Condition condition,
|
||||
public List<Long> hpExpireAt(String key, long unixTimeInMillis, ExpirationOptions.Condition condition,
|
||||
String... fields) {
|
||||
return hpExpireAt(serialize(key), unixTimeInMillis, condition, serializeMulti(fields));
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ import org.springframework.data.geo.Distance;
|
||||
import org.springframework.data.geo.GeoResults;
|
||||
import org.springframework.data.geo.Metric;
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.data.redis.connection.Hash.FieldExpirationOptions;
|
||||
import org.springframework.data.redis.connection.stream.ByteRecord;
|
||||
import org.springframework.data.redis.connection.stream.Consumer;
|
||||
import org.springframework.data.redis.connection.stream.MapRecord;
|
||||
@@ -162,7 +161,14 @@ public interface DefaultedRedisConnection extends RedisCommands, RedisCommandsPr
|
||||
@Override
|
||||
@Deprecated
|
||||
default Boolean expire(byte[] key, long seconds) {
|
||||
return keyCommands().expire(key, seconds);
|
||||
return keyCommands().expire(key, seconds, ExpirationOptions.Condition.ALWAYS);
|
||||
}
|
||||
|
||||
/** @deprecated in favor of {@link RedisConnection#keyCommands()}. */
|
||||
@Override
|
||||
@Deprecated
|
||||
default Boolean expire(byte[] key, long seconds, ExpirationOptions.Condition condition) {
|
||||
return keyCommands().expire(key, seconds, condition);
|
||||
}
|
||||
|
||||
/** @deprecated in favor of {@link RedisConnection#keyCommands()}. */
|
||||
@@ -204,21 +210,42 @@ public interface DefaultedRedisConnection extends RedisCommands, RedisCommandsPr
|
||||
@Override
|
||||
@Deprecated
|
||||
default Boolean pExpire(byte[] key, long millis) {
|
||||
return keyCommands().pExpire(key, millis);
|
||||
return keyCommands().pExpire(key, millis, ExpirationOptions.Condition.ALWAYS);
|
||||
}
|
||||
|
||||
/** @deprecated in favor of {@link RedisConnection#keyCommands()}. */
|
||||
@Override
|
||||
@Deprecated
|
||||
default Boolean pExpire(byte[] key, long millis, ExpirationOptions.Condition condition) {
|
||||
return keyCommands().pExpire(key, millis, condition);
|
||||
}
|
||||
|
||||
/** @deprecated in favor of {@link RedisConnection#keyCommands()}. */
|
||||
@Override
|
||||
@Deprecated
|
||||
default Boolean pExpireAt(byte[] key, long unixTimeInMillis) {
|
||||
return keyCommands().pExpireAt(key, unixTimeInMillis);
|
||||
return keyCommands().pExpireAt(key, unixTimeInMillis, ExpirationOptions.Condition.ALWAYS);
|
||||
}
|
||||
|
||||
/** @deprecated in favor of {@link RedisConnection#keyCommands()}. */
|
||||
@Override
|
||||
@Deprecated
|
||||
default Boolean pExpireAt(byte[] key, long unixTimeInMillis, ExpirationOptions.Condition condition) {
|
||||
return keyCommands().pExpireAt(key, unixTimeInMillis, condition);
|
||||
}
|
||||
|
||||
/** @deprecated in favor of {@link RedisConnection#keyCommands()}. */
|
||||
@Override
|
||||
@Deprecated
|
||||
default Boolean expireAt(byte[] key, long unixTime) {
|
||||
return keyCommands().expireAt(key, unixTime);
|
||||
return keyCommands().expireAt(key, unixTime, ExpirationOptions.Condition.ALWAYS);
|
||||
}
|
||||
|
||||
/** @deprecated in favor of {@link RedisConnection#keyCommands()}. */
|
||||
@Override
|
||||
@Deprecated
|
||||
default Boolean expireAt(byte[] key, long unixTime, ExpirationOptions.Condition condition) {
|
||||
return keyCommands().expireAt(key, unixTime, condition);
|
||||
}
|
||||
|
||||
/** @deprecated in favor of {@link RedisConnection#keyCommands()}. */
|
||||
@@ -1483,13 +1510,13 @@ public interface DefaultedRedisConnection extends RedisCommands, RedisCommandsPr
|
||||
@Override
|
||||
@Deprecated
|
||||
default List<Long> hExpire(byte[] key, long seconds, byte[]... fields) {
|
||||
return hashCommands().hExpire(key, seconds, FieldExpirationOptions.Condition.ALWAYS, fields);
|
||||
return hashCommands().hExpire(key, seconds, ExpirationOptions.Condition.ALWAYS, fields);
|
||||
}
|
||||
|
||||
/** @deprecated in favor of {@link RedisConnection#hashCommands()}}. */
|
||||
@Override
|
||||
@Deprecated
|
||||
default List<Long> hExpire(byte[] key, long seconds, FieldExpirationOptions.Condition condition, byte[]... fields) {
|
||||
default List<Long> hExpire(byte[] key, long seconds, ExpirationOptions.Condition condition, byte[]... fields) {
|
||||
return hashCommands().hExpire(key, seconds, condition, fields);
|
||||
}
|
||||
|
||||
@@ -1497,13 +1524,13 @@ public interface DefaultedRedisConnection extends RedisCommands, RedisCommandsPr
|
||||
@Override
|
||||
@Deprecated
|
||||
default List<Long> hpExpire(byte[] key, long millis, byte[]... fields) {
|
||||
return hashCommands().hpExpire(key, millis, FieldExpirationOptions.Condition.ALWAYS, fields);
|
||||
return hashCommands().hpExpire(key, millis, ExpirationOptions.Condition.ALWAYS, fields);
|
||||
}
|
||||
|
||||
/** @deprecated in favor of {@link RedisConnection#hashCommands()}}. */
|
||||
@Override
|
||||
@Deprecated
|
||||
default List<Long> hpExpire(byte[] key, long millis, FieldExpirationOptions.Condition condition, byte[]... fields) {
|
||||
default List<Long> hpExpire(byte[] key, long millis, ExpirationOptions.Condition condition, byte[]... fields) {
|
||||
return hashCommands().hpExpire(key, millis, condition, fields);
|
||||
}
|
||||
|
||||
@@ -1511,13 +1538,13 @@ public interface DefaultedRedisConnection extends RedisCommands, RedisCommandsPr
|
||||
@Override
|
||||
@Deprecated
|
||||
default List<Long> hExpireAt(byte[] key, long unixTime, byte[]... fields) {
|
||||
return hashCommands().hExpireAt(key, unixTime, FieldExpirationOptions.Condition.ALWAYS, fields);
|
||||
return hashCommands().hExpireAt(key, unixTime, ExpirationOptions.Condition.ALWAYS, fields);
|
||||
}
|
||||
|
||||
/** @deprecated in favor of {@link RedisConnection#hashCommands()}}. */
|
||||
@Override
|
||||
@Deprecated
|
||||
default List<Long> hExpireAt(byte[] key, long unixTime, FieldExpirationOptions.Condition condition,
|
||||
default List<Long> hExpireAt(byte[] key, long unixTime, ExpirationOptions.Condition condition,
|
||||
byte[]... fields) {
|
||||
return hashCommands().hExpireAt(key, unixTime, condition, fields);
|
||||
}
|
||||
@@ -1526,13 +1553,13 @@ public interface DefaultedRedisConnection extends RedisCommands, RedisCommandsPr
|
||||
@Override
|
||||
@Deprecated
|
||||
default List<Long> hpExpireAt(byte[] key, long unixTimeInMillis, byte[]... fields) {
|
||||
return hashCommands().hpExpireAt(key, unixTimeInMillis, FieldExpirationOptions.Condition.ALWAYS, fields);
|
||||
return hashCommands().hpExpireAt(key, unixTimeInMillis, ExpirationOptions.Condition.ALWAYS, fields);
|
||||
}
|
||||
|
||||
/** @deprecated in favor of {@link RedisConnection#hashCommands()}}. */
|
||||
@Override
|
||||
@Deprecated
|
||||
default List<Long> hpExpireAt(byte[] key, long unixTimeInMillis, FieldExpirationOptions.Condition condition,
|
||||
default List<Long> hpExpireAt(byte[] key, long unixTimeInMillis, ExpirationOptions.Condition condition,
|
||||
byte[]... fields) {
|
||||
return hashCommands().hpExpireAt(key, unixTimeInMillis, condition, fields);
|
||||
}
|
||||
@@ -1568,10 +1595,10 @@ public interface DefaultedRedisConnection extends RedisCommands, RedisCommandsPr
|
||||
/** @deprecated in favor of {@link RedisConnection#hashCommands()}}. */
|
||||
@Override
|
||||
@Deprecated
|
||||
default @Nullable List<Long> applyExpiration(byte[] key,
|
||||
org.springframework.data.redis.core.types.Expiration expiration, FieldExpirationOptions options,
|
||||
default @Nullable List<Long> applyHashFieldExpiration(byte[] key,
|
||||
org.springframework.data.redis.core.types.Expiration expiration, ExpirationOptions options,
|
||||
byte[]... fields) {
|
||||
return hashCommands().applyExpiration(key, expiration, options, fields);
|
||||
return hashCommands().applyHashFieldExpiration(key, expiration, options, fields);
|
||||
}
|
||||
|
||||
// GEO COMMANDS
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright 2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.redis.connection;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import org.springframework.lang.Contract;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Expiration options for Expiation updates.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
* @since 3.5
|
||||
*/
|
||||
public class ExpirationOptions {
|
||||
|
||||
private static final ExpirationOptions NONE = new ExpirationOptions(Condition.ALWAYS);
|
||||
private final Condition condition;
|
||||
|
||||
ExpirationOptions(Condition condition) {
|
||||
this.condition = condition;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an empty expiration options object.
|
||||
*/
|
||||
public static ExpirationOptions none() {
|
||||
return NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return builder for creating {@code FieldExpireOptionsBuilder}.
|
||||
*/
|
||||
public static FieldExpireOptionsBuilder builder() {
|
||||
return new FieldExpireOptionsBuilder();
|
||||
}
|
||||
|
||||
public Condition getCondition() {
|
||||
return condition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
ExpirationOptions that = (ExpirationOptions) o;
|
||||
return ObjectUtils.nullSafeEquals(this.condition, that.condition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(condition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder to build {@link ExpirationOptions}
|
||||
*/
|
||||
public static class FieldExpireOptionsBuilder {
|
||||
|
||||
private Condition condition = Condition.ALWAYS;
|
||||
|
||||
private FieldExpireOptionsBuilder() {}
|
||||
|
||||
@Contract("-> this")
|
||||
public FieldExpireOptionsBuilder nx() {
|
||||
this.condition = Condition.NX;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Contract("-> this")
|
||||
public FieldExpireOptionsBuilder xx() {
|
||||
this.condition = Condition.XX;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Contract("-> this")
|
||||
public FieldExpireOptionsBuilder gt() {
|
||||
this.condition = Condition.GT;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Contract("-> this")
|
||||
public FieldExpireOptionsBuilder lt() {
|
||||
this.condition = Condition.LT;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ExpirationOptions build() {
|
||||
return condition == Condition.ALWAYS ? NONE : new ExpirationOptions(condition);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Conditions to apply when changing expiration.
|
||||
*/
|
||||
public enum Condition {
|
||||
|
||||
/**
|
||||
* Always apply expiration.
|
||||
*/
|
||||
ALWAYS,
|
||||
|
||||
/**
|
||||
* Set expiration only when the field has no expiration.
|
||||
*/
|
||||
NX,
|
||||
|
||||
/**
|
||||
* Set expiration only when the field has an existing expiration.
|
||||
*/
|
||||
XX,
|
||||
|
||||
/**
|
||||
* Set expiration only when the new expiration is greater than current one.
|
||||
*/
|
||||
GT,
|
||||
|
||||
/**
|
||||
* Set expiration only when the new expiration is greater than current one.
|
||||
*/
|
||||
LT
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
/*
|
||||
* Copyright 2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.redis.connection;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import org.springframework.lang.Contract;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Types for interacting with Hash data structures.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 3.5
|
||||
*/
|
||||
public interface Hash {
|
||||
|
||||
/**
|
||||
* Expiration options for Hash Expiation updates.
|
||||
*/
|
||||
class FieldExpirationOptions {
|
||||
|
||||
private static final FieldExpirationOptions NONE = new FieldExpirationOptions(Condition.ALWAYS);
|
||||
private final Condition condition;
|
||||
|
||||
FieldExpirationOptions(Condition condition) {
|
||||
this.condition = condition;
|
||||
}
|
||||
|
||||
public static FieldExpirationOptions none() {
|
||||
return NONE;
|
||||
}
|
||||
|
||||
public static FieldExpireOptionsBuilder builder() {
|
||||
return new FieldExpireOptionsBuilder();
|
||||
}
|
||||
|
||||
public Condition getCondition() {
|
||||
return condition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
FieldExpirationOptions that = (FieldExpirationOptions) o;
|
||||
return ObjectUtils.nullSafeEquals(this.condition, that.condition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(condition);
|
||||
}
|
||||
|
||||
public static class FieldExpireOptionsBuilder {
|
||||
|
||||
private Condition condition = Condition.ALWAYS;
|
||||
|
||||
@Contract("-> this")
|
||||
public FieldExpireOptionsBuilder nx() {
|
||||
this.condition = Condition.NX;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Contract("-> this")
|
||||
public FieldExpireOptionsBuilder xx() {
|
||||
this.condition = Condition.XX;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Contract("-> this")
|
||||
public FieldExpireOptionsBuilder gt() {
|
||||
this.condition = Condition.GT;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Contract("-> this")
|
||||
public FieldExpireOptionsBuilder lt() {
|
||||
this.condition = Condition.LT;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FieldExpirationOptions build() {
|
||||
return condition == Condition.ALWAYS ? NONE : new FieldExpirationOptions(condition);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public enum Condition {
|
||||
|
||||
/**
|
||||
* Always apply expiration.
|
||||
*/
|
||||
ALWAYS,
|
||||
|
||||
/**
|
||||
* Set expiration only when the field has no expiration.
|
||||
*/
|
||||
NX,
|
||||
|
||||
/**
|
||||
* Set expiration only when the field has an existing expiration.
|
||||
*/
|
||||
XX,
|
||||
|
||||
/**
|
||||
* Set expiration only when the new expiration is greater than current one.
|
||||
*/
|
||||
GT,
|
||||
|
||||
/**
|
||||
* Set expiration only when the new expiration is greater than current one.
|
||||
*/
|
||||
LT
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -31,7 +31,6 @@ import java.util.function.Function;
|
||||
|
||||
import org.reactivestreams.Publisher;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.redis.connection.Hash.FieldExpirationOptions;
|
||||
import org.springframework.data.redis.connection.ReactiveRedisConnection.BooleanResponse;
|
||||
import org.springframework.data.redis.connection.ReactiveRedisConnection.Command;
|
||||
import org.springframework.data.redis.connection.ReactiveRedisConnection.CommandResponse;
|
||||
@@ -851,13 +850,13 @@ public interface ReactiveHashCommands {
|
||||
/**
|
||||
* @since 3.5
|
||||
*/
|
||||
class ExpireCommand extends HashFieldsCommand {
|
||||
class HashExpireCommand extends HashFieldsCommand {
|
||||
|
||||
private final Expiration expiration;
|
||||
private final FieldExpirationOptions options;
|
||||
private final ExpirationOptions options;
|
||||
|
||||
private ExpireCommand(@Nullable ByteBuffer key, List<ByteBuffer> fields, Expiration expiration,
|
||||
FieldExpirationOptions options) {
|
||||
private HashExpireCommand(@Nullable ByteBuffer key, List<ByteBuffer> fields, Expiration expiration,
|
||||
ExpirationOptions options) {
|
||||
|
||||
super(key, fields);
|
||||
|
||||
@@ -866,52 +865,52 @@ public interface ReactiveHashCommands {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link ExpireCommand}.
|
||||
* Creates a new {@link HashExpireCommand}.
|
||||
*
|
||||
* @param fields the {@code field} names to apply expiration to
|
||||
* @param timeout the actual timeout
|
||||
* @param unit the unit of measure for the {@code timeout}.
|
||||
* @return new instance of {@link ExpireCommand}.
|
||||
* @return new instance of {@link HashExpireCommand}.
|
||||
*/
|
||||
public static ExpireCommand expire(List<ByteBuffer> fields, long timeout, TimeUnit unit) {
|
||||
public static HashExpireCommand expire(List<ByteBuffer> fields, long timeout, TimeUnit unit) {
|
||||
|
||||
Assert.notNull(fields, "Field must not be null");
|
||||
return expire(fields, Expiration.from(timeout, unit));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link ExpireCommand}.
|
||||
* Creates a new {@link HashExpireCommand}.
|
||||
*
|
||||
* @param fields the {@code field} names to apply expiration to.
|
||||
* @param ttl the actual timeout.
|
||||
* @return new instance of {@link ExpireCommand}.
|
||||
* @return new instance of {@link HashExpireCommand}.
|
||||
*/
|
||||
public static ExpireCommand expire(List<ByteBuffer> fields, Duration ttl) {
|
||||
public static HashExpireCommand expire(List<ByteBuffer> fields, Duration ttl) {
|
||||
|
||||
Assert.notNull(fields, "Field must not be null");
|
||||
return expire(fields, Expiration.from(ttl));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link ExpireCommand}.
|
||||
* Creates a new {@link HashExpireCommand}.
|
||||
*
|
||||
* @param fields the {@code field} names to apply expiration to
|
||||
* @param expiration the {@link Expiration} to apply to the given {@literal fields}.
|
||||
* @return new instance of {@link ExpireCommand}.
|
||||
* @return new instance of {@link HashExpireCommand}.
|
||||
*/
|
||||
public static ExpireCommand expire(List<ByteBuffer> fields, Expiration expiration) {
|
||||
return new ExpireCommand(null, fields, expiration, FieldExpirationOptions.none());
|
||||
public static HashExpireCommand expire(List<ByteBuffer> fields, Expiration expiration) {
|
||||
return new HashExpireCommand(null, fields, expiration, ExpirationOptions.none());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link ExpireCommand}.
|
||||
* Creates a new {@link HashExpireCommand}.
|
||||
*
|
||||
* @param fields the {@code field} names to apply expiration to
|
||||
* @param ttl the unix point in time when to expire the given {@literal fields}.
|
||||
* @param precision can be {@link TimeUnit#SECONDS} or {@link TimeUnit#MILLISECONDS}.
|
||||
* @return new instance of {@link ExpireCommand}.
|
||||
* @return new instance of {@link HashExpireCommand}.
|
||||
*/
|
||||
public static ExpireCommand expireAt(List<ByteBuffer> fields, Instant ttl, TimeUnit precision) {
|
||||
public static HashExpireCommand expireAt(List<ByteBuffer> fields, Instant ttl, TimeUnit precision) {
|
||||
|
||||
if (precision.compareTo(TimeUnit.MILLISECONDS) > 0) {
|
||||
return expire(fields, Expiration.unixTimestamp(ttl.getEpochSecond(), TimeUnit.SECONDS));
|
||||
@@ -922,25 +921,25 @@ public interface ReactiveHashCommands {
|
||||
|
||||
/**
|
||||
* @param key the {@literal key} from which to expire the {@literal fields} from.
|
||||
* @return new instance of {@link ExpireCommand}.
|
||||
* @return new instance of {@link HashExpireCommand}.
|
||||
*/
|
||||
public ExpireCommand from(ByteBuffer key) {
|
||||
return new ExpireCommand(key, getFields(), expiration, options);
|
||||
public HashExpireCommand from(ByteBuffer key) {
|
||||
return new HashExpireCommand(key, getFields(), expiration, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param options additional options to be sent along with the command.
|
||||
* @return new instance of {@link ExpireCommand}.
|
||||
* @return new instance of {@link HashExpireCommand}.
|
||||
*/
|
||||
public ExpireCommand withOptions(FieldExpirationOptions options) {
|
||||
return new ExpireCommand(getKey(), getFields(), getExpiration(), options);
|
||||
public HashExpireCommand withOptions(ExpirationOptions options) {
|
||||
return new HashExpireCommand(getKey(), getFields(), getExpiration(), options);
|
||||
}
|
||||
|
||||
public Expiration getExpiration() {
|
||||
return expiration;
|
||||
}
|
||||
|
||||
public FieldExpirationOptions getOptions() {
|
||||
public ExpirationOptions getOptions() {
|
||||
return options;
|
||||
}
|
||||
}
|
||||
@@ -983,7 +982,7 @@ public interface ReactiveHashCommands {
|
||||
|
||||
Assert.notNull(duration, "Duration must not be null");
|
||||
|
||||
return applyExpiration(Flux.just(ExpireCommand.expire(fields, duration).from(key)))
|
||||
return applyHashFieldExpiration(Flux.just(HashExpireCommand.expire(fields, duration).from(key)))
|
||||
.mapNotNull(NumericResponse::getOutput);
|
||||
}
|
||||
|
||||
@@ -999,7 +998,7 @@ public interface ReactiveHashCommands {
|
||||
* @since 3.5
|
||||
* @see <a href="https://redis.io/commands/hexpire">Redis Documentation: HEXPIRE</a>
|
||||
*/
|
||||
Flux<NumericResponse<ExpireCommand, Long>> applyExpiration(Publisher<ExpireCommand> commands);
|
||||
Flux<NumericResponse<HashExpireCommand, Long>> applyHashFieldExpiration(Publisher<HashExpireCommand> commands);
|
||||
|
||||
/**
|
||||
* Expire a given {@literal field} after a given {@link Duration} of time, measured in milliseconds, has passed.
|
||||
@@ -1039,8 +1038,8 @@ public interface ReactiveHashCommands {
|
||||
|
||||
Assert.notNull(duration, "Duration must not be null");
|
||||
|
||||
return applyExpiration(Flux.just(new ExpireCommand(key, fields,
|
||||
Expiration.from(duration.toMillis(), TimeUnit.MILLISECONDS), FieldExpirationOptions.none())))
|
||||
return applyHashFieldExpiration(Flux.just(new HashExpireCommand(key, fields,
|
||||
Expiration.from(duration.toMillis(), TimeUnit.MILLISECONDS), ExpirationOptions.none())))
|
||||
.mapNotNull(NumericResponse::getOutput);
|
||||
}
|
||||
|
||||
@@ -1083,7 +1082,7 @@ public interface ReactiveHashCommands {
|
||||
|
||||
Assert.notNull(expireAt, "Duration must not be null");
|
||||
|
||||
return applyExpiration(Flux.just(ExpireCommand.expireAt(fields, expireAt, TimeUnit.SECONDS).from(key)))
|
||||
return applyHashFieldExpiration(Flux.just(HashExpireCommand.expireAt(fields, expireAt, TimeUnit.SECONDS).from(key)))
|
||||
.mapNotNull(NumericResponse::getOutput);
|
||||
}
|
||||
|
||||
@@ -1126,7 +1125,8 @@ public interface ReactiveHashCommands {
|
||||
|
||||
Assert.notNull(expireAt, "Duration must not be null");
|
||||
|
||||
return applyExpiration(Flux.just(ExpireCommand.expireAt(fields, expireAt, TimeUnit.MILLISECONDS).from(key)))
|
||||
return applyHashFieldExpiration(
|
||||
Flux.just(HashExpireCommand.expireAt(fields, expireAt, TimeUnit.MILLISECONDS).from(key)))
|
||||
.mapNotNull(NumericResponse::getOutput);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.reactivestreams.Publisher;
|
||||
|
||||
import org.springframework.data.redis.connection.ReactiveRedisConnection.BooleanResponse;
|
||||
import org.springframework.data.redis.connection.ReactiveRedisConnection.CommandResponse;
|
||||
import org.springframework.data.redis.connection.ReactiveRedisConnection.KeyCommand;
|
||||
@@ -32,6 +33,7 @@ import org.springframework.data.redis.connection.ReactiveRedisConnection.MultiVa
|
||||
import org.springframework.data.redis.connection.ReactiveRedisConnection.NumericResponse;
|
||||
import org.springframework.data.redis.core.KeyScanOptions;
|
||||
import org.springframework.data.redis.core.ScanOptions;
|
||||
import org.springframework.data.redis.core.types.Expiration;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -513,13 +515,35 @@ public interface ReactiveKeyCommands {
|
||||
*/
|
||||
class ExpireCommand extends KeyCommand {
|
||||
|
||||
private @Nullable Duration timeout;
|
||||
private final Expiration expiration;
|
||||
private final ExpirationOptions options;
|
||||
|
||||
private ExpireCommand(ByteBuffer key, @Nullable Duration timeout) {
|
||||
private ExpireCommand(ByteBuffer key, Duration timeout) {
|
||||
this(key, Expiration.from(timeout), ExpirationOptions.none());
|
||||
}
|
||||
|
||||
private ExpireCommand(@Nullable ByteBuffer key, Expiration expiration, ExpirationOptions options) {
|
||||
|
||||
super(key);
|
||||
|
||||
this.timeout = timeout;
|
||||
this.expiration = expiration;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link ExpireCommand} given a {@link ByteBuffer key} and {@link Expiration}.
|
||||
*
|
||||
* @param key must not be {@literal null}.
|
||||
* @param expiration must not be {@literal null}.
|
||||
* @return a new {@link ExpireCommand} for {@link ByteBuffer key} and {@link Expiration}.
|
||||
* @since 3.5
|
||||
*/
|
||||
public static ExpireCommand expire(ByteBuffer key, Expiration expiration) {
|
||||
|
||||
Assert.notNull(key, "Key must not be null");
|
||||
Assert.notNull(expiration, "Expiration must not be null");
|
||||
|
||||
return new ExpireCommand(key, expiration, ExpirationOptions.none());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -532,7 +556,7 @@ public interface ReactiveKeyCommands {
|
||||
|
||||
Assert.notNull(key, "Key must not be null");
|
||||
|
||||
return new ExpireCommand(key, null);
|
||||
return new ExpireCommand(key, Expiration.persistent(), ExpirationOptions.none());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -545,7 +569,21 @@ public interface ReactiveKeyCommands {
|
||||
|
||||
Assert.notNull(timeout, "Timeout must not be null");
|
||||
|
||||
return new ExpireCommand(getKey(), timeout);
|
||||
return new ExpireCommand(getKey(), Expiration.from(timeout), options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the {@literal timeout}. Constructs a new command instance with all previously configured properties.
|
||||
*
|
||||
* @param timeout must not be {@literal null}.
|
||||
* @return a new {@link ExpireCommand} with {@literal timeout} applied.
|
||||
* @since 3.5
|
||||
*/
|
||||
public ExpireCommand expire(Duration timeout) {
|
||||
|
||||
Assert.notNull(timeout, "Timeout must not be null");
|
||||
|
||||
return new ExpireCommand(getKey(), Expiration.from(timeout), options);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -553,10 +591,50 @@ public interface ReactiveKeyCommands {
|
||||
*/
|
||||
@Nullable
|
||||
public Duration getTimeout() {
|
||||
return timeout;
|
||||
|
||||
if (expiration.isUnixTimestamp() || expiration.isPersistent()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Duration.ofMillis(expiration.getExpirationTimeInMilliseconds());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param options additional options to be sent along with the command.
|
||||
* @return new instance of {@link ExpireCommand}.
|
||||
* @since 3.5
|
||||
*/
|
||||
public ExpireCommand withOptions(ExpirationOptions options) {
|
||||
return new ExpireCommand(getKey(), getExpiration(), options);
|
||||
}
|
||||
|
||||
public Expiration getExpiration() {
|
||||
return expiration;
|
||||
}
|
||||
|
||||
public ExpirationOptions getOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Expire a {@link List} of {@literal field} after a given {@link Duration} of time, measured in milliseconds, has
|
||||
* passed.
|
||||
*
|
||||
* @param commands must not be {@literal null}.
|
||||
* @return a {@link Flux} emitting the expiration results one by one, {@literal true} if the timeout was set or
|
||||
* {@literal false} if the timeout was not set; for example, the key doesn't exist, or the operation was
|
||||
* skipped because of the provided arguments.
|
||||
* @since 3.5
|
||||
* @see <a href="https://redis.io/commands/expire">Redis Documentation: EXPIRE</a>
|
||||
* @see <a href="https://redis.io/commands/pexpire">Redis Documentation: PEXPIRE</a>
|
||||
* @see <a href="https://redis.io/commands/expireat">Redis Documentation: EXPIREAT</a>
|
||||
* @see <a href="https://redis.io/commands/pexpireat">Redis Documentation: PEXPIREAT</a>
|
||||
* @see <a href="https://redis.io/commands/persist">Redis Documentation: PERSIST</a>
|
||||
*/
|
||||
Flux<BooleanResponse<ExpireCommand>> applyExpiration(Publisher<ExpireCommand> commands);
|
||||
|
||||
/**
|
||||
* Set time to live for given {@code key} in seconds.
|
||||
*
|
||||
@@ -581,7 +659,9 @@ public interface ReactiveKeyCommands {
|
||||
* result.
|
||||
* @see <a href="https://redis.io/commands/expire">Redis Documentation: EXPIRE</a>
|
||||
*/
|
||||
Flux<BooleanResponse<ExpireCommand>> expire(Publisher<ExpireCommand> commands);
|
||||
default Flux<BooleanResponse<ExpireCommand>> expire(Publisher<ExpireCommand> commands) {
|
||||
return applyExpiration(commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set time to live for given {@code key} in milliseconds.
|
||||
@@ -607,7 +687,9 @@ public interface ReactiveKeyCommands {
|
||||
* result.
|
||||
* @see <a href="https://redis.io/commands/pexpire">Redis Documentation: PEXPIRE</a>
|
||||
*/
|
||||
Flux<BooleanResponse<ExpireCommand>> pExpire(Publisher<ExpireCommand> commands);
|
||||
default Flux<BooleanResponse<ExpireCommand>> pExpire(Publisher<ExpireCommand> commands) {
|
||||
return applyExpiration(commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code EXPIREAT}/{@code PEXPIREAT} command parameters.
|
||||
@@ -619,12 +701,18 @@ public interface ReactiveKeyCommands {
|
||||
class ExpireAtCommand extends KeyCommand {
|
||||
|
||||
private @Nullable Instant expireAt;
|
||||
private final ExpirationOptions options;
|
||||
|
||||
private ExpireAtCommand(ByteBuffer key, @Nullable Instant expireAt) {
|
||||
private ExpireAtCommand(ByteBuffer key, Instant expireAt) {
|
||||
this(key, expireAt, ExpirationOptions.none());
|
||||
}
|
||||
|
||||
private ExpireAtCommand(@Nullable ByteBuffer key, Instant expireAt, ExpirationOptions options) {
|
||||
|
||||
super(key);
|
||||
|
||||
this.expireAt = expireAt;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -653,6 +741,15 @@ public interface ReactiveKeyCommands {
|
||||
return new ExpireAtCommand(getKey(), expireAt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param options additional options to be sent along with the command.
|
||||
* @return new instance of {@link ExpireAtCommand}.
|
||||
* @since 3.5
|
||||
*/
|
||||
public ExpireAtCommand withOptions(ExpirationOptions options) {
|
||||
return new ExpireAtCommand(getKey(), getExpireAt(), options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return can be {@literal null}.
|
||||
*/
|
||||
@@ -660,6 +757,11 @@ public interface ReactiveKeyCommands {
|
||||
public Instant getExpireAt() {
|
||||
return expireAt;
|
||||
}
|
||||
|
||||
public ExpirationOptions getOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,7 +21,6 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.data.redis.connection.Hash.FieldExpirationOptions;
|
||||
import org.springframework.data.redis.core.Cursor;
|
||||
import org.springframework.data.redis.core.ScanOptions;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -257,7 +256,7 @@ public interface RedisHashCommands {
|
||||
|
||||
/**
|
||||
* Apply a given {@link org.springframework.data.redis.core.types.Expiration} to the given {@literal fields}.
|
||||
*
|
||||
*
|
||||
* @param key must not be {@literal null}.
|
||||
* @param expiration the {@link org.springframework.data.redis.core.types.Expiration} to apply.
|
||||
* @param fields the names of the {@literal fields} to apply the {@literal expiration} to.
|
||||
@@ -267,9 +266,9 @@ public interface RedisHashCommands {
|
||||
* such field;
|
||||
* @since 3.5
|
||||
*/
|
||||
default @Nullable List<Long> applyExpiration(byte[] key,
|
||||
default @Nullable List<Long> applyHashFieldExpiration(byte[] key,
|
||||
org.springframework.data.redis.core.types.Expiration expiration, byte[]... fields) {
|
||||
return applyExpiration(key, expiration, FieldExpirationOptions.none(), fields);
|
||||
return applyHashFieldExpiration(key, expiration, ExpirationOptions.none(), fields);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -284,14 +283,14 @@ public interface RedisHashCommands {
|
||||
* @since 3.5
|
||||
*/
|
||||
@Nullable
|
||||
default List<Long> applyExpiration(byte[] key, org.springframework.data.redis.core.types.Expiration expiration,
|
||||
FieldExpirationOptions options, byte[]... fields) {
|
||||
default List<Long> applyHashFieldExpiration(byte[] key,
|
||||
org.springframework.data.redis.core.types.Expiration expiration, ExpirationOptions options, byte[]... fields) {
|
||||
|
||||
if (expiration.isPersistent()) {
|
||||
return hPersist(key, fields);
|
||||
}
|
||||
|
||||
if (ObjectUtils.nullSafeEquals(FieldExpirationOptions.none(), options)) {
|
||||
if (ObjectUtils.nullSafeEquals(ExpirationOptions.none(), options)) {
|
||||
if (ObjectUtils.nullSafeEquals(TimeUnit.MILLISECONDS, expiration.getTimeUnit())) {
|
||||
if (expiration.isUnixTimestamp()) {
|
||||
return hpExpireAt(key, expiration.getExpirationTimeInMilliseconds(), fields);
|
||||
@@ -334,7 +333,7 @@ public interface RedisHashCommands {
|
||||
*/
|
||||
@Nullable
|
||||
default List<Long> hExpire(byte[] key, long seconds, byte[]... fields) {
|
||||
return hExpire(key, seconds, FieldExpirationOptions.Condition.ALWAYS, fields);
|
||||
return hExpire(key, seconds, ExpirationOptions.Condition.ALWAYS, fields);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -372,7 +371,7 @@ public interface RedisHashCommands {
|
||||
* @since 3.5
|
||||
*/
|
||||
@Nullable
|
||||
List<Long> hExpire(byte[] key, long seconds, FieldExpirationOptions.Condition condition, byte[]... fields);
|
||||
List<Long> hExpire(byte[] key, long seconds, ExpirationOptions.Condition condition, byte[]... fields);
|
||||
|
||||
/**
|
||||
* Set time to live for given {@code fields} in milliseconds.
|
||||
@@ -390,7 +389,7 @@ public interface RedisHashCommands {
|
||||
*/
|
||||
@Nullable
|
||||
default List<Long> hpExpire(byte[] key, long millis, byte[]... fields) {
|
||||
return hpExpire(key, millis, FieldExpirationOptions.Condition.ALWAYS, fields);
|
||||
return hpExpire(key, millis, ExpirationOptions.Condition.ALWAYS, fields);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -429,7 +428,7 @@ public interface RedisHashCommands {
|
||||
* @since 3.5
|
||||
*/
|
||||
@Nullable
|
||||
List<Long> hpExpire(byte[] key, long millis, FieldExpirationOptions.Condition condition, byte[]... fields);
|
||||
List<Long> hpExpire(byte[] key, long millis, ExpirationOptions.Condition condition, byte[]... fields);
|
||||
|
||||
/**
|
||||
* Set the expiration for given {@code field} as a {@literal UNIX} timestamp.
|
||||
@@ -446,7 +445,7 @@ public interface RedisHashCommands {
|
||||
*/
|
||||
@Nullable
|
||||
default List<Long> hExpireAt(byte[] key, long unixTime, byte[]... fields) {
|
||||
return hExpireAt(key, unixTime, FieldExpirationOptions.Condition.ALWAYS, fields);
|
||||
return hExpireAt(key, unixTime, ExpirationOptions.Condition.ALWAYS, fields);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -465,7 +464,7 @@ public interface RedisHashCommands {
|
||||
* @since 3.5
|
||||
*/
|
||||
@Nullable
|
||||
List<Long> hExpireAt(byte[] key, long unixTime, FieldExpirationOptions.Condition condition, byte[]... fields);
|
||||
List<Long> hExpireAt(byte[] key, long unixTime, ExpirationOptions.Condition condition, byte[]... fields);
|
||||
|
||||
/**
|
||||
* Set the expiration for given {@code field} as a {@literal UNIX} timestamp in milliseconds.
|
||||
@@ -482,7 +481,7 @@ public interface RedisHashCommands {
|
||||
*/
|
||||
@Nullable
|
||||
default List<Long> hpExpireAt(byte[] key, long unixTimeInMillis, byte[]... fields) {
|
||||
return hpExpireAt(key, unixTimeInMillis, FieldExpirationOptions.Condition.ALWAYS, fields);
|
||||
return hpExpireAt(key, unixTimeInMillis, ExpirationOptions.Condition.ALWAYS, fields);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -501,7 +500,7 @@ public interface RedisHashCommands {
|
||||
* @since 3.5
|
||||
*/
|
||||
@Nullable
|
||||
List<Long> hpExpireAt(byte[] key, long unixTimeInMillis, FieldExpirationOptions.Condition condition,
|
||||
List<Long> hpExpireAt(byte[] key, long unixTimeInMillis, ExpirationOptions.Condition condition,
|
||||
byte[]... fields);
|
||||
|
||||
/**
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.springframework.data.redis.core.KeyScanOptions;
|
||||
import org.springframework.data.redis.core.ScanOptions;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Key-specific commands supported by Redis.
|
||||
@@ -181,23 +182,93 @@ public interface RedisKeyCommands {
|
||||
@Nullable
|
||||
Boolean renameNX(byte[] oldKey, byte[] newKey);
|
||||
|
||||
/**
|
||||
* @param key must not be {@literal null}.
|
||||
* @param expiration the {@link org.springframework.data.redis.core.types.Expiration} to apply.
|
||||
* @param options additional options to be sent along with the command.
|
||||
* @return {@literal null} when used in pipeline / transaction. {@literal true} if the timeout was set or
|
||||
* {@literal false} if the timeout was not set; for example, the key doesn't exist, or the operation was
|
||||
* skipped because of the provided arguments.
|
||||
* @since 3.5
|
||||
* @see <a href="https://redis.io/commands/expire">Redis Documentation: EXPIRE</a>
|
||||
* @see <a href="https://redis.io/commands/pexpire">Redis Documentation: PEXPIRE</a>
|
||||
* @see <a href="https://redis.io/commands/expireat">Redis Documentation: EXPIREAT</a>
|
||||
* @see <a href="https://redis.io/commands/pexpireat">Redis Documentation: PEXPIREAT</a>
|
||||
* @see <a href="https://redis.io/commands/persist">Redis Documentation: PERSIST</a>
|
||||
*/
|
||||
@Nullable
|
||||
default Boolean applyExpiration(byte[] key, org.springframework.data.redis.core.types.Expiration expiration,
|
||||
ExpirationOptions options) {
|
||||
|
||||
if (expiration.isPersistent()) {
|
||||
return persist(key);
|
||||
}
|
||||
|
||||
if (ObjectUtils.nullSafeEquals(ExpirationOptions.none(), options)) {
|
||||
if (ObjectUtils.nullSafeEquals(TimeUnit.MILLISECONDS, expiration.getTimeUnit())) {
|
||||
if (expiration.isUnixTimestamp()) {
|
||||
return expireAt(key, expiration.getExpirationTimeInMilliseconds());
|
||||
}
|
||||
return expire(key, expiration.getExpirationTimeInMilliseconds());
|
||||
}
|
||||
if (expiration.isUnixTimestamp()) {
|
||||
return expireAt(key, expiration.getExpirationTimeInSeconds());
|
||||
}
|
||||
return expire(key, expiration.getExpirationTimeInSeconds());
|
||||
}
|
||||
|
||||
if (ObjectUtils.nullSafeEquals(TimeUnit.MILLISECONDS, expiration.getTimeUnit())) {
|
||||
if (expiration.isUnixTimestamp()) {
|
||||
return expireAt(key, expiration.getExpirationTimeInMilliseconds(), options.getCondition());
|
||||
}
|
||||
|
||||
return expire(key, expiration.getExpirationTimeInMilliseconds(), options.getCondition());
|
||||
}
|
||||
|
||||
if (expiration.isUnixTimestamp()) {
|
||||
return expireAt(key, expiration.getExpirationTimeInSeconds(), options.getCondition());
|
||||
}
|
||||
|
||||
return expire(key, expiration.getExpirationTimeInSeconds(), options.getCondition());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set time to live for given {@code key} in seconds.
|
||||
*
|
||||
* @param key must not be {@literal null}.
|
||||
* @param seconds
|
||||
* @return {@literal null} when used in pipeline / transaction.
|
||||
* @return {@literal null} when used in pipeline / transaction. {@literal true} if the timeout was set or
|
||||
* {@literal false} if the timeout was not set; for example, the key doesn't exist, or the operation was
|
||||
* skipped because of the provided arguments.
|
||||
* @see <a href="https://redis.io/commands/expire">Redis Documentation: EXPIRE</a>
|
||||
*/
|
||||
@Nullable
|
||||
Boolean expire(byte[] key, long seconds);
|
||||
default Boolean expire(byte[] key, long seconds) {
|
||||
return expire(key, seconds, ExpirationOptions.Condition.ALWAYS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set time to live for given {@code key} in seconds.
|
||||
*
|
||||
* @param key must not be {@literal null}.
|
||||
* @param seconds
|
||||
* @return {@literal null} when used in pipeline / transaction. {@literal true} if the timeout was set or
|
||||
* {@literal false} if the timeout was not set; for example, the key doesn't exist, or the operation was
|
||||
* skipped because of the provided arguments.
|
||||
* @see <a href="https://redis.io/commands/expire">Redis Documentation: EXPIRE</a>
|
||||
* @since 3.5
|
||||
*/
|
||||
@Nullable
|
||||
Boolean expire(byte[] key, long seconds, ExpirationOptions.Condition condition);
|
||||
|
||||
/**
|
||||
* Set time to live for given {@code key} using {@link Duration#toSeconds() seconds} precision.
|
||||
*
|
||||
* @param key must not be {@literal null}.
|
||||
* @param duration
|
||||
* @return {@literal null} when used in pipeline / transaction.
|
||||
* @return {@literal null} when used in pipeline / transaction. {@literal true} if the timeout was set or
|
||||
* {@literal false} if the timeout was not set; for example, the key doesn't exist, or the operation was
|
||||
* skipped because of the provided arguments.
|
||||
* @see <a href="https://redis.io/commands/expire">Redis Documentation: EXPIRE</a>
|
||||
* @since 3.5
|
||||
*/
|
||||
@@ -211,18 +282,38 @@ public interface RedisKeyCommands {
|
||||
*
|
||||
* @param key must not be {@literal null}.
|
||||
* @param millis
|
||||
* @return {@literal null} when used in pipeline / transaction.
|
||||
* @return {@literal null} when used in pipeline / transaction. {@literal true} if the timeout was set or
|
||||
* {@literal false} if the timeout was not set; for example, the key doesn't exist, or the operation was
|
||||
* skipped because of the provided arguments.
|
||||
* @see <a href="https://redis.io/commands/pexpire">Redis Documentation: PEXPIRE</a>
|
||||
*/
|
||||
@Nullable
|
||||
Boolean pExpire(byte[] key, long millis);
|
||||
default Boolean pExpire(byte[] key, long millis) {
|
||||
return pExpire(key, millis, ExpirationOptions.Condition.ALWAYS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set time to live for given {@code key} in milliseconds.
|
||||
*
|
||||
* @param key must not be {@literal null}.
|
||||
* @param millis
|
||||
* @return {@literal null} when used in pipeline / transaction. {@literal true} if the timeout was set or
|
||||
* {@literal false} if the timeout was not set; for example, the key doesn't exist, or the operation was
|
||||
* skipped because of the provided arguments.
|
||||
* @see <a href="https://redis.io/commands/pexpire">Redis Documentation: PEXPIRE</a>
|
||||
* @since 3.5
|
||||
*/
|
||||
@Nullable
|
||||
Boolean pExpire(byte[] key, long millis, ExpirationOptions.Condition condition);
|
||||
|
||||
/**
|
||||
* Set time to live for given {@code key} using {@link Duration#toMillis() milliseconds} precision.
|
||||
*
|
||||
* @param key must not be {@literal null}.
|
||||
* @param duration
|
||||
* @return {@literal null} when used in pipeline / transaction.
|
||||
* @return {@literal null} when used in pipeline / transaction. {@literal true} if the timeout was set or
|
||||
* {@literal false} if the timeout was not set; for example, the key doesn't exist, or the operation was
|
||||
* skipped because of the provided arguments.
|
||||
* @see <a href="https://redis.io/commands/pexpire">Redis Documentation: PEXPIRE</a>
|
||||
* @since 3.5
|
||||
*/
|
||||
@@ -236,11 +327,29 @@ public interface RedisKeyCommands {
|
||||
*
|
||||
* @param key must not be {@literal null}.
|
||||
* @param unixTime
|
||||
* @return {@literal null} when used in pipeline / transaction.
|
||||
* @return {@literal null} when used in pipeline / transaction. {@literal true} if the timeout was set or
|
||||
* {@literal false} if the timeout was not set; for example, the key doesn't exist, or the operation was
|
||||
* skipped because of the provided arguments.
|
||||
* @see <a href="https://redis.io/commands/expireat">Redis Documentation: EXPIREAT</a>
|
||||
*/
|
||||
@Nullable
|
||||
Boolean expireAt(byte[] key, long unixTime);
|
||||
default Boolean expireAt(byte[] key, long unixTime) {
|
||||
return expireAt(key, unixTime, ExpirationOptions.Condition.ALWAYS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the expiration for given {@code key} as a {@literal UNIX} timestamp.
|
||||
*
|
||||
* @param key must not be {@literal null}.
|
||||
* @param unixTime
|
||||
* @return {@literal null} when used in pipeline / transaction. {@literal true} if the timeout was set or
|
||||
* {@literal false} if the timeout was not set; for example, the key doesn't exist, or the operation was
|
||||
* skipped because of the provided arguments.
|
||||
* @see <a href="https://redis.io/commands/expireat">Redis Documentation: EXPIREAT</a>
|
||||
* @since 3.5
|
||||
*/
|
||||
@Nullable
|
||||
Boolean expireAt(byte[] key, long unixTime, ExpirationOptions.Condition condition);
|
||||
|
||||
/**
|
||||
* Set the expiration for given {@code key} as a {@literal UNIX} timestamp in {@link Instant#getEpochSecond() seconds}
|
||||
@@ -248,7 +357,9 @@ public interface RedisKeyCommands {
|
||||
*
|
||||
* @param key must not be {@literal null}.
|
||||
* @param unixTime
|
||||
* @return {@literal null} when used in pipeline / transaction.
|
||||
* @return {@literal null} when used in pipeline / transaction. {@literal true} if the timeout was set or
|
||||
* {@literal false} if the timeout was not set; for example, the key doesn't exist, or the operation was
|
||||
* skipped because of the provided arguments.
|
||||
* @see <a href="https://redis.io/commands/expireat">Redis Documentation: EXPIREAT</a>
|
||||
* @since 3.5
|
||||
*/
|
||||
@@ -262,11 +373,29 @@ public interface RedisKeyCommands {
|
||||
*
|
||||
* @param key must not be {@literal null}.
|
||||
* @param unixTimeInMillis
|
||||
* @return {@literal null} when used in pipeline / transaction.
|
||||
* @return {@literal null} when used in pipeline / transaction. {@literal true} if the timeout was set or
|
||||
* {@literal false} if the timeout was not set; for example, the key doesn't exist, or the operation was
|
||||
* skipped because of the provided arguments.
|
||||
* @see <a href="https://redis.io/commands/pexpireat">Redis Documentation: PEXPIREAT</a>
|
||||
*/
|
||||
@Nullable
|
||||
Boolean pExpireAt(byte[] key, long unixTimeInMillis);
|
||||
default Boolean pExpireAt(byte[] key, long unixTimeInMillis) {
|
||||
return pExpireAt(key, unixTimeInMillis, ExpirationOptions.Condition.ALWAYS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the expiration for given {@code key} as a {@literal UNIX} timestamp in milliseconds.
|
||||
*
|
||||
* @param key must not be {@literal null}.
|
||||
* @param unixTimeInMillis
|
||||
* @return {@literal null} when used in pipeline / transaction. {@literal true} if the timeout was set or
|
||||
* {@literal false} if the timeout was not set; for example, the key doesn't exist, or the operation was
|
||||
* skipped because of the provided arguments.
|
||||
* @see <a href="https://redis.io/commands/pexpireat">Redis Documentation: PEXPIREAT</a>
|
||||
* @since 3.5
|
||||
*/
|
||||
@Nullable
|
||||
Boolean pExpireAt(byte[] key, long unixTimeInMillis, ExpirationOptions.Condition condition);
|
||||
|
||||
/**
|
||||
* Set the expiration for given {@code key} as a {@literal UNIX} timestamp in {@link Instant#toEpochMilli()
|
||||
@@ -274,7 +403,9 @@ public interface RedisKeyCommands {
|
||||
*
|
||||
* @param key must not be {@literal null}.
|
||||
* @param unixTime
|
||||
* @return {@literal null} when used in pipeline / transaction.
|
||||
* @return {@literal null} when used in pipeline / transaction. {@literal true} if the timeout was set or
|
||||
* {@literal false} if the timeout was not set; for example, the key doesn't exist, or the operation was
|
||||
* skipped because of the provided arguments.
|
||||
* @see <a href="https://redis.io/commands/pexpireat">Redis Documentation: PEXPIREAT</a>
|
||||
* @since 3.5
|
||||
*/
|
||||
|
||||
@@ -224,7 +224,22 @@ public interface StringRedisConnection extends RedisConnection {
|
||||
* @see <a href="https://redis.io/commands/expire">Redis Documentation: EXPIRE</a>
|
||||
* @see RedisKeyCommands#expire(byte[], long)
|
||||
*/
|
||||
Boolean expire(String key, long seconds);
|
||||
default Boolean expire(String key, long seconds) {
|
||||
return expire(key, seconds, ExpirationOptions.Condition.ALWAYS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set time to live for given {@code key} in seconds.
|
||||
*
|
||||
* @param key must not be {@literal null}.
|
||||
* @param condition the condition for expiration, must not be {@literal null}.
|
||||
* @param seconds
|
||||
* @return
|
||||
* @since 3.5
|
||||
* @see <a href="https://redis.io/commands/expire">Redis Documentation: EXPIRE</a>
|
||||
* @see RedisKeyCommands#expire(byte[], long)
|
||||
*/
|
||||
Boolean expire(String key, long seconds, ExpirationOptions.Condition condition);
|
||||
|
||||
/**
|
||||
* Set time to live for given {@code key} in milliseconds.
|
||||
@@ -235,7 +250,22 @@ public interface StringRedisConnection extends RedisConnection {
|
||||
* @see <a href="https://redis.io/commands/pexpire">Redis Documentation: PEXPIRE</a>
|
||||
* @see RedisKeyCommands#pExpire(byte[], long)
|
||||
*/
|
||||
Boolean pExpire(String key, long millis);
|
||||
default Boolean pExpire(String key, long millis) {
|
||||
return pExpire(key, millis, ExpirationOptions.Condition.ALWAYS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set time to live for given {@code key} in milliseconds.
|
||||
*
|
||||
* @param key must not be {@literal null}.
|
||||
* @param millis
|
||||
* @param condition the condition for expiration, must not be {@literal null}.
|
||||
* @return
|
||||
* @since 3.5
|
||||
* @see <a href="https://redis.io/commands/pexpire">Redis Documentation: PEXPIRE</a>
|
||||
* @see RedisKeyCommands#pExpire(byte[], long)
|
||||
*/
|
||||
Boolean pExpire(String key, long millis, ExpirationOptions.Condition condition);
|
||||
|
||||
/**
|
||||
* Set the expiration for given {@code key} as a {@literal UNIX} timestamp.
|
||||
@@ -246,7 +276,22 @@ public interface StringRedisConnection extends RedisConnection {
|
||||
* @see <a href="https://redis.io/commands/expireat">Redis Documentation: EXPIREAT</a>
|
||||
* @see RedisKeyCommands#expireAt(byte[], long)
|
||||
*/
|
||||
Boolean expireAt(String key, long unixTime);
|
||||
default Boolean expireAt(String key, long unixTime) {
|
||||
return expireAt(key, unixTime, ExpirationOptions.Condition.ALWAYS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the expiration for given {@code key} as a {@literal UNIX} timestamp.
|
||||
*
|
||||
* @param key must not be {@literal null}.
|
||||
* @param unixTime
|
||||
* @param condition the condition for expiration, must not be {@literal null}.
|
||||
* @return
|
||||
* @since 3.5
|
||||
* @see <a href="https://redis.io/commands/expireat">Redis Documentation: EXPIREAT</a>
|
||||
* @see RedisKeyCommands#expireAt(byte[], long)
|
||||
*/
|
||||
Boolean expireAt(String key, long unixTime, ExpirationOptions.Condition condition);
|
||||
|
||||
/**
|
||||
* Set the expiration for given {@code key} as a {@literal UNIX} timestamp in milliseconds.
|
||||
@@ -257,7 +302,22 @@ public interface StringRedisConnection extends RedisConnection {
|
||||
* @see <a href="https://redis.io/commands/pexpireat">Redis Documentation: PEXPIREAT</a>
|
||||
* @see RedisKeyCommands#pExpireAt(byte[], long)
|
||||
*/
|
||||
Boolean pExpireAt(String key, long unixTimeInMillis);
|
||||
default Boolean pExpireAt(String key, long unixTimeInMillis) {
|
||||
return pExpireAt(key, unixTimeInMillis, ExpirationOptions.Condition.ALWAYS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the expiration for given {@code key} as a {@literal UNIX} timestamp in milliseconds.
|
||||
*
|
||||
* @param key must not be {@literal null}.
|
||||
* @param unixTimeInMillis
|
||||
* @param condition the condition for expiration, must not be {@literal null}.
|
||||
* @return
|
||||
* @since 3.5
|
||||
* @see <a href="https://redis.io/commands/pexpireat">Redis Documentation: PEXPIREAT</a>
|
||||
* @see RedisKeyCommands#pExpireAt(byte[], long)
|
||||
*/
|
||||
Boolean pExpireAt(String key, long unixTimeInMillis, ExpirationOptions.Condition condition);
|
||||
|
||||
/**
|
||||
* Remove the expiration from given {@code key}.
|
||||
@@ -2348,7 +2408,7 @@ public interface StringRedisConnection extends RedisConnection {
|
||||
*/
|
||||
@Nullable
|
||||
default List<Long> hExpire(String key, long seconds, String... fields) {
|
||||
return hExpire(key, seconds, Hash.FieldExpirationOptions.Condition.ALWAYS, fields);
|
||||
return hExpire(key, seconds, ExpirationOptions.Condition.ALWAYS, fields);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2366,7 +2426,7 @@ public interface StringRedisConnection extends RedisConnection {
|
||||
* @since 3.5
|
||||
*/
|
||||
@Nullable
|
||||
List<Long> hExpire(String key, long seconds, Hash.FieldExpirationOptions.Condition condition, String... fields);
|
||||
List<Long> hExpire(String key, long seconds, ExpirationOptions.Condition condition, String... fields);
|
||||
|
||||
/**
|
||||
* Set time to live for given {@code field} in milliseconds.
|
||||
@@ -2383,7 +2443,7 @@ public interface StringRedisConnection extends RedisConnection {
|
||||
*/
|
||||
@Nullable
|
||||
default List<Long> hpExpire(String key, long millis, String... fields) {
|
||||
return hpExpire(key, millis, Hash.FieldExpirationOptions.Condition.ALWAYS, fields);
|
||||
return hpExpire(key, millis, ExpirationOptions.Condition.ALWAYS, fields);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2401,7 +2461,7 @@ public interface StringRedisConnection extends RedisConnection {
|
||||
* @since 3.5
|
||||
*/
|
||||
@Nullable
|
||||
List<Long> hpExpire(String key, long millis, Hash.FieldExpirationOptions.Condition condition, String... fields);
|
||||
List<Long> hpExpire(String key, long millis, ExpirationOptions.Condition condition, String... fields);
|
||||
|
||||
/**
|
||||
* Set the expiration for given {@code field} as a {@literal UNIX} timestamp.
|
||||
@@ -2418,7 +2478,7 @@ public interface StringRedisConnection extends RedisConnection {
|
||||
*/
|
||||
@Nullable
|
||||
default List<Long> hExpireAt(String key, long unixTime, String... fields) {
|
||||
return hExpireAt(key, unixTime, Hash.FieldExpirationOptions.Condition.ALWAYS, fields);
|
||||
return hExpireAt(key, unixTime, ExpirationOptions.Condition.ALWAYS, fields);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2436,7 +2496,7 @@ public interface StringRedisConnection extends RedisConnection {
|
||||
* @since 3.5
|
||||
*/
|
||||
@Nullable
|
||||
List<Long> hExpireAt(String key, long unixTime, Hash.FieldExpirationOptions.Condition condition, String... fields);
|
||||
List<Long> hExpireAt(String key, long unixTime, ExpirationOptions.Condition condition, String... fields);
|
||||
|
||||
/**
|
||||
* Set the expiration for given {@code field} as a {@literal UNIX} timestamp in milliseconds.
|
||||
@@ -2453,7 +2513,7 @@ public interface StringRedisConnection extends RedisConnection {
|
||||
*/
|
||||
@Nullable
|
||||
default List<Long> hpExpireAt(String key, long unixTimeInMillis, String... fields) {
|
||||
return hpExpireAt(key, unixTimeInMillis, Hash.FieldExpirationOptions.Condition.ALWAYS, fields);
|
||||
return hpExpireAt(key, unixTimeInMillis, ExpirationOptions.Condition.ALWAYS, fields);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2471,7 +2531,7 @@ public interface StringRedisConnection extends RedisConnection {
|
||||
* @since 3.5
|
||||
*/
|
||||
@Nullable
|
||||
List<Long> hpExpireAt(String key, long unixTimeInMillis, Hash.FieldExpirationOptions.Condition condition,
|
||||
List<Long> hpExpireAt(String key, long unixTimeInMillis, ExpirationOptions.Condition condition,
|
||||
String... fields);
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,7 +27,7 @@ import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.data.redis.connection.Hash.FieldExpirationOptions;
|
||||
import org.springframework.data.redis.connection.ExpirationOptions;
|
||||
import org.springframework.data.redis.connection.RedisHashCommands;
|
||||
import org.springframework.data.redis.core.Cursor;
|
||||
import org.springframework.data.redis.core.ScanCursor;
|
||||
@@ -291,13 +291,13 @@ class JedisClusterHashCommands implements RedisHashCommands {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> hExpire(byte[] key, long seconds, FieldExpirationOptions.Condition condition, byte[]... fields) {
|
||||
public List<Long> hExpire(byte[] key, long seconds, ExpirationOptions.Condition condition, byte[]... fields) {
|
||||
|
||||
Assert.notNull(key, "Key must not be null");
|
||||
Assert.notNull(fields, "Fields must not be null");
|
||||
|
||||
try {
|
||||
if (condition == FieldExpirationOptions.Condition.ALWAYS) {
|
||||
if (condition == ExpirationOptions.Condition.ALWAYS) {
|
||||
return connection.getCluster().hexpire(key, seconds, fields);
|
||||
}
|
||||
|
||||
@@ -308,13 +308,13 @@ class JedisClusterHashCommands implements RedisHashCommands {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> hpExpire(byte[] key, long millis, FieldExpirationOptions.Condition condition, byte[]... fields) {
|
||||
public List<Long> hpExpire(byte[] key, long millis, ExpirationOptions.Condition condition, byte[]... fields) {
|
||||
|
||||
Assert.notNull(key, "Key must not be null");
|
||||
Assert.notNull(fields, "Fields must not be null");
|
||||
|
||||
try {
|
||||
if (condition == FieldExpirationOptions.Condition.ALWAYS) {
|
||||
if (condition == ExpirationOptions.Condition.ALWAYS) {
|
||||
return connection.getCluster().hpexpire(key, millis, fields);
|
||||
}
|
||||
|
||||
@@ -325,13 +325,13 @@ class JedisClusterHashCommands implements RedisHashCommands {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> hExpireAt(byte[] key, long unixTime, FieldExpirationOptions.Condition condition, byte[]... fields) {
|
||||
public List<Long> hExpireAt(byte[] key, long unixTime, ExpirationOptions.Condition condition, byte[]... fields) {
|
||||
Assert.notNull(key, "Key must not be null");
|
||||
Assert.notNull(fields, "Fields must not be null");
|
||||
|
||||
try {
|
||||
|
||||
if (condition == FieldExpirationOptions.Condition.ALWAYS) {
|
||||
if (condition == ExpirationOptions.Condition.ALWAYS) {
|
||||
return connection.getCluster().hexpireAt(key, unixTime, fields);
|
||||
}
|
||||
|
||||
@@ -342,7 +342,7 @@ class JedisClusterHashCommands implements RedisHashCommands {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> hpExpireAt(byte[] key, long unixTimeInMillis, FieldExpirationOptions.Condition condition,
|
||||
public List<Long> hpExpireAt(byte[] key, long unixTimeInMillis, ExpirationOptions.Condition condition,
|
||||
byte[]... fields) {
|
||||
|
||||
Assert.notNull(key, "Key must not be null");
|
||||
@@ -350,7 +350,7 @@ class JedisClusterHashCommands implements RedisHashCommands {
|
||||
|
||||
try {
|
||||
|
||||
if (condition == FieldExpirationOptions.Condition.ALWAYS) {
|
||||
if (condition == ExpirationOptions.Condition.ALWAYS) {
|
||||
return connection.getCluster().hpexpireAt(key, unixTimeInMillis, fields);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.data.redis.connection.jedis;
|
||||
|
||||
import redis.clients.jedis.Jedis;
|
||||
import redis.clients.jedis.args.ExpiryOption;
|
||||
import redis.clients.jedis.params.RestoreParams;
|
||||
import redis.clients.jedis.params.ScanParams;
|
||||
import redis.clients.jedis.resps.ScanResult;
|
||||
@@ -35,6 +36,7 @@ import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.redis.connection.ClusterSlotHashUtil;
|
||||
import org.springframework.data.redis.connection.DataType;
|
||||
import org.springframework.data.redis.connection.ExpirationOptions;
|
||||
import org.springframework.data.redis.connection.RedisClusterNode;
|
||||
import org.springframework.data.redis.connection.RedisKeyCommands;
|
||||
import org.springframework.data.redis.connection.RedisNode;
|
||||
@@ -274,48 +276,67 @@ class JedisClusterKeyCommands implements RedisKeyCommands {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean expire(byte[] key, long seconds) {
|
||||
public Boolean expire(byte[] key, long seconds, ExpirationOptions.Condition condition) {
|
||||
|
||||
Assert.notNull(key, "Key must not be null");
|
||||
|
||||
try {
|
||||
return JedisConverters.toBoolean(connection.getCluster().expire(key, seconds));
|
||||
if (condition == ExpirationOptions.Condition.ALWAYS) {
|
||||
return JedisConverters.toBoolean(connection.getCluster().expire(key, seconds));
|
||||
}
|
||||
|
||||
return JedisConverters
|
||||
.toBoolean(connection.getCluster().expire(key, seconds, ExpiryOption.valueOf(condition.name())));
|
||||
} catch (Exception ex) {
|
||||
throw convertJedisAccessException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean pExpire(byte[] key, long millis) {
|
||||
public Boolean pExpire(byte[] key, long millis, ExpirationOptions.Condition condition) {
|
||||
|
||||
Assert.notNull(key, "Key must not be null");
|
||||
|
||||
try {
|
||||
return JedisConverters.toBoolean(connection.getCluster().pexpire(key, millis));
|
||||
if (condition == ExpirationOptions.Condition.ALWAYS) {
|
||||
return JedisConverters.toBoolean(connection.getCluster().pexpire(key, millis));
|
||||
}
|
||||
return JedisConverters
|
||||
.toBoolean(connection.getCluster().pexpire(key, millis, ExpiryOption.valueOf(condition.name())));
|
||||
} catch (Exception ex) {
|
||||
throw convertJedisAccessException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean expireAt(byte[] key, long unixTime) {
|
||||
public Boolean expireAt(byte[] key, long unixTime, ExpirationOptions.Condition condition) {
|
||||
|
||||
Assert.notNull(key, "Key must not be null");
|
||||
|
||||
try {
|
||||
return JedisConverters.toBoolean(connection.getCluster().expireAt(key, unixTime));
|
||||
if (condition == ExpirationOptions.Condition.ALWAYS) {
|
||||
return JedisConverters.toBoolean(connection.getCluster().expireAt(key, unixTime));
|
||||
}
|
||||
|
||||
return JedisConverters
|
||||
.toBoolean(connection.getCluster().expireAt(key, unixTime, ExpiryOption.valueOf(condition.name())));
|
||||
} catch (Exception ex) {
|
||||
throw convertJedisAccessException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean pExpireAt(byte[] key, long unixTimeInMillis) {
|
||||
public Boolean pExpireAt(byte[] key, long unixTimeInMillis, ExpirationOptions.Condition condition) {
|
||||
|
||||
Assert.notNull(key, "Key must not be null");
|
||||
|
||||
try {
|
||||
return JedisConverters.toBoolean(connection.getCluster().pexpireAt(key, unixTimeInMillis));
|
||||
if (condition == ExpirationOptions.Condition.ALWAYS) {
|
||||
return JedisConverters.toBoolean(connection.getCluster().pexpireAt(key, unixTimeInMillis));
|
||||
}
|
||||
|
||||
return JedisConverters
|
||||
.toBoolean(connection.getCluster().pexpireAt(key, unixTimeInMillis, ExpiryOption.valueOf(condition.name())));
|
||||
} catch (Exception ex) {
|
||||
throw convertJedisAccessException(ex);
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.redis.connection.Hash.FieldExpirationOptions;
|
||||
import org.springframework.data.redis.connection.ExpirationOptions;
|
||||
import org.springframework.data.redis.connection.RedisHashCommands;
|
||||
import org.springframework.data.redis.connection.convert.Converters;
|
||||
import org.springframework.data.redis.core.Cursor;
|
||||
@@ -256,9 +256,9 @@ class JedisHashCommands implements RedisHashCommands {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> hExpire(byte[] key, long seconds, FieldExpirationOptions.Condition condition, byte[]... fields) {
|
||||
public List<Long> hExpire(byte[] key, long seconds, ExpirationOptions.Condition condition, byte[]... fields) {
|
||||
|
||||
if (condition == FieldExpirationOptions.Condition.ALWAYS) {
|
||||
if (condition == ExpirationOptions.Condition.ALWAYS) {
|
||||
return connection.invoke().just(Jedis::hexpire, PipelineBinaryCommands::hexpire, key, seconds, fields);
|
||||
}
|
||||
|
||||
@@ -267,9 +267,9 @@ class JedisHashCommands implements RedisHashCommands {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> hpExpire(byte[] key, long millis, FieldExpirationOptions.Condition condition, byte[]... fields) {
|
||||
public List<Long> hpExpire(byte[] key, long millis, ExpirationOptions.Condition condition, byte[]... fields) {
|
||||
|
||||
if (condition == FieldExpirationOptions.Condition.ALWAYS) {
|
||||
if (condition == ExpirationOptions.Condition.ALWAYS) {
|
||||
return connection.invoke().just(Jedis::hpexpire, PipelineBinaryCommands::hpexpire, key, millis, fields);
|
||||
}
|
||||
|
||||
@@ -278,9 +278,9 @@ class JedisHashCommands implements RedisHashCommands {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> hExpireAt(byte[] key, long unixTime, FieldExpirationOptions.Condition condition, byte[]... fields) {
|
||||
public List<Long> hExpireAt(byte[] key, long unixTime, ExpirationOptions.Condition condition, byte[]... fields) {
|
||||
|
||||
if (condition == FieldExpirationOptions.Condition.ALWAYS) {
|
||||
if (condition == ExpirationOptions.Condition.ALWAYS) {
|
||||
return connection.invoke().just(Jedis::hexpireAt, PipelineBinaryCommands::hexpireAt, key, unixTime, fields);
|
||||
}
|
||||
|
||||
@@ -289,10 +289,10 @@ class JedisHashCommands implements RedisHashCommands {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> hpExpireAt(byte[] key, long unixTimeInMillis, FieldExpirationOptions.Condition condition,
|
||||
public List<Long> hpExpireAt(byte[] key, long unixTimeInMillis, ExpirationOptions.Condition condition,
|
||||
byte[]... fields) {
|
||||
|
||||
if (condition == FieldExpirationOptions.Condition.ALWAYS) {
|
||||
if (condition == ExpirationOptions.Condition.ALWAYS) {
|
||||
return connection.invoke().just(Jedis::hpexpireAt, PipelineBinaryCommands::hpexpireAt, key, unixTimeInMillis,
|
||||
fields);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.redis.connection.jedis;
|
||||
|
||||
import redis.clients.jedis.args.ExpiryOption;
|
||||
import redis.clients.jedis.commands.JedisBinaryCommands;
|
||||
import redis.clients.jedis.commands.PipelineBinaryCommands;
|
||||
import redis.clients.jedis.params.RestoreParams;
|
||||
@@ -30,6 +31,7 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.redis.connection.DataType;
|
||||
import org.springframework.data.redis.connection.ExpirationOptions;
|
||||
import org.springframework.data.redis.connection.RedisKeyCommands;
|
||||
import org.springframework.data.redis.connection.SortParameters;
|
||||
import org.springframework.data.redis.connection.ValueEncoding;
|
||||
@@ -206,43 +208,69 @@ class JedisKeyCommands implements RedisKeyCommands {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean expire(byte[] key, long seconds) {
|
||||
public Boolean expire(byte[] key, long seconds, ExpirationOptions.Condition condition) {
|
||||
|
||||
Assert.notNull(key, "Key must not be null");
|
||||
|
||||
if (seconds > Integer.MAX_VALUE) {
|
||||
return pExpire(key, TimeUnit.SECONDS.toMillis(seconds));
|
||||
return pExpire(key, TimeUnit.SECONDS.toMillis(seconds), condition);
|
||||
}
|
||||
|
||||
return connection.invoke().from(JedisBinaryCommands::expire, PipelineBinaryCommands::expire, key, seconds)
|
||||
if (condition == ExpirationOptions.Condition.ALWAYS) {
|
||||
return connection.invoke().from(JedisBinaryCommands::expire, PipelineBinaryCommands::expire, key, seconds)
|
||||
.get(JedisConverters.longToBoolean());
|
||||
}
|
||||
|
||||
ExpiryOption option = ExpiryOption.valueOf(condition.name());
|
||||
return connection.invoke().from(JedisBinaryCommands::expire, PipelineBinaryCommands::expire, key, seconds, option)
|
||||
.get(JedisConverters.longToBoolean());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean pExpire(byte[] key, long millis) {
|
||||
public Boolean pExpire(byte[] key, long millis, ExpirationOptions.Condition condition) {
|
||||
|
||||
Assert.notNull(key, "Key must not be null");
|
||||
|
||||
return connection.invoke().from(JedisBinaryCommands::pexpire, PipelineBinaryCommands::pexpire, key, millis)
|
||||
if (condition == ExpirationOptions.Condition.ALWAYS) {
|
||||
return connection.invoke().from(JedisBinaryCommands::pexpire, PipelineBinaryCommands::pexpire, key, millis)
|
||||
.get(JedisConverters.longToBoolean());
|
||||
}
|
||||
|
||||
ExpiryOption option = ExpiryOption.valueOf(condition.name());
|
||||
return connection.invoke().from(JedisBinaryCommands::pexpire, PipelineBinaryCommands::pexpire, key, millis, option)
|
||||
.get(JedisConverters.longToBoolean());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean expireAt(byte[] key, long unixTime) {
|
||||
public Boolean expireAt(byte[] key, long unixTime, ExpirationOptions.Condition condition) {
|
||||
|
||||
Assert.notNull(key, "Key must not be null");
|
||||
|
||||
return connection.invoke().from(JedisBinaryCommands::expireAt, PipelineBinaryCommands::expireAt, key, unixTime)
|
||||
.get(JedisConverters.longToBoolean());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean pExpireAt(byte[] key, long unixTimeInMillis) {
|
||||
|
||||
Assert.notNull(key, "Key must not be null");
|
||||
if (condition == ExpirationOptions.Condition.ALWAYS) {
|
||||
return connection.invoke().from(JedisBinaryCommands::expireAt, PipelineBinaryCommands::expireAt, key, unixTime)
|
||||
.get(JedisConverters.longToBoolean());
|
||||
}
|
||||
|
||||
ExpiryOption option = ExpiryOption.valueOf(condition.name());
|
||||
return connection.invoke()
|
||||
.from(JedisBinaryCommands::pexpireAt, PipelineBinaryCommands::pexpireAt, key, unixTimeInMillis)
|
||||
.from(JedisBinaryCommands::expireAt, PipelineBinaryCommands::expireAt, key, unixTime, option)
|
||||
.get(JedisConverters.longToBoolean());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean pExpireAt(byte[] key, long unixTimeInMillis, ExpirationOptions.Condition condition) {
|
||||
|
||||
Assert.notNull(key, "Key must not be null");
|
||||
|
||||
if (condition == ExpirationOptions.Condition.ALWAYS) {
|
||||
return connection.invoke()
|
||||
.from(JedisBinaryCommands::pexpireAt, PipelineBinaryCommands::pexpireAt, key, unixTimeInMillis)
|
||||
.get(JedisConverters.longToBoolean());
|
||||
}
|
||||
|
||||
ExpiryOption option = ExpiryOption.valueOf(condition.name());
|
||||
return connection.invoke()
|
||||
.from(JedisBinaryCommands::pexpireAt, PipelineBinaryCommands::pexpireAt, key, unixTimeInMillis, option)
|
||||
.get(JedisConverters.longToBoolean());
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.redis.connection.Hash.FieldExpirationOptions;
|
||||
import org.springframework.data.redis.connection.ExpirationOptions;
|
||||
import org.springframework.data.redis.connection.RedisHashCommands;
|
||||
import org.springframework.data.redis.connection.convert.Converters;
|
||||
import org.springframework.data.redis.core.Cursor;
|
||||
@@ -215,25 +215,25 @@ class LettuceHashCommands implements RedisHashCommands {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> hExpire(byte[] key, long seconds, FieldExpirationOptions.Condition condition, byte[]... fields) {
|
||||
public List<Long> hExpire(byte[] key, long seconds, ExpirationOptions.Condition condition, byte[]... fields) {
|
||||
return connection.invoke().fromMany(RedisHashAsyncCommands::hexpire, key, seconds, getExpireArgs(condition), fields)
|
||||
.toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> hpExpire(byte[] key, long millis, FieldExpirationOptions.Condition condition, byte[]... fields) {
|
||||
public List<Long> hpExpire(byte[] key, long millis, ExpirationOptions.Condition condition, byte[]... fields) {
|
||||
return connection.invoke().fromMany(RedisHashAsyncCommands::hpexpire, key, millis, getExpireArgs(condition), fields)
|
||||
.toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> hExpireAt(byte[] key, long unixTime, FieldExpirationOptions.Condition condition, byte[]... fields) {
|
||||
public List<Long> hExpireAt(byte[] key, long unixTime, ExpirationOptions.Condition condition, byte[]... fields) {
|
||||
return connection.invoke()
|
||||
.fromMany(RedisHashAsyncCommands::hexpireat, key, unixTime, getExpireArgs(condition), fields).toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> hpExpireAt(byte[] key, long unixTimeInMillis, FieldExpirationOptions.Condition condition,
|
||||
public List<Long> hpExpireAt(byte[] key, long unixTimeInMillis, ExpirationOptions.Condition condition,
|
||||
byte[]... fields) {
|
||||
return connection.invoke()
|
||||
.fromMany(RedisHashAsyncCommands::hpexpireat, key, unixTimeInMillis, getExpireArgs(condition), fields).toList();
|
||||
@@ -314,13 +314,13 @@ class LettuceHashCommands implements RedisHashCommands {
|
||||
return value.hasValue() ? Converters.entryOf(value.getKey(), value.getValue()) : null;
|
||||
}
|
||||
|
||||
private ExpireArgs getExpireArgs(FieldExpirationOptions.Condition condition) {
|
||||
private static ExpireArgs getExpireArgs(ExpirationOptions.Condition condition) {
|
||||
|
||||
return new ExpireArgs() {
|
||||
@Override
|
||||
public <K, V> void build(CommandArgs<K, V> args) {
|
||||
|
||||
if (ObjectUtils.nullSafeEquals(condition, FieldExpirationOptions.Condition.ALWAYS)) {
|
||||
if (ObjectUtils.nullSafeEquals(condition, ExpirationOptions.Condition.ALWAYS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,12 +16,14 @@
|
||||
package org.springframework.data.redis.connection.lettuce;
|
||||
|
||||
import io.lettuce.core.CopyArgs;
|
||||
import io.lettuce.core.ExpireArgs;
|
||||
import io.lettuce.core.KeyScanCursor;
|
||||
import io.lettuce.core.RestoreArgs;
|
||||
import io.lettuce.core.ScanArgs;
|
||||
import io.lettuce.core.ScanCursor;
|
||||
import io.lettuce.core.SortArgs;
|
||||
import io.lettuce.core.api.async.RedisKeyAsyncCommands;
|
||||
import io.lettuce.core.protocol.CommandArgs;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
@@ -30,6 +32,7 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.redis.connection.DataType;
|
||||
import org.springframework.data.redis.connection.ExpirationOptions;
|
||||
import org.springframework.data.redis.connection.RedisKeyCommands;
|
||||
import org.springframework.data.redis.connection.SortParameters;
|
||||
import org.springframework.data.redis.connection.ValueEncoding;
|
||||
@@ -39,6 +42,7 @@ import org.springframework.data.redis.core.Cursor;
|
||||
import org.springframework.data.redis.core.ScanOptions;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
@@ -192,35 +196,35 @@ class LettuceKeyCommands implements RedisKeyCommands {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean expire(byte[] key, long seconds) {
|
||||
public Boolean expire(byte[] key, long seconds, ExpirationOptions.Condition condition) {
|
||||
|
||||
Assert.notNull(key, "Key must not be null");
|
||||
|
||||
return connection.invoke().just(RedisKeyAsyncCommands::expire, key, seconds);
|
||||
return connection.invoke().just(RedisKeyAsyncCommands::expire, key, seconds, getExpireArgs(condition));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean pExpire(byte[] key, long millis) {
|
||||
public Boolean pExpire(byte[] key, long millis, ExpirationOptions.Condition condition) {
|
||||
|
||||
Assert.notNull(key, "Key must not be null");
|
||||
|
||||
return connection.invoke().just(RedisKeyAsyncCommands::pexpire, key, millis);
|
||||
return connection.invoke().just(RedisKeyAsyncCommands::pexpire, key, millis, getExpireArgs(condition));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean expireAt(byte[] key, long unixTime) {
|
||||
public Boolean expireAt(byte[] key, long unixTime, ExpirationOptions.Condition condition) {
|
||||
|
||||
Assert.notNull(key, "Key must not be null");
|
||||
|
||||
return connection.invoke().just(RedisKeyAsyncCommands::expireat, key, unixTime);
|
||||
return connection.invoke().just(RedisKeyAsyncCommands::expireat, key, unixTime, getExpireArgs(condition));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean pExpireAt(byte[] key, long unixTimeInMillis) {
|
||||
public Boolean pExpireAt(byte[] key, long unixTimeInMillis, ExpirationOptions.Condition condition) {
|
||||
|
||||
Assert.notNull(key, "Key must not be null");
|
||||
|
||||
return connection.invoke().just(RedisKeyAsyncCommands::pexpireat, key, unixTimeInMillis);
|
||||
return connection.invoke().just(RedisKeyAsyncCommands::pexpireat, key, unixTimeInMillis, getExpireArgs(condition));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -337,4 +341,19 @@ class LettuceKeyCommands implements RedisKeyCommands {
|
||||
|
||||
return connection.invoke().just(RedisKeyAsyncCommands::objectRefcount, key);
|
||||
}
|
||||
|
||||
private static ExpireArgs getExpireArgs(ExpirationOptions.Condition condition) {
|
||||
|
||||
return new ExpireArgs() {
|
||||
@Override
|
||||
public <K, V> void build(CommandArgs<K, V> args) {
|
||||
|
||||
if (ObjectUtils.nullSafeEquals(condition, ExpirationOptions.Condition.ALWAYS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
args.add(condition.name());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.reactivestreams.Publisher;
|
||||
import org.springframework.data.redis.connection.Hash.FieldExpirationOptions;
|
||||
import org.springframework.data.redis.connection.ExpirationOptions;
|
||||
import org.springframework.data.redis.connection.ReactiveHashCommands;
|
||||
import org.springframework.data.redis.connection.ReactiveRedisConnection.BooleanResponse;
|
||||
import org.springframework.data.redis.connection.ReactiveRedisConnection.CommandResponse;
|
||||
@@ -269,7 +269,8 @@ class LettuceReactiveHashCommands implements ReactiveHashCommands {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<NumericResponse<ExpireCommand, Long>> applyExpiration(Publisher<ExpireCommand> commands) {
|
||||
public Flux<NumericResponse<HashExpireCommand, Long>> applyHashFieldExpiration(
|
||||
Publisher<HashExpireCommand> commands) {
|
||||
|
||||
return connection.execute(cmd -> Flux.from(commands).concatMap(command -> {
|
||||
|
||||
@@ -287,7 +288,7 @@ class LettuceReactiveHashCommands implements ReactiveHashCommands {
|
||||
@Override
|
||||
public <K, V> void build(CommandArgs<K, V> args) {
|
||||
super.build(args);
|
||||
if (ObjectUtils.nullSafeEquals(command.getOptions(), FieldExpirationOptions.none())) {
|
||||
if (ObjectUtils.nullSafeEquals(command.getOptions(), ExpirationOptions.none())) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,8 +16,10 @@
|
||||
package org.springframework.data.redis.connection.lettuce;
|
||||
|
||||
import io.lettuce.core.CopyArgs;
|
||||
import io.lettuce.core.ExpireArgs;
|
||||
import io.lettuce.core.ScanStream;
|
||||
import io.lettuce.core.api.reactive.RedisKeyReactiveCommands;
|
||||
import io.lettuce.core.protocol.CommandArgs;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@@ -25,9 +27,12 @@ import java.nio.ByteBuffer;
|
||||
import java.time.Duration;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.reactivestreams.Publisher;
|
||||
|
||||
import org.springframework.data.redis.connection.DataType;
|
||||
import org.springframework.data.redis.connection.ExpirationOptions;
|
||||
import org.springframework.data.redis.connection.ReactiveKeyCommands;
|
||||
import org.springframework.data.redis.connection.ReactiveRedisConnection.BooleanResponse;
|
||||
import org.springframework.data.redis.connection.ReactiveRedisConnection.CommandResponse;
|
||||
@@ -38,6 +43,7 @@ import org.springframework.data.redis.connection.ValueEncoding;
|
||||
import org.springframework.data.redis.connection.ValueEncoding.RedisValueEncoding;
|
||||
import org.springframework.data.redis.core.ScanOptions;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
@@ -206,27 +212,45 @@ class LettuceReactiveKeyCommands implements ReactiveKeyCommands {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<BooleanResponse<ExpireCommand>> expire(Publisher<ExpireCommand> commands) {
|
||||
public Flux<BooleanResponse<ExpireCommand>> applyExpiration(Publisher<ExpireCommand> commands) {
|
||||
|
||||
return connection.execute(cmd -> Flux.from(commands).concatMap(command -> {
|
||||
|
||||
Assert.notNull(command.getKey(), "Key must not be null");
|
||||
Assert.notNull(command.getTimeout(), "Timeout must not be null");
|
||||
|
||||
return cmd.expire(command.getKey(), command.getTimeout().getSeconds())
|
||||
.map(value -> new BooleanResponse<>(command, value));
|
||||
}));
|
||||
}
|
||||
if (command.getExpiration().isPersistent()) {
|
||||
return cmd.persist(command.getKey()).map(value -> new BooleanResponse<>(command, value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<BooleanResponse<ExpireCommand>> pExpire(Publisher<ExpireCommand> commands) {
|
||||
ExpireArgs args = new ExpireArgs() {
|
||||
|
||||
return connection.execute(cmd -> Flux.from(commands).concatMap(command -> {
|
||||
@Override
|
||||
public <K, V> void build(CommandArgs<K, V> args) {
|
||||
super.build(args);
|
||||
if (ObjectUtils.nullSafeEquals(command.getOptions(), ExpirationOptions.none())) {
|
||||
return;
|
||||
}
|
||||
|
||||
Assert.notNull(command.getKey(), "Key must not be null");
|
||||
Assert.notNull(command.getTimeout(), "Timeout must not be null");
|
||||
args.add(command.getOptions().getCondition().name());
|
||||
}
|
||||
};
|
||||
|
||||
return cmd.pexpire(command.getKey(), command.getTimeout().toMillis())
|
||||
if (command.getExpiration().isUnixTimestamp()) {
|
||||
|
||||
if (command.getExpiration().getTimeUnit().equals(TimeUnit.MILLISECONDS)) {
|
||||
return cmd.pexpireat(command.getKey(), command.getExpiration().getExpirationTimeInMilliseconds(), args)
|
||||
.map(value -> new BooleanResponse<>(command, value));
|
||||
}
|
||||
return cmd.expireat(command.getKey(), command.getExpiration().getExpirationTimeInSeconds(), args)
|
||||
.map(value -> new BooleanResponse<>(command, value));
|
||||
}
|
||||
|
||||
if (command.getExpiration().getTimeUnit().equals(TimeUnit.MILLISECONDS)) {
|
||||
return cmd.pexpire(command.getKey(), command.getExpiration().getExpirationTimeInMilliseconds(), args)
|
||||
.map(value -> new BooleanResponse<>(command, value));
|
||||
}
|
||||
|
||||
return cmd.expire(command.getKey(), command.getExpiration().getExpirationTimeInSeconds(), args)
|
||||
.map(value -> new BooleanResponse<>(command, value));
|
||||
}));
|
||||
}
|
||||
@@ -239,7 +263,7 @@ class LettuceReactiveKeyCommands implements ReactiveKeyCommands {
|
||||
Assert.notNull(command.getKey(), "Key must not be null");
|
||||
Assert.notNull(command.getExpireAt(), "Expire at must not be null");
|
||||
|
||||
return cmd.expireat(command.getKey(), command.getExpireAt().getEpochSecond())
|
||||
return cmd.expireat(command.getKey(), command.getExpireAt().getEpochSecond(), getExpireArgs(command.getOptions()))
|
||||
.map(value -> new BooleanResponse<>(command, value));
|
||||
}));
|
||||
}
|
||||
@@ -252,7 +276,7 @@ class LettuceReactiveKeyCommands implements ReactiveKeyCommands {
|
||||
Assert.notNull(command.getKey(), "Key must not be null");
|
||||
Assert.notNull(command.getExpireAt(), "Expire at must not be null");
|
||||
|
||||
return cmd.pexpireat(command.getKey(), command.getExpireAt().toEpochMilli())
|
||||
return cmd.pexpireat(command.getKey(), command.getExpireAt().toEpochMilli(), getExpireArgs(command.getOptions()))
|
||||
.map(value -> new BooleanResponse<>(command, value));
|
||||
}));
|
||||
}
|
||||
@@ -319,4 +343,21 @@ class LettuceReactiveKeyCommands implements ReactiveKeyCommands {
|
||||
public Mono<Long> refcount(ByteBuffer key) {
|
||||
return connection.execute(cmd -> cmd.objectRefcount(key)).next();
|
||||
}
|
||||
|
||||
private static ExpireArgs getExpireArgs(ExpirationOptions options) {
|
||||
|
||||
return new ExpireArgs() {
|
||||
|
||||
@Override
|
||||
public <K, V> void build(CommandArgs<K, V> args) {
|
||||
super.build(args);
|
||||
if (ObjectUtils.nullSafeEquals(options.getCondition(), ExpirationOptions.Condition.ALWAYS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
args.add(options.getCondition().name());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.data.redis.connection.Hash;
|
||||
import org.springframework.data.redis.connection.ExpirationOptions;
|
||||
import org.springframework.data.redis.core.types.Expiration;
|
||||
import org.springframework.data.redis.core.types.Expirations;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -40,18 +40,17 @@ public interface BoundHashFieldExpirationOperations<HK> {
|
||||
* @return changes to the hash fields. {@literal null} when used in pipeline / transaction.
|
||||
*/
|
||||
default ExpireChanges<HK> expire(Expiration expiration) {
|
||||
return expire(expiration, Hash.FieldExpirationOptions.none());
|
||||
return expire(expiration, ExpirationOptions.none());
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply {@link Expiration} to the bound hash key/hash fields given {@link Hash.FieldExpirationOptions expiration
|
||||
* options}.
|
||||
* Apply {@link Expiration} to the bound hash key/hash fields given {@link ExpirationOptions expiration options}.
|
||||
*
|
||||
* @param expiration the expiration definition.
|
||||
* @param options expiration options.
|
||||
* @return changes to the hash fields. {@literal null} when used in pipeline / transaction.
|
||||
*/
|
||||
ExpireChanges<HK> expire(Expiration expiration, Hash.FieldExpirationOptions options);
|
||||
ExpireChanges<HK> expire(Expiration expiration, ExpirationOptions options);
|
||||
|
||||
/**
|
||||
* Set time to live for the bound hash key/hash fields.
|
||||
|
||||
@@ -223,7 +223,7 @@ public interface BoundHashOperations<H, HK, HV> extends BoundKeyOperations<H> {
|
||||
* @return the bound operations object to perform operations on the hash field expiration.
|
||||
* @since 3.5
|
||||
*/
|
||||
default BoundHashFieldExpirationOperations<HK> expiration() {
|
||||
default BoundHashFieldExpirationOperations<HK> hashExpiration() {
|
||||
return new DefaultBoundHashFieldExpirationOperations<>(getOperations().opsForHash(), getKey(), this::keys);
|
||||
}
|
||||
|
||||
@@ -235,8 +235,8 @@ public interface BoundHashOperations<H, HK, HV> extends BoundKeyOperations<H> {
|
||||
* @return the bound operations object to perform operations on the hash field expiration.
|
||||
* @since 3.5
|
||||
*/
|
||||
default BoundHashFieldExpirationOperations<HK> expiration(HK... hashFields) {
|
||||
return expiration(Arrays.asList(hashFields));
|
||||
default BoundHashFieldExpirationOperations<HK> hashExpiration(HK... hashFields) {
|
||||
return hashExpiration(Arrays.asList(hashFields));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -247,7 +247,7 @@ public interface BoundHashOperations<H, HK, HV> extends BoundKeyOperations<H> {
|
||||
* @return the bound operations object to perform operations on the hash field expiration.
|
||||
* @since 3.5
|
||||
*/
|
||||
default BoundHashFieldExpirationOperations<HK> expiration(Collection<HK> hashFields) {
|
||||
default BoundHashFieldExpirationOperations<HK> hashExpiration(Collection<HK> hashFields) {
|
||||
return new DefaultBoundHashFieldExpirationOperations<>(getOperations().opsForHash(), getKey(), () -> hashFields);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ import java.util.Collection;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.data.redis.connection.Hash;
|
||||
import org.springframework.data.redis.connection.ExpirationOptions;
|
||||
import org.springframework.data.redis.core.types.Expiration;
|
||||
import org.springframework.data.redis.core.types.Expirations;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -48,7 +48,7 @@ class DefaultBoundHashFieldExpirationOperations<H, HK> implements BoundHashField
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpireChanges<HK> expire(Expiration expiration, Hash.FieldExpirationOptions options) {
|
||||
public ExpireChanges<HK> expire(Expiration expiration, ExpirationOptions options) {
|
||||
return operations.expire(key, expiration, options, getHashKeys());
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.data.redis.connection.Hash.FieldExpirationOptions;
|
||||
import org.springframework.data.redis.connection.ExpirationOptions;
|
||||
import org.springframework.data.redis.connection.convert.Converters;
|
||||
import org.springframework.data.redis.core.types.Expiration;
|
||||
import org.springframework.data.redis.core.types.Expirations;
|
||||
@@ -251,13 +251,13 @@ class DefaultHashOperations<K, HK, HV> extends AbstractOperations<K, Object> imp
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpireChanges<HK> expire(K key, Expiration expiration, FieldExpirationOptions options, Collection<HK> hashKeys) {
|
||||
public ExpireChanges<HK> expire(K key, Expiration expiration, ExpirationOptions options, Collection<HK> hashKeys) {
|
||||
|
||||
List<HK> orderedKeys = List.copyOf(hashKeys);
|
||||
byte[] rawKey = rawKey(key);
|
||||
byte[][] rawHashKeys = rawHashKeys(orderedKeys.toArray());
|
||||
List<Long> raw = execute(
|
||||
connection -> connection.hashCommands().applyExpiration(rawKey, expiration, options, rawHashKeys));
|
||||
connection -> connection.hashCommands().applyHashFieldExpiration(rawKey, expiration, options, rawHashKeys));
|
||||
|
||||
return raw != null ? ExpireChanges.of(orderedKeys, raw) : null;
|
||||
}
|
||||
|
||||
@@ -30,9 +30,9 @@ import java.util.function.Function;
|
||||
|
||||
import org.reactivestreams.Publisher;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.redis.connection.Hash.FieldExpirationOptions;
|
||||
import org.springframework.data.redis.connection.ExpirationOptions;
|
||||
import org.springframework.data.redis.connection.ReactiveHashCommands;
|
||||
import org.springframework.data.redis.connection.ReactiveHashCommands.ExpireCommand;
|
||||
import org.springframework.data.redis.connection.ReactiveHashCommands.HashExpireCommand;
|
||||
import org.springframework.data.redis.connection.ReactiveRedisConnection.NumericResponse;
|
||||
import org.springframework.data.redis.connection.convert.Converters;
|
||||
import org.springframework.data.redis.core.types.Expiration;
|
||||
@@ -244,11 +244,11 @@ class DefaultReactiveHashOperations<H, HK, HV> implements ReactiveHashOperations
|
||||
|
||||
@Override
|
||||
public Mono<ExpireChanges<HK>> expire(H key, Duration timeout, Collection<HK> hashKeys) {
|
||||
return expire(key, Expiration.from(timeout), FieldExpirationOptions.none(), hashKeys);
|
||||
return expire(key, Expiration.from(timeout), ExpirationOptions.none(), hashKeys);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<ExpireChanges<HK>> expire(H key, Expiration expiration, FieldExpirationOptions options,
|
||||
public Mono<ExpireChanges<HK>> expire(H key, Expiration expiration, ExpirationOptions options,
|
||||
Collection<HK> hashKeys) {
|
||||
|
||||
List<HK> orderedKeys = List.copyOf(hashKeys);
|
||||
@@ -257,7 +257,8 @@ class DefaultReactiveHashOperations<H, HK, HV> implements ReactiveHashOperations
|
||||
|
||||
Mono<List<Long>> raw = createFlux(connection -> {
|
||||
return connection
|
||||
.applyExpiration(Mono.just(ExpireCommand.expire(rawHashKeys, expiration).from(rawKey).withOptions(options)))
|
||||
.applyHashFieldExpiration(
|
||||
Mono.just(HashExpireCommand.expire(rawHashKeys, expiration).from(rawKey).withOptions(options)))
|
||||
.map(NumericResponse::getOutput);
|
||||
}).collectList();
|
||||
|
||||
|
||||
@@ -151,6 +151,10 @@ public class ExpireChanges<K> {
|
||||
public static final ExpiryChangeState OK = new ExpiryChangeState(1L);
|
||||
public static final ExpiryChangeState EXPIRED = new ExpiryChangeState(2L);
|
||||
|
||||
static ExpiryChangeState of(boolean value) {
|
||||
return value ? OK : CONDITION_NOT_MET;
|
||||
}
|
||||
|
||||
static ExpiryChangeState of(Number value) {
|
||||
return switch (value.intValue()) {
|
||||
case -2 -> DOES_NOT_EXIST;
|
||||
|
||||
@@ -24,7 +24,7 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.data.redis.connection.Hash.FieldExpirationOptions;
|
||||
import org.springframework.data.redis.connection.ExpirationOptions;
|
||||
import org.springframework.data.redis.core.types.Expiration;
|
||||
import org.springframework.data.redis.core.types.Expirations;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -258,7 +258,7 @@ public interface HashOperations<H, HK, HV> {
|
||||
ExpireChanges<HK> expireAt(H key, Instant expireAt, Collection<HK> hashKeys);
|
||||
|
||||
/**
|
||||
* Apply the expiration for given {@code hashKeys} as a {@literal date} timestamp.
|
||||
* Apply the expiration for given {@code hashKeys}.
|
||||
*
|
||||
* @param key must not be {@literal null}.
|
||||
* @param expiration must not be {@literal null}.
|
||||
@@ -266,11 +266,15 @@ public interface HashOperations<H, HK, HV> {
|
||||
* @param hashKeys must not be {@literal null}.
|
||||
* @return changes to the hash fields. {@literal null} when used in pipeline / transaction.
|
||||
* @throws IllegalArgumentException if the instant is {@literal null} or too large to represent as a {@code Date}.
|
||||
* @see <a href="https://redis.io/docs/latest/commands/hexpireat/">Redis Documentation: HEXPIRE</a>
|
||||
* @see <a href="https://redis.io/docs/latest/commands/hexpire/">Redis Documentation: HEXPIRE</a>
|
||||
* @see <a href="https://redis.io/docs/latest/commands/hpexpire/">Redis Documentation: HPEXPIRE</a>
|
||||
* @see <a href="https://redis.io/docs/latest/commands/hexpireat/">Redis Documentation: HEXPIREAT</a>
|
||||
* @see <a href="https://redis.io/docs/latest/commands/hpexpireat/">Redis Documentation: HPEXPIREAT</a>
|
||||
* @see <a href="https://redis.io/docs/latest/commands/hpersist/">Redis Documentation: HPERSIST</a>
|
||||
* @since 3.5
|
||||
*/
|
||||
@Nullable
|
||||
ExpireChanges<HK> expire(H key, Expiration expiration, FieldExpirationOptions options, Collection<HK> hashKeys);
|
||||
ExpireChanges<HK> expire(H key, Expiration expiration, ExpirationOptions options, Collection<HK> hashKeys);
|
||||
|
||||
/**
|
||||
* Remove the expiration from given {@code hashKeys} .
|
||||
|
||||
@@ -26,7 +26,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.data.redis.connection.Hash.FieldExpirationOptions;
|
||||
import org.springframework.data.redis.connection.ExpirationOptions;
|
||||
import org.springframework.data.redis.core.types.Expiration;
|
||||
import org.springframework.data.redis.core.types.Expirations;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -263,7 +263,7 @@ public interface ReactiveHashOperations<H, HK, HV> {
|
||||
* @see <a href="https://redis.io/docs/latest/commands/hexpire/">Redis Documentation: HEXPIRE</a>
|
||||
* @since 3.5
|
||||
*/
|
||||
Mono<ExpireChanges<HK>> expire(H key, Expiration expiration, FieldExpirationOptions options, Collection<HK> hashKeys);
|
||||
Mono<ExpireChanges<HK>> expire(H key, Expiration expiration, ExpirationOptions options, Collection<HK> hashKeys);
|
||||
|
||||
/**
|
||||
* Set the expiration for given {@code hashKey} as a {@literal date} timestamp.
|
||||
|
||||
@@ -26,9 +26,12 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.reactivestreams.Publisher;
|
||||
|
||||
import org.springframework.data.redis.connection.DataType;
|
||||
import org.springframework.data.redis.connection.ExpirationOptions;
|
||||
import org.springframework.data.redis.connection.ReactiveSubscription.Message;
|
||||
import org.springframework.data.redis.core.script.RedisScript;
|
||||
import org.springframework.data.redis.core.types.Expiration;
|
||||
import org.springframework.data.redis.hash.HashMapper;
|
||||
import org.springframework.data.redis.listener.ChannelTopic;
|
||||
import org.springframework.data.redis.listener.PatternTopic;
|
||||
@@ -373,6 +376,22 @@ public interface ReactiveRedisOperations<K, V> {
|
||||
*/
|
||||
Mono<Boolean> expireAt(K key, Instant expireAt);
|
||||
|
||||
/**
|
||||
* Set the expiration for given {@code key}.
|
||||
*
|
||||
* @param key must not be {@literal null}.
|
||||
* @param expiration must not be {@literal null}.
|
||||
* @param options must not be {@literal null}.
|
||||
* @throws IllegalArgumentException if the instant is {@literal null} or too large to represent as a {@code Date}.
|
||||
* @see <a href="https://redis.io/commands/expire">Redis Documentation: EXPIRE</a>
|
||||
* @see <a href="https://redis.io/commands/pexpire">Redis Documentation: PEXPIRE</a>
|
||||
* @see <a href="https://redis.io/commands/expireat">Redis Documentation: EXPIREAT</a>
|
||||
* @see <a href="https://redis.io/commands/pexpireat">Redis Documentation: PEXPIREAT</a>
|
||||
* @see <a href="https://redis.io/commands/persist">Redis Documentation: PERSIST</a>
|
||||
* @since 3.5
|
||||
*/
|
||||
Mono<ExpireChanges.ExpiryChangeState> expire(K key, Expiration expiration, ExpirationOptions options);
|
||||
|
||||
/**
|
||||
* Remove the expiration from given {@code key}.
|
||||
*
|
||||
|
||||
@@ -29,6 +29,8 @@ import java.util.stream.Collectors;
|
||||
import org.reactivestreams.Publisher;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.redis.connection.DataType;
|
||||
import org.springframework.data.redis.connection.ExpirationOptions;
|
||||
import org.springframework.data.redis.connection.ReactiveKeyCommands;
|
||||
import org.springframework.data.redis.connection.ReactiveRedisConnection;
|
||||
import org.springframework.data.redis.connection.ReactiveRedisConnection.CommandResponse;
|
||||
import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
|
||||
@@ -36,6 +38,7 @@ import org.springframework.data.redis.connection.ReactiveSubscription.Message;
|
||||
import org.springframework.data.redis.core.script.DefaultReactiveScriptExecutor;
|
||||
import org.springframework.data.redis.core.script.ReactiveScriptExecutor;
|
||||
import org.springframework.data.redis.core.script.RedisScript;
|
||||
import org.springframework.data.redis.core.types.Expiration;
|
||||
import org.springframework.data.redis.hash.HashMapper;
|
||||
import org.springframework.data.redis.hash.ObjectHashMapper;
|
||||
import org.springframework.data.redis.listener.ReactiveRedisMessageListenerContainer;
|
||||
@@ -454,6 +457,19 @@ public class ReactiveRedisTemplate<K, V> implements ReactiveRedisOperations<K, V
|
||||
return doCreateMono(connection -> connection.keyCommands().pExpireAt(rawKey(key), expireAt));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<ExpireChanges.ExpiryChangeState> expire(K key, Expiration expiration, ExpirationOptions options) {
|
||||
|
||||
Assert.notNull(key, "Key must not be null");
|
||||
Assert.notNull(expiration, "Expiration at must not be null");
|
||||
Assert.notNull(options, "ExpirationOptions at must not be null");
|
||||
|
||||
Mono<ReactiveKeyCommands.ExpireCommand> just = Mono
|
||||
.just(ReactiveKeyCommands.ExpireCommand.expire(rawKey(key), expiration).withOptions(options));
|
||||
return doCreateMono(connection -> connection.keyCommands().applyExpiration(just))
|
||||
.map(ReactiveRedisConnection.BooleanResponse::getOutput).map(ExpireChanges.ExpiryChangeState::of);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Boolean> persist(K key) {
|
||||
|
||||
|
||||
@@ -77,8 +77,8 @@ public enum RedisCommand {
|
||||
EVALSHA("rw", 2), //
|
||||
EXEC("rw", 0, 0), //
|
||||
EXISTS("r", 1, 1), //
|
||||
EXPIRE("rw", 2, 2), //
|
||||
EXPIREAT("rw", 2, 2), //
|
||||
EXPIRE("rw", 2), //
|
||||
EXPIREAT("rw", 2), //
|
||||
// -- F
|
||||
FLUSHALL("w", 0, 0), //
|
||||
FLUSHDB("w", 0, 0), //
|
||||
@@ -142,8 +142,8 @@ public enum RedisCommand {
|
||||
MULTI("rw", 0, 0), //
|
||||
// -- P
|
||||
PERSIST("rw", 1, 1), //
|
||||
PEXPIRE("rw", 2, 2), //
|
||||
PEXPIREAT("rw", 2, 2), //
|
||||
PEXPIRE("rw", 2), //
|
||||
PEXPIREAT("rw", 2), //
|
||||
PING("r", 0, 0), //
|
||||
PSETEX("w", 3), //
|
||||
PSUBSCRIBE("r", 1), //
|
||||
|
||||
@@ -25,10 +25,12 @@ import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.data.redis.connection.DataType;
|
||||
import org.springframework.data.redis.connection.ExpirationOptions;
|
||||
import org.springframework.data.redis.connection.RedisConnection;
|
||||
import org.springframework.data.redis.connection.stream.ObjectRecord;
|
||||
import org.springframework.data.redis.core.query.SortQuery;
|
||||
import org.springframework.data.redis.core.script.RedisScript;
|
||||
import org.springframework.data.redis.core.types.Expiration;
|
||||
import org.springframework.data.redis.core.types.RedisClientInfo;
|
||||
import org.springframework.data.redis.hash.HashMapper;
|
||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||
@@ -366,6 +368,24 @@ public interface RedisOperations<K, V> {
|
||||
return expireAt(key, Date.from(expireAt));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the expiration for given {@code key}.
|
||||
*
|
||||
* @param key must not be {@literal null}.
|
||||
* @param expiration must not be {@literal null}.
|
||||
* @param options must not be {@literal null}.
|
||||
* @return changes to the expiry. {@literal null} when used in pipeline / transaction.
|
||||
* @throws IllegalArgumentException if the instant is {@literal null} or too large to represent as a {@code Date}.
|
||||
* @see <a href="https://redis.io/commands/expire">Redis Documentation: EXPIRE</a>
|
||||
* @see <a href="https://redis.io/commands/pexpire">Redis Documentation: PEXPIRE</a>
|
||||
* @see <a href="https://redis.io/commands/expireat">Redis Documentation: EXPIREAT</a>
|
||||
* @see <a href="https://redis.io/commands/pexpireat">Redis Documentation: PEXPIREAT</a>
|
||||
* @see <a href="https://redis.io/commands/persist">Redis Documentation: PERSIST</a>
|
||||
* @since 3.5
|
||||
*/
|
||||
@Nullable
|
||||
ExpireChanges.ExpiryChangeState expire(K key, Expiration expiration, ExpirationOptions options);
|
||||
|
||||
/**
|
||||
* Remove the expiration from given {@code key}.
|
||||
*
|
||||
|
||||
@@ -33,6 +33,7 @@ import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.redis.RedisSystemException;
|
||||
import org.springframework.data.redis.connection.DataType;
|
||||
import org.springframework.data.redis.connection.ExpirationOptions;
|
||||
import org.springframework.data.redis.connection.RedisConnection;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.connection.RedisKeyCommands;
|
||||
@@ -46,6 +47,7 @@ import org.springframework.data.redis.core.query.SortQuery;
|
||||
import org.springframework.data.redis.core.script.DefaultScriptExecutor;
|
||||
import org.springframework.data.redis.core.script.RedisScript;
|
||||
import org.springframework.data.redis.core.script.ScriptExecutor;
|
||||
import org.springframework.data.redis.core.types.Expiration;
|
||||
import org.springframework.data.redis.core.types.RedisClientInfo;
|
||||
import org.springframework.data.redis.hash.HashMapper;
|
||||
import org.springframework.data.redis.hash.ObjectHashMapper;
|
||||
@@ -711,6 +713,16 @@ public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperation
|
||||
});
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ExpireChanges.ExpiryChangeState expire(K key, Expiration expiration, ExpirationOptions options) {
|
||||
|
||||
byte[] rawKey = rawKey(key);
|
||||
Boolean raw = doWithKeys(connection -> connection.applyExpiration(rawKey, expiration, options));
|
||||
|
||||
return raw != null ? ExpireChanges.ExpiryChangeState.of(raw) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean persist(K key) {
|
||||
|
||||
|
||||
@@ -324,13 +324,13 @@ public class DefaultRedisMap<K, V> implements RedisMap<K, V> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoundHashFieldExpirationOperations<K> expiration() {
|
||||
return hashOps.expiration();
|
||||
public BoundHashFieldExpirationOperations<K> hashFieldExpiration() {
|
||||
return hashOps.hashExpiration();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoundHashFieldExpirationOperations<K> expiration(Collection<K> hashFields) {
|
||||
return hashOps.expiration(hashFields);
|
||||
public BoundHashFieldExpirationOperations<K> hashFieldExpiration(Collection<K> hashFields) {
|
||||
return hashOps.hashExpiration(hashFields);
|
||||
}
|
||||
|
||||
private void checkResult(@Nullable Object obj) {
|
||||
|
||||
@@ -78,34 +78,35 @@ public interface RedisMap<K, V> extends RedisStore, ConcurrentMap<K, V> {
|
||||
Iterator<Map.Entry<K, V>> scan();
|
||||
|
||||
/**
|
||||
* Returns a bound operations object to perform operations on the hash field expiration for all hash fields at
|
||||
* {@code key}. Operations on the expiration object obtain keys at the time of invoking any expiration operation.
|
||||
* Returns a bound operations object to perform operations on the hash field expiration for all hash fields at the
|
||||
* bound {@link #getKey()}. Operations on the expiration object obtain keys at the time of invoking any expiration
|
||||
* operation.
|
||||
*
|
||||
* @return the bound operations object to perform operations on the hash field expiration.
|
||||
* @since 3.5
|
||||
*/
|
||||
BoundHashFieldExpirationOperations<K> expiration();
|
||||
BoundHashFieldExpirationOperations<K> hashFieldExpiration();
|
||||
|
||||
/**
|
||||
* Returns a bound operations object to perform operations on the hash field expiration for all hash fields at the
|
||||
* bound {@code key} for the given hash fields.
|
||||
* bound {@link #getKey()} for the given hash fields.
|
||||
*
|
||||
* @param hashFields collection of hash fields to operate on.
|
||||
* @return the bound operations object to perform operations on the hash field expiration.
|
||||
* @since 3.5
|
||||
*/
|
||||
default BoundHashFieldExpirationOperations<K> expiration(K... hashFields) {
|
||||
return expiration(Arrays.asList(hashFields));
|
||||
default BoundHashFieldExpirationOperations<K> hashFieldExpiration(K... hashFields) {
|
||||
return hashFieldExpiration(Arrays.asList(hashFields));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a bound operations object to perform operations on the hash field expiration for all hash fields at the
|
||||
* bound {@code key} for the given hash fields.
|
||||
* bound {@link #getKey()} for the given hash fields.
|
||||
*
|
||||
* @param hashFields collection of hash fields to operate on.
|
||||
* @return the bound operations object to perform operations on the hash field expiration.
|
||||
* @since 3.5
|
||||
*/
|
||||
BoundHashFieldExpirationOperations<K> expiration(Collection<K> hashFields);
|
||||
BoundHashFieldExpirationOperations<K> hashFieldExpiration(Collection<K> hashFields);
|
||||
|
||||
}
|
||||
|
||||
@@ -307,13 +307,13 @@ public class RedisProperties extends Properties implements RedisMap<Object, Obje
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoundHashFieldExpirationOperations<Object> expiration() {
|
||||
return (BoundHashFieldExpirationOperations) delegate.expiration();
|
||||
public BoundHashFieldExpirationOperations<Object> hashFieldExpiration() {
|
||||
return (BoundHashFieldExpirationOperations) delegate.hashFieldExpiration();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoundHashFieldExpirationOperations<Object> expiration(Collection<Object> hashFields) {
|
||||
return (BoundHashFieldExpirationOperations) delegate.expiration((Collection) hashFields);
|
||||
public BoundHashFieldExpirationOperations<Object> hashFieldExpiration(Collection<Object> hashFields) {
|
||||
return (BoundHashFieldExpirationOperations) delegate.hashFieldExpiration((Collection) hashFields);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,48 +15,24 @@
|
||||
*/
|
||||
package org.springframework.data.redis.connection;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.assertj.core.api.Assertions.within;
|
||||
import static org.assertj.core.api.Assumptions.assumeThat;
|
||||
import static org.awaitility.Awaitility.await;
|
||||
import static org.junit.jupiter.api.condition.OS.MAC;
|
||||
import static org.springframework.data.redis.connection.BitFieldSubCommands.create;
|
||||
import static org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldIncrBy.Overflow.FAIL;
|
||||
import static org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldType.INT_8;
|
||||
import static org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldType.signed;
|
||||
import static org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldType.unsigned;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.KEY_1;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.KEY_2;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.KEY_3;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.VALUE_1;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.VALUE_2;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.VALUE_3;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.VALUE_4;
|
||||
import static org.springframework.data.redis.connection.RedisGeoCommands.DistanceUnit.KILOMETERS;
|
||||
import static org.springframework.data.redis.connection.RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs;
|
||||
import static org.springframework.data.redis.connection.RedisGeoCommands.GeoRadiusCommandArgs.newGeoSearchArgs;
|
||||
import static org.springframework.data.redis.connection.RedisGeoCommands.GeoSearchStoreCommandArgs.newGeoSearchStoreArgs;
|
||||
import static org.springframework.data.redis.core.ScanOptions.scanOptions;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.assertj.core.api.Assumptions.*;
|
||||
import static org.awaitility.Awaitility.*;
|
||||
import static org.junit.jupiter.api.condition.OS.*;
|
||||
import static org.springframework.data.redis.connection.BitFieldSubCommands.*;
|
||||
import static org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldIncrBy.Overflow.*;
|
||||
import static org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldType.*;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.*;
|
||||
import static org.springframework.data.redis.connection.RedisGeoCommands.DistanceUnit.*;
|
||||
import static org.springframework.data.redis.connection.RedisGeoCommands.GeoRadiusCommandArgs.*;
|
||||
import static org.springframework.data.redis.connection.RedisGeoCommands.GeoSearchStoreCommandArgs.*;
|
||||
import static org.springframework.data.redis.core.ScanOptions.*;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.BlockingDeque;
|
||||
import java.util.concurrent.LinkedBlockingDeque;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -71,6 +47,7 @@ import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.DisabledOnOs;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.data.domain.Range;
|
||||
@@ -215,6 +192,23 @@ public abstract class AbstractConnectionIntegrationTests {
|
||||
await().atMost(Duration.ofMillis(3000L)).until(keyExpired::passes);
|
||||
}
|
||||
|
||||
@LongRunningTest // GH-3114
|
||||
@EnabledOnCommand("SPUBLISH") // Redis 7.0
|
||||
void testExpireWithArgs() {
|
||||
|
||||
actual.add(connection.set("exp", "true"));
|
||||
actual.add(
|
||||
connection.applyExpiration("exp".getBytes(), Expiration.from(Duration.ofMinutes(1)), ExpirationOptions.none()));
|
||||
actual.add(connection.applyExpiration("exp".getBytes(), Expiration.from(Duration.ofMinutes(1)),
|
||||
ExpirationOptions.builder().nx().build()));
|
||||
actual.add(connection.applyExpiration("exp".getBytes(), Expiration.from(Duration.ofMinutes(2)),
|
||||
ExpirationOptions.builder().gt().build()));
|
||||
actual.add(connection.applyExpiration("exp".getBytes(), Expiration.from(Duration.ofMinutes(3)),
|
||||
ExpirationOptions.builder().lt().build()));
|
||||
|
||||
verifyResults(Arrays.asList(true, true, false, true, false));
|
||||
}
|
||||
|
||||
@Test // DATAREDIS-1103
|
||||
void testSetWithKeepTTL() {
|
||||
|
||||
@@ -777,7 +771,25 @@ public abstract class AbstractConnectionIntegrationTests {
|
||||
assertThat(stringSerializer.deserialize((byte[]) getResults().get(1))).isEqualTo("bar");
|
||||
}
|
||||
|
||||
@Test // GH-
|
||||
@Test // GH-3114
|
||||
@EnabledOnCommand("SPUBLISH") // Redis 7.0
|
||||
void testExecuteExpirationWithConditions() {
|
||||
|
||||
actual.add(connection.set("foo", "bar"));
|
||||
actual.add(connection.execute("TTL", "foo"));
|
||||
actual.add(connection.execute("EXPIRE", "foo", "100", "NX"));
|
||||
actual.add(connection.execute("PERSIST", "foo"));
|
||||
actual.add(connection.execute("TTL", "foo"));
|
||||
|
||||
List<Object> results = getResults();
|
||||
|
||||
assertThat(results.get(1)).isEqualTo(-1L);
|
||||
assertThat(results.get(2)).isIn(1L, true);
|
||||
assertThat(results.get(3)).isIn(1L, true);
|
||||
assertThat(results.get(4)).isEqualTo(-1L);
|
||||
}
|
||||
|
||||
@Test // GH-3054
|
||||
@EnabledOnCommand("HEXPIRE")
|
||||
void testExecuteHashFieldExpiration() {
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@ public interface ClusterConnectionTests {
|
||||
void expireAtShouldBeSetCorrectly();
|
||||
|
||||
// DATAREDIS-315
|
||||
void expireShouldBeSetCorreclty();
|
||||
void expireShouldBeSetCorrectly();
|
||||
|
||||
// DATAREDIS-315
|
||||
void flushDbOnSingleNodeShouldFlushOnlyGivenNodesDb();
|
||||
@@ -386,7 +386,7 @@ public interface ClusterConnectionTests {
|
||||
void pExpireAtShouldBeSetCorrectly();
|
||||
|
||||
// DATAREDIS-315
|
||||
void pExpireShouldBeSetCorreclty();
|
||||
void pExpireShouldBeSetCorrectly();
|
||||
|
||||
// DATAREDIS-315
|
||||
void pSetExShouldSetValueCorrectly();
|
||||
|
||||
@@ -273,28 +273,28 @@ public class DefaultStringRedisConnectionTests {
|
||||
|
||||
@Test
|
||||
public void testExpireBytes() {
|
||||
doReturn(true).when(nativeConnection).expire(fooBytes, 1L);
|
||||
doReturn(true).when(nativeConnection).expire(fooBytes, 1L, ExpirationOptions.Condition.ALWAYS);
|
||||
actual.add(connection.expire(fooBytes, 1L));
|
||||
verifyResults(Collections.singletonList(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpire() {
|
||||
doReturn(true).when(nativeConnection).expire(fooBytes, 1L);
|
||||
doReturn(true).when(nativeConnection).expire(fooBytes, 1L, ExpirationOptions.Condition.ALWAYS);
|
||||
actual.add(connection.expire(foo, 1L));
|
||||
verifyResults(Collections.singletonList(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpireAtBytes() {
|
||||
doReturn(true).when(nativeConnection).expireAt(fooBytes, 1L);
|
||||
doReturn(true).when(nativeConnection).expireAt(fooBytes, 1L, ExpirationOptions.Condition.ALWAYS);
|
||||
actual.add(connection.expireAt(fooBytes, 1L));
|
||||
verifyResults(Collections.singletonList(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpireAt() {
|
||||
doReturn(true).when(nativeConnection).expireAt(fooBytes, 1L);
|
||||
doReturn(true).when(nativeConnection).expireAt(fooBytes, 1L, ExpirationOptions.Condition.ALWAYS);
|
||||
actual.add(connection.expireAt(foo, 1L));
|
||||
verifyResults(Collections.singletonList(true));
|
||||
}
|
||||
@@ -1662,28 +1662,28 @@ public class DefaultStringRedisConnectionTests {
|
||||
|
||||
@Test
|
||||
public void testPExpireBytes() {
|
||||
doReturn(true).when(nativeConnection).pExpire(fooBytes, 34L);
|
||||
doReturn(true).when(nativeConnection).pExpire(fooBytes, 34L, ExpirationOptions.Condition.ALWAYS);
|
||||
actual.add(connection.pExpire(fooBytes, 34L));
|
||||
verifyResults(Collections.singletonList(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPExpire() {
|
||||
doReturn(true).when(nativeConnection).pExpire(fooBytes, 34L);
|
||||
doReturn(true).when(nativeConnection).pExpire(fooBytes, 34L, ExpirationOptions.Condition.ALWAYS);
|
||||
actual.add(connection.pExpire(foo, 34L));
|
||||
verifyResults(Collections.singletonList(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPExpireAtBytes() {
|
||||
doReturn(true).when(nativeConnection).pExpireAt(fooBytes, 34L);
|
||||
doReturn(true).when(nativeConnection).pExpireAt(fooBytes, 34L, ExpirationOptions.Condition.ALWAYS);
|
||||
actual.add(connection.pExpireAt(fooBytes, 34L));
|
||||
verifyResults(Collections.singletonList(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPExpireAt() {
|
||||
doReturn(true).when(nativeConnection).pExpireAt(fooBytes, 34L);
|
||||
doReturn(true).when(nativeConnection).pExpireAt(fooBytes, 34L, ExpirationOptions.Condition.ALWAYS);
|
||||
actual.add(connection.pExpireAt(foo, 34L));
|
||||
verifyResults(Collections.singletonList(true));
|
||||
}
|
||||
|
||||
@@ -15,37 +15,18 @@
|
||||
*/
|
||||
package org.springframework.data.redis.connection.jedis;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.assertj.core.data.Offset.*;
|
||||
import static org.assertj.core.data.Offset.offset;
|
||||
import static org.springframework.data.redis.connection.BitFieldSubCommands.create;
|
||||
import static org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldIncrBy.Overflow.FAIL;
|
||||
import static org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldType.INT_8;
|
||||
import static org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldType.signed;
|
||||
import static org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldType.unsigned;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.CLUSTER_HOST;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.KEY_1;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.KEY_2;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.KEY_3;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.MASTER_NODE_1_PORT;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.MASTER_NODE_2_PORT;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.MASTER_NODE_3_PORT;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.REPLICAOF_NODE_1_PORT;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.SAME_SLOT_KEY_1;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.SAME_SLOT_KEY_2;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.SAME_SLOT_KEY_3;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.VALUE_1;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.VALUE_2;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.VALUE_3;
|
||||
import static org.springframework.data.redis.connection.RedisGeoCommands.DistanceUnit.KILOMETERS;
|
||||
import static org.springframework.data.redis.connection.RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs;
|
||||
import static org.springframework.data.redis.connection.RedisListCommands.Direction;
|
||||
import static org.springframework.data.redis.connection.RedisListCommands.Position;
|
||||
import static org.springframework.data.redis.connection.RedisZSetCommands.Range;
|
||||
import static org.springframework.data.redis.core.ScanOptions.NONE;
|
||||
import static org.springframework.data.redis.core.ScanOptions.scanOptions;
|
||||
import static org.springframework.data.redis.connection.BitFieldSubCommands.*;
|
||||
import static org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldIncrBy.Overflow.*;
|
||||
import static org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldType.*;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.*;
|
||||
import static org.springframework.data.redis.connection.RedisGeoCommands.DistanceUnit.*;
|
||||
import static org.springframework.data.redis.connection.RedisGeoCommands.GeoRadiusCommandArgs.*;
|
||||
import static org.springframework.data.redis.connection.RedisListCommands.*;
|
||||
import static org.springframework.data.redis.connection.RedisZSetCommands.*;
|
||||
import static org.springframework.data.redis.core.ScanOptions.*;
|
||||
|
||||
import redis.clients.jedis.ConnectionPool;
|
||||
import redis.clients.jedis.HostAndPort;
|
||||
@@ -57,23 +38,14 @@ import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestInstance;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.domain.Range.Bound;
|
||||
@@ -81,21 +53,13 @@ import org.springframework.data.geo.Circle;
|
||||
import org.springframework.data.geo.Distance;
|
||||
import org.springframework.data.geo.GeoResults;
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.data.redis.connection.BitFieldSubCommands;
|
||||
import org.springframework.data.redis.connection.ClusterConnectionTests;
|
||||
import org.springframework.data.redis.connection.ClusterSlotHashUtil;
|
||||
import org.springframework.data.redis.connection.ClusterTopology;
|
||||
import org.springframework.data.redis.connection.DataType;
|
||||
import org.springframework.data.redis.connection.DefaultSortParameters;
|
||||
import org.springframework.data.redis.connection.*;
|
||||
import org.springframework.data.redis.connection.Limit;
|
||||
import org.springframework.data.redis.connection.RedisClusterNode;
|
||||
import org.springframework.data.redis.connection.RedisClusterNode.SlotRange;
|
||||
import org.springframework.data.redis.connection.RedisGeoCommands.GeoLocation;
|
||||
import org.springframework.data.redis.connection.RedisNode;
|
||||
import org.springframework.data.redis.connection.RedisServerCommands.FlushOption;
|
||||
import org.springframework.data.redis.connection.RedisStringCommands.BitOperation;
|
||||
import org.springframework.data.redis.connection.RedisStringCommands.SetOption;
|
||||
import org.springframework.data.redis.connection.ReturnType;
|
||||
import org.springframework.data.redis.connection.ValueEncoding.RedisValueEncoding;
|
||||
import org.springframework.data.redis.connection.zset.DefaultTuple;
|
||||
import org.springframework.data.redis.connection.zset.Tuple;
|
||||
@@ -472,8 +436,24 @@ public class JedisClusterConnectionTests implements ClusterConnectionTests {
|
||||
assertThat(nativeConnection.ttl(JedisConverters.toString(KEY_1_BYTES))).isGreaterThan(1);
|
||||
}
|
||||
|
||||
@Test // GH-3114
|
||||
@EnabledOnCommand("SPUBLISH") // Redis 7.0
|
||||
public void expireAtWithConditionShouldBeSetCorrectly() {
|
||||
|
||||
nativeConnection.set(KEY_1, VALUE_1);
|
||||
|
||||
assertThat(clusterConnection.expireAt(KEY_1_BYTES, System.currentTimeMillis() / 1000 + 5000,
|
||||
ExpirationOptions.Condition.XX)).isFalse();
|
||||
assertThat(clusterConnection.expireAt(KEY_1_BYTES, System.currentTimeMillis() / 1000 + 5000,
|
||||
ExpirationOptions.Condition.NX)).isTrue();
|
||||
assertThat(clusterConnection.expireAt(KEY_1_BYTES, System.currentTimeMillis() / 1000 + 15000,
|
||||
ExpirationOptions.Condition.LT)).isFalse();
|
||||
|
||||
assertThat(nativeConnection.ttl(JedisConverters.toString(KEY_1_BYTES))).isGreaterThan(1);
|
||||
}
|
||||
|
||||
@Test // DATAREDIS-315
|
||||
public void expireShouldBeSetCorreclty() {
|
||||
public void expireShouldBeSetCorrectly() {
|
||||
|
||||
nativeConnection.set(KEY_1, VALUE_1);
|
||||
|
||||
@@ -482,6 +462,19 @@ public class JedisClusterConnectionTests implements ClusterConnectionTests {
|
||||
assertThat(nativeConnection.ttl(JedisConverters.toString(KEY_1_BYTES))).isGreaterThan(1);
|
||||
}
|
||||
|
||||
@Test // GH-3114
|
||||
@EnabledOnCommand("SPUBLISH") // Redis 7.0
|
||||
public void expireWithConditionShouldBeSetCorrectly() {
|
||||
|
||||
nativeConnection.set(KEY_1, VALUE_1);
|
||||
|
||||
assertThat(clusterConnection.expire(KEY_1_BYTES, 15, ExpirationOptions.Condition.XX)).isFalse();
|
||||
assertThat(clusterConnection.expire(KEY_1_BYTES, 15, ExpirationOptions.Condition.NX)).isTrue();
|
||||
assertThat(clusterConnection.expire(KEY_1_BYTES, 15, ExpirationOptions.Condition.LT)).isFalse();
|
||||
|
||||
assertThat(nativeConnection.ttl(JedisConverters.toString(KEY_1_BYTES))).isGreaterThan(1);
|
||||
}
|
||||
|
||||
@Test // DATAREDIS-315
|
||||
public void flushDbOnSingleNodeShouldFlushOnlyGivenNodesDb() {
|
||||
|
||||
@@ -1597,8 +1590,27 @@ public class JedisClusterConnectionTests implements ClusterConnectionTests {
|
||||
assertThat(nativeConnection.ttl(JedisConverters.toString(KEY_1_BYTES))).isGreaterThan(1);
|
||||
}
|
||||
|
||||
@Test // GH-3114
|
||||
@EnabledOnCommand("SPUBLISH") // Redis 7.0
|
||||
public void pExpireAtWithConditionShouldBeSetCorrectly() {
|
||||
|
||||
nativeConnection.set(KEY_1, VALUE_1);
|
||||
|
||||
assertThat(
|
||||
clusterConnection.pExpireAt(KEY_1_BYTES, System.currentTimeMillis() + 5000, ExpirationOptions.Condition.XX))
|
||||
.isFalse();
|
||||
assertThat(
|
||||
clusterConnection.pExpireAt(KEY_1_BYTES, System.currentTimeMillis() + 5000, ExpirationOptions.Condition.NX))
|
||||
.isTrue();
|
||||
assertThat(
|
||||
clusterConnection.pExpireAt(KEY_1_BYTES, System.currentTimeMillis() + 15000, ExpirationOptions.Condition.LT))
|
||||
.isFalse();
|
||||
|
||||
assertThat(nativeConnection.ttl(JedisConverters.toString(KEY_1_BYTES))).isGreaterThan(1);
|
||||
}
|
||||
|
||||
@Test // DATAREDIS-315
|
||||
public void pExpireShouldBeSetCorreclty() {
|
||||
public void pExpireShouldBeSetCorrectly() {
|
||||
|
||||
nativeConnection.set(KEY_1, VALUE_1);
|
||||
|
||||
@@ -1607,6 +1619,19 @@ public class JedisClusterConnectionTests implements ClusterConnectionTests {
|
||||
assertThat(nativeConnection.ttl(JedisConverters.toString(KEY_1_BYTES))).isGreaterThan(1);
|
||||
}
|
||||
|
||||
@Test // GH-3114
|
||||
@EnabledOnCommand("SPUBLISH") // Redis 7.0
|
||||
public void pExpireWithConditionShouldBeSetCorrectly() {
|
||||
|
||||
nativeConnection.set(KEY_1, VALUE_1);
|
||||
|
||||
assertThat(clusterConnection.pExpire(KEY_1_BYTES, 15000, ExpirationOptions.Condition.XX)).isFalse();
|
||||
assertThat(clusterConnection.pExpire(KEY_1_BYTES, 15000, ExpirationOptions.Condition.NX)).isTrue();
|
||||
assertThat(clusterConnection.pExpire(KEY_1_BYTES, 15000, ExpirationOptions.Condition.LT)).isFalse();
|
||||
|
||||
assertThat(nativeConnection.ttl(JedisConverters.toString(KEY_1_BYTES))).isGreaterThan(1);
|
||||
}
|
||||
|
||||
@Test // DATAREDIS-315
|
||||
public void pSetExShouldSetValueCorrectly() {
|
||||
|
||||
|
||||
@@ -15,35 +15,17 @@
|
||||
*/
|
||||
package org.springframework.data.redis.connection.lettuce;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.assertj.core.data.Offset.*;
|
||||
import static org.assertj.core.data.Offset.offset;
|
||||
import static org.springframework.data.redis.connection.BitFieldSubCommands.create;
|
||||
import static org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldIncrBy.Overflow.FAIL;
|
||||
import static org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldType.INT_8;
|
||||
import static org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldType.signed;
|
||||
import static org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldType.unsigned;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.CLUSTER_HOST;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.KEY_1;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.KEY_2;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.KEY_3;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.KEY_4;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.MASTER_NODE_1_PORT;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.MASTER_NODE_2_PORT;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.MASTER_NODE_3_PORT;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.REPLICAOF_NODE_1_PORT;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.SAME_SLOT_KEY_1;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.SAME_SLOT_KEY_2;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.SAME_SLOT_KEY_3;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.VALUE_1;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.VALUE_2;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.VALUE_3;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.VALUE_4;
|
||||
import static org.springframework.data.redis.connection.RedisGeoCommands.DistanceUnit.KILOMETERS;
|
||||
import static org.springframework.data.redis.connection.RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs;
|
||||
import static org.springframework.data.redis.connection.RedisZSetCommands.Range;
|
||||
import static org.springframework.data.redis.core.ScanOptions.scanOptions;
|
||||
import static org.springframework.data.redis.connection.BitFieldSubCommands.*;
|
||||
import static org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldIncrBy.Overflow.*;
|
||||
import static org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldType.*;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.*;
|
||||
import static org.springframework.data.redis.connection.RedisGeoCommands.DistanceUnit.*;
|
||||
import static org.springframework.data.redis.connection.RedisGeoCommands.GeoRadiusCommandArgs.*;
|
||||
import static org.springframework.data.redis.connection.RedisZSetCommands.*;
|
||||
import static org.springframework.data.redis.core.ScanOptions.*;
|
||||
|
||||
import io.lettuce.core.cluster.RedisClusterClient;
|
||||
import io.lettuce.core.cluster.api.sync.RedisAdvancedClusterCommands;
|
||||
@@ -52,17 +34,7 @@ import io.lettuce.core.codec.ByteArrayCodec;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.assertj.core.data.Offset;
|
||||
@@ -71,6 +43,7 @@ import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestInstance;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.domain.Range.Bound;
|
||||
@@ -78,21 +51,11 @@ import org.springframework.data.geo.Circle;
|
||||
import org.springframework.data.geo.Distance;
|
||||
import org.springframework.data.geo.GeoResults;
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.data.redis.connection.BitFieldSubCommands;
|
||||
import org.springframework.data.redis.connection.ClusterConnectionTests;
|
||||
import org.springframework.data.redis.connection.ClusterSlotHashUtil;
|
||||
import org.springframework.data.redis.connection.ClusterTestVariables;
|
||||
import org.springframework.data.redis.connection.DataType;
|
||||
import org.springframework.data.redis.connection.DefaultSortParameters;
|
||||
import org.springframework.data.redis.connection.*;
|
||||
import org.springframework.data.redis.connection.Limit;
|
||||
import org.springframework.data.redis.connection.RedisClusterConfiguration;
|
||||
import org.springframework.data.redis.connection.RedisClusterConnection;
|
||||
import org.springframework.data.redis.connection.RedisClusterNode;
|
||||
import org.springframework.data.redis.connection.RedisClusterNode.SlotRange;
|
||||
import org.springframework.data.redis.connection.RedisGeoCommands.GeoLocation;
|
||||
import org.springframework.data.redis.connection.RedisListCommands;
|
||||
import org.springframework.data.redis.connection.RedisListCommands.Position;
|
||||
import org.springframework.data.redis.connection.RedisNode;
|
||||
import org.springframework.data.redis.connection.RedisServerCommands.FlushOption;
|
||||
import org.springframework.data.redis.connection.RedisStringCommands.BitOperation;
|
||||
import org.springframework.data.redis.connection.RedisStringCommands.SetOption;
|
||||
@@ -538,8 +501,24 @@ public class LettuceClusterConnectionTests implements ClusterConnectionTests {
|
||||
assertThat(nativeConnection.ttl(LettuceConverters.toString(KEY_1_BYTES))).isGreaterThan(1);
|
||||
}
|
||||
|
||||
@Test // GH-3114
|
||||
@EnabledOnCommand("SPUBLISH") // Redis 7.0
|
||||
public void expireAtWithConditionShouldBeSetCorrectly() {
|
||||
|
||||
nativeConnection.set(KEY_1, VALUE_1);
|
||||
|
||||
assertThat(clusterConnection.expireAt(KEY_1_BYTES, System.currentTimeMillis() / 1000 + 5000,
|
||||
ExpirationOptions.Condition.XX)).isFalse();
|
||||
assertThat(clusterConnection.expireAt(KEY_1_BYTES, System.currentTimeMillis() / 1000 + 5000,
|
||||
ExpirationOptions.Condition.NX)).isTrue();
|
||||
assertThat(clusterConnection.expireAt(KEY_1_BYTES, System.currentTimeMillis() / 1000 + 10000,
|
||||
ExpirationOptions.Condition.LT)).isFalse();
|
||||
|
||||
assertThat(nativeConnection.ttl(LettuceConverters.toString(KEY_1_BYTES))).isGreaterThan(1);
|
||||
}
|
||||
|
||||
@Test // DATAREDIS-315
|
||||
public void expireShouldBeSetCorreclty() {
|
||||
public void expireShouldBeSetCorrectly() {
|
||||
|
||||
nativeConnection.set(KEY_1, VALUE_1);
|
||||
|
||||
@@ -548,6 +527,19 @@ public class LettuceClusterConnectionTests implements ClusterConnectionTests {
|
||||
assertThat(nativeConnection.ttl(LettuceConverters.toString(KEY_1_BYTES))).isGreaterThan(1);
|
||||
}
|
||||
|
||||
@Test // GH-3114
|
||||
@EnabledOnCommand("SPUBLISH") // Redis 7.0
|
||||
public void expireWithConditionShouldBeSetCorrectly() {
|
||||
|
||||
nativeConnection.set(KEY_1, VALUE_1);
|
||||
|
||||
assertThat(clusterConnection.expire(KEY_1_BYTES, 15, ExpirationOptions.Condition.XX)).isFalse();
|
||||
assertThat(clusterConnection.expire(KEY_1_BYTES, 15, ExpirationOptions.Condition.NX)).isTrue();
|
||||
assertThat(clusterConnection.expire(KEY_1_BYTES, 15, ExpirationOptions.Condition.LT)).isFalse();
|
||||
|
||||
assertThat(nativeConnection.ttl(LettuceConverters.toString(KEY_1_BYTES))).isGreaterThan(1);
|
||||
}
|
||||
|
||||
@Test // DATAREDIS-315
|
||||
public void flushDbOnSingleNodeShouldFlushOnlyGivenNodesDb() {
|
||||
|
||||
@@ -1666,8 +1658,27 @@ public class LettuceClusterConnectionTests implements ClusterConnectionTests {
|
||||
assertThat(nativeConnection.ttl(LettuceConverters.toString(KEY_1_BYTES))).isGreaterThan(1);
|
||||
}
|
||||
|
||||
@Test // GH-3114
|
||||
@EnabledOnCommand("SPUBLISH") // Redis 7.0
|
||||
public void pExpireAtWithConditionShouldBeSetCorrectly() {
|
||||
|
||||
nativeConnection.set(KEY_1, VALUE_1);
|
||||
|
||||
assertThat(
|
||||
clusterConnection.pExpireAt(KEY_1_BYTES, System.currentTimeMillis() + 5000, ExpirationOptions.Condition.XX))
|
||||
.isFalse();
|
||||
assertThat(
|
||||
clusterConnection.pExpireAt(KEY_1_BYTES, System.currentTimeMillis() + 5000, ExpirationOptions.Condition.NX))
|
||||
.isTrue();
|
||||
assertThat(
|
||||
clusterConnection.pExpireAt(KEY_1_BYTES, System.currentTimeMillis() + 15000, ExpirationOptions.Condition.LT))
|
||||
.isFalse();
|
||||
|
||||
assertThat(nativeConnection.ttl(LettuceConverters.toString(KEY_1_BYTES))).isGreaterThan(1);
|
||||
}
|
||||
|
||||
@Test // DATAREDIS-315
|
||||
public void pExpireShouldBeSetCorreclty() {
|
||||
public void pExpireShouldBeSetCorrectly() {
|
||||
|
||||
nativeConnection.set(KEY_1, VALUE_1);
|
||||
|
||||
@@ -1676,6 +1687,19 @@ public class LettuceClusterConnectionTests implements ClusterConnectionTests {
|
||||
assertThat(nativeConnection.ttl(LettuceConverters.toString(KEY_1_BYTES))).isGreaterThan(1);
|
||||
}
|
||||
|
||||
@Test // GH-3114
|
||||
@EnabledOnCommand("SPUBLISH") // Redis 7.0
|
||||
public void pExpireWithConditionShouldBeSetCorrectly() {
|
||||
|
||||
nativeConnection.set(KEY_1, VALUE_1);
|
||||
|
||||
assertThat(clusterConnection.pExpire(KEY_1_BYTES, 15000, ExpirationOptions.Condition.XX)).isFalse();
|
||||
assertThat(clusterConnection.pExpire(KEY_1_BYTES, 15000, ExpirationOptions.Condition.NX)).isTrue();
|
||||
assertThat(clusterConnection.pExpire(KEY_1_BYTES, 15000, ExpirationOptions.Condition.LT)).isFalse();
|
||||
|
||||
assertThat(nativeConnection.ttl(LettuceConverters.toString(KEY_1_BYTES))).isGreaterThan(1);
|
||||
}
|
||||
|
||||
@Test // DATAREDIS-315
|
||||
public void pSetExShouldSetValueCorrectly() {
|
||||
|
||||
|
||||
@@ -32,11 +32,15 @@ import java.util.List;
|
||||
|
||||
import org.springframework.data.redis.RedisSystemException;
|
||||
import org.springframework.data.redis.connection.DataType;
|
||||
import org.springframework.data.redis.connection.ExpirationOptions;
|
||||
import org.springframework.data.redis.connection.ReactiveKeyCommands;
|
||||
import org.springframework.data.redis.connection.ReactiveRedisConnection;
|
||||
import org.springframework.data.redis.connection.ReactiveRedisConnection.KeyCommand;
|
||||
import org.springframework.data.redis.connection.ReactiveRedisConnection.NumericResponse;
|
||||
import org.springframework.data.redis.connection.ValueEncoding.RedisValueEncoding;
|
||||
import org.springframework.data.redis.core.KeyScanOptions;
|
||||
import org.springframework.data.redis.core.ScanOptions;
|
||||
import org.springframework.data.redis.core.types.Expiration;
|
||||
import org.springframework.data.redis.test.condition.EnabledOnCommand;
|
||||
import org.springframework.data.redis.test.condition.EnabledOnRedisVersion;
|
||||
import org.springframework.data.redis.test.extension.parametrized.ParameterizedRedisTest;
|
||||
@@ -303,6 +307,35 @@ public class LettuceReactiveKeyCommandsIntegrationTests extends LettuceReactiveC
|
||||
assertThat(nativeCommands.ttl(KEY_1)).isGreaterThan(8L);
|
||||
}
|
||||
|
||||
@ParameterizedRedisTest // GH-3114
|
||||
@EnabledOnCommand("SPUBLISH") // Redis 7.0
|
||||
void shouldExpireWithOptionsKeysCorrectly() {
|
||||
|
||||
nativeCommands.set(KEY_1, VALUE_1);
|
||||
|
||||
connection.keyCommands()
|
||||
.applyExpiration(
|
||||
Mono.just(ReactiveKeyCommands.ExpireCommand.expire(KEY_1_BBUFFER, Expiration.from(Duration.ofSeconds(10)))
|
||||
.withOptions(ExpirationOptions.builder().xx().build())))
|
||||
.map(ReactiveRedisConnection.BooleanResponse::getOutput).as(StepVerifier::create) //
|
||||
.expectNext(false) //
|
||||
.expectComplete() //
|
||||
.verify();
|
||||
|
||||
assertThat(nativeCommands.ttl(KEY_1)).isEqualTo(-1L);
|
||||
|
||||
connection.keyCommands()
|
||||
.applyExpiration(
|
||||
Mono.just(ReactiveKeyCommands.ExpireCommand.expire(KEY_1_BBUFFER, Expiration.from(Duration.ofSeconds(10)))
|
||||
.withOptions(ExpirationOptions.builder().nx().build())))
|
||||
.map(ReactiveRedisConnection.BooleanResponse::getOutput).as(StepVerifier::create) //
|
||||
.expectNext(true) //
|
||||
.expectComplete() //
|
||||
.verify();
|
||||
|
||||
assertThat(nativeCommands.ttl(KEY_1)).isGreaterThan(8L);
|
||||
}
|
||||
|
||||
@ParameterizedRedisTest // DATAREDIS-602, DATAREDIS-1031
|
||||
void shouldPreciseExpireKeysCorrectly() {
|
||||
|
||||
|
||||
@@ -15,9 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.redis.core;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assumptions.assumeThat;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.assertj.core.api.Assumptions.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Duration;
|
||||
@@ -30,10 +29,11 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.assertj.core.api.InstanceOfAssertFactories;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
||||
import org.springframework.data.redis.ObjectFactory;
|
||||
import org.springframework.data.redis.RawObjectFactory;
|
||||
import org.springframework.data.redis.StringObjectFactory;
|
||||
import org.springframework.data.redis.connection.Hash.FieldExpirationOptions;
|
||||
import org.springframework.data.redis.connection.ExpirationOptions;
|
||||
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
|
||||
import org.springframework.data.redis.connection.jedis.extension.JedisConnectionFactoryExtension;
|
||||
import org.springframework.data.redis.core.ExpireChanges.ExpiryChangeState;
|
||||
@@ -281,7 +281,7 @@ public class DefaultHashOperationsIntegrationTests<K, HK, HV> {
|
||||
hashOps.put(key, key2, val2);
|
||||
|
||||
BoundHashOperations<K, HK, HV> hashOps = redisTemplate.boundHashOps(key);
|
||||
BoundHashFieldExpirationOperations<HK> exp = hashOps.expiration(key1, key2);
|
||||
BoundHashFieldExpirationOperations<HK> exp = hashOps.hashExpiration(key1, key2);
|
||||
|
||||
assertThat(exp.expire(Duration.ofSeconds(5))).satisfies(changes -> {
|
||||
assertThat(changes.allOk()).isTrue();
|
||||
@@ -350,7 +350,7 @@ public class DefaultHashOperationsIntegrationTests<K, HK, HV> {
|
||||
hashOps.put(key, key2, val2);
|
||||
|
||||
ExpireChanges<Object> expire = redisTemplate.opsForHash().expire(key,
|
||||
org.springframework.data.redis.core.types.Expiration.seconds(20), FieldExpirationOptions.none(), List.of(key1));
|
||||
org.springframework.data.redis.core.types.Expiration.seconds(20), ExpirationOptions.none(), List.of(key1));
|
||||
|
||||
assertThat(expire.allOk()).isTrue();
|
||||
}
|
||||
@@ -369,12 +369,12 @@ public class DefaultHashOperationsIntegrationTests<K, HK, HV> {
|
||||
hashOps.put(key, key2, val2);
|
||||
|
||||
redisTemplate.opsForHash().expire(key, org.springframework.data.redis.core.types.Expiration.seconds(20),
|
||||
FieldExpirationOptions.none(), List.of(key1));
|
||||
ExpirationOptions.none(), List.of(key1));
|
||||
redisTemplate.opsForHash().expire(key, org.springframework.data.redis.core.types.Expiration.seconds(60),
|
||||
FieldExpirationOptions.none(), List.of(key2));
|
||||
ExpirationOptions.none(), List.of(key2));
|
||||
|
||||
ExpireChanges<Object> changes = redisTemplate.opsForHash().expire(key,
|
||||
org.springframework.data.redis.core.types.Expiration.seconds(30), FieldExpirationOptions.builder().gt().build(),
|
||||
org.springframework.data.redis.core.types.Expiration.seconds(30), ExpirationOptions.builder().gt().build(),
|
||||
List.of(key1, key2));
|
||||
|
||||
assertThat(changes.ok()).containsExactly(key1);
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
*/
|
||||
package org.springframework.data.redis.core;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assumptions.assumeThat;
|
||||
import static org.junit.jupiter.api.condition.OS.MAC;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.assertj.core.api.Assumptions.*;
|
||||
import static org.junit.jupiter.api.condition.OS.*;
|
||||
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
@@ -33,11 +33,12 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.condition.DisabledOnOs;
|
||||
|
||||
import org.springframework.data.redis.ObjectFactory;
|
||||
import org.springframework.data.redis.RawObjectFactory;
|
||||
import org.springframework.data.redis.SettingsUtils;
|
||||
import org.springframework.data.redis.StringObjectFactory;
|
||||
import org.springframework.data.redis.connection.Hash.FieldExpirationOptions;
|
||||
import org.springframework.data.redis.connection.ExpirationOptions;
|
||||
import org.springframework.data.redis.connection.RedisConnection;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.connection.convert.Converters;
|
||||
@@ -543,14 +544,14 @@ public class DefaultReactiveHashOperationsIntegrationTests<K, HK, HV> {
|
||||
putAll(key, key1, val1, key2, val2);
|
||||
|
||||
hashOperations
|
||||
.expire(key, org.springframework.data.redis.core.types.Expiration.seconds(20), FieldExpirationOptions.none(),
|
||||
.expire(key, org.springframework.data.redis.core.types.Expiration.seconds(20), ExpirationOptions.none(),
|
||||
List.of(key1))
|
||||
.as(StepVerifier::create)//
|
||||
.assertNext(changes -> {
|
||||
assertThat(changes.allOk()).isTrue();
|
||||
}).verifyComplete();
|
||||
hashOperations
|
||||
.expire(key, org.springframework.data.redis.core.types.Expiration.seconds(60), FieldExpirationOptions.none(),
|
||||
.expire(key, org.springframework.data.redis.core.types.Expiration.seconds(60), ExpirationOptions.none(),
|
||||
List.of(key2))
|
||||
.as(StepVerifier::create)//
|
||||
.assertNext(changes -> {
|
||||
@@ -559,7 +560,7 @@ public class DefaultReactiveHashOperationsIntegrationTests<K, HK, HV> {
|
||||
|
||||
hashOperations
|
||||
.expire(key, org.springframework.data.redis.core.types.Expiration.seconds(30),
|
||||
FieldExpirationOptions.builder().gt().build(), List.of(key1, key2))
|
||||
ExpirationOptions.builder().gt().build(), List.of(key1, key2))
|
||||
.as(StepVerifier::create)//
|
||||
.assertNext(changes -> {
|
||||
assertThat(changes.ok()).containsExactly(key1);
|
||||
|
||||
@@ -37,6 +37,7 @@ import org.springframework.data.redis.Person;
|
||||
import org.springframework.data.redis.PersonObjectFactory;
|
||||
import org.springframework.data.redis.StringObjectFactory;
|
||||
import org.springframework.data.redis.connection.DataType;
|
||||
import org.springframework.data.redis.connection.ExpirationOptions;
|
||||
import org.springframework.data.redis.connection.ReactiveRedisClusterConnection;
|
||||
import org.springframework.data.redis.connection.ReactiveSubscription.ChannelMessage;
|
||||
import org.springframework.data.redis.connection.ReactiveSubscription.Message;
|
||||
@@ -45,6 +46,7 @@ import org.springframework.data.redis.connection.RedisConnection;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.ReactiveOperationsTestParams.Fixture;
|
||||
import org.springframework.data.redis.core.script.DefaultRedisScript;
|
||||
import org.springframework.data.redis.core.types.Expiration;
|
||||
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
|
||||
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
|
||||
import org.springframework.data.redis.serializer.RedisElementReader;
|
||||
@@ -323,6 +325,24 @@ public class ReactiveRedisTemplateIntegrationTests<K, V> {
|
||||
.consumeNextWith(actual -> assertThat(actual).isGreaterThan(Duration.ofSeconds(8))).verifyComplete();
|
||||
}
|
||||
|
||||
@ParameterizedRedisTest // GH-3114
|
||||
@EnabledOnCommand("SPUBLISH") // Redis 7.0
|
||||
void expireWithCondition() {
|
||||
|
||||
K key = keyFactory.instance();
|
||||
V value = valueFactory.instance();
|
||||
|
||||
redisTemplate.opsForValue().set(key, value).as(StepVerifier::create).expectNext(true).verifyComplete();
|
||||
|
||||
redisTemplate.expire(key, Expiration.seconds(10), ExpirationOptions.none()).as(StepVerifier::create)
|
||||
.expectNext(ExpireChanges.ExpiryChangeState.OK).verifyComplete();
|
||||
redisTemplate.expire(key, Expiration.seconds(20), ExpirationOptions.builder().lt().build()).as(StepVerifier::create)
|
||||
.expectNext(ExpireChanges.ExpiryChangeState.CONDITION_NOT_MET).verifyComplete();
|
||||
|
||||
redisTemplate.getExpire(key).as(StepVerifier::create) //
|
||||
.consumeNextWith(actual -> assertThat(actual).isGreaterThan(Duration.ofSeconds(5))).verifyComplete();
|
||||
}
|
||||
|
||||
@ParameterizedRedisTest // DATAREDIS-602
|
||||
void preciseExpire() {
|
||||
|
||||
@@ -337,6 +357,24 @@ public class ReactiveRedisTemplateIntegrationTests<K, V> {
|
||||
.consumeNextWith(actual -> assertThat(actual).isGreaterThan(Duration.ofSeconds(8))).verifyComplete();
|
||||
}
|
||||
|
||||
@ParameterizedRedisTest // GH-3114
|
||||
@EnabledOnCommand("SPUBLISH") // Redis 7.0
|
||||
void preciseExpireWithCondition() {
|
||||
|
||||
K key = keyFactory.instance();
|
||||
V value = valueFactory.instance();
|
||||
|
||||
redisTemplate.opsForValue().set(key, value).as(StepVerifier::create).expectNext(true).verifyComplete();
|
||||
|
||||
redisTemplate.expire(key, Expiration.milliseconds(10000), ExpirationOptions.none()).as(StepVerifier::create)
|
||||
.expectNext(ExpireChanges.ExpiryChangeState.OK).verifyComplete();
|
||||
redisTemplate.expire(key, Expiration.milliseconds(20000), ExpirationOptions.builder().lt().build())
|
||||
.as(StepVerifier::create).expectNext(ExpireChanges.ExpiryChangeState.CONDITION_NOT_MET).verifyComplete();
|
||||
|
||||
redisTemplate.getExpire(key).as(StepVerifier::create) //
|
||||
.consumeNextWith(actual -> assertThat(actual).isGreaterThan(Duration.ofSeconds(5))).verifyComplete();
|
||||
}
|
||||
|
||||
@ParameterizedRedisTest // DATAREDIS-602
|
||||
void expireAt() {
|
||||
|
||||
|
||||
@@ -15,9 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.redis.support.collections;
|
||||
|
||||
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
|
||||
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assumptions.assumeThat;
|
||||
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.*;
|
||||
import static org.assertj.core.api.Assumptions.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.DecimalFormat;
|
||||
@@ -36,6 +35,7 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.assertj.core.api.Assumptions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.redis.DoubleAsStringObjectFactory;
|
||||
import org.springframework.data.redis.LongAsStringObjectFactory;
|
||||
@@ -205,7 +205,7 @@ public abstract class AbstractRedisMapIntegrationTests<K, V> {
|
||||
V v1 = getValue();
|
||||
assertThat(map.put(k1, v1)).isEqualTo(null);
|
||||
|
||||
BoundHashFieldExpirationOperations<K> ops = map.expiration(Collections.singletonList(k1));
|
||||
BoundHashFieldExpirationOperations<K> ops = map.hashFieldExpiration(Collections.singletonList(k1));
|
||||
assertThat(ops.expire(Duration.ofSeconds(5))).satisfies(ExpireChanges::allOk);
|
||||
assertThat(ops.getTimeToLive()).satisfies(expiration -> {
|
||||
assertThat(expiration.expirationOf(k1).raw()).isBetween(1L, 5L);
|
||||
@@ -224,7 +224,7 @@ public abstract class AbstractRedisMapIntegrationTests<K, V> {
|
||||
V v1 = getValue();
|
||||
assertThat(map.put(k1, v1)).isEqualTo(null);
|
||||
|
||||
BoundHashFieldExpirationOperations<K> ops = map.expiration(Collections.singletonList(k1));
|
||||
BoundHashFieldExpirationOperations<K> ops = map.hashFieldExpiration(Collections.singletonList(k1));
|
||||
assertThat(ops.expireAt(Instant.now().plusSeconds(5))).satisfies(ExpireChanges::allOk);
|
||||
assertThat(ops.getTimeToLive()).satisfies(expiration -> {
|
||||
assertThat(expiration.expirationOf(k1).raw()).isBetween(1L, 5L);
|
||||
|
||||
Reference in New Issue
Block a user