Skip to content

Commit cde3b58

Browse files
committed
Add support for GETEX and GETDEL through getAndExpire(…), getAndPersist(…) and getAndDelete(…) methods.
We now support Redis 6.2 GETEX and GETDEL commands through the Template API and on the connection level for all drivers.
1 parent 1fbfc5a commit cde3b58

25 files changed

+851
-8
lines changed

src/main/asciidoc/new-features.adoc

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ This section briefly covers items that are new and noteworthy in the latest rele
77
== New in Spring Data Redis 2.6
88

99
* Support for `SubscriptionListener` when using `MessageListener` for subscription confirmation callbacks. `ReactiveRedisMessageListenerContainer` and `ReactiveRedisOperations` provide `receiveLater(…)` and `listenToLater(…)` methods to await until Redis acknowledges the subscription.
10-
* Support Redis 6.2 commands (`LPOP`/`RPOP` with `count`).
10+
* Support Redis 6.2 commands (`LPOP`/`RPOP` with `count`, `GETEX`, `GETDEL`).
1111

1212
[[new-in-2.5.0]]
1313
== New in Spring Data Redis 2.5

src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java

+40
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,46 @@ public byte[] get(byte[] key) {
399399
return convertAndReturn(delegate.get(key), Converters.identityConverter());
400400
}
401401

402+
/*
403+
* (non-Javadoc)
404+
* @see org.springframework.data.redis.connection.RedisStringCommands#getDel(byte[])
405+
*/
406+
@Nullable
407+
@Override
408+
public byte[] getDel(byte[] key) {
409+
return convertAndReturn(delegate.getDel(key), Converters.identityConverter());
410+
}
411+
412+
/*
413+
* (non-Javadoc)
414+
* @see org.springframework.data.redis.connection.RedisStringCommands#getDel(byte[])
415+
*/
416+
@Nullable
417+
@Override
418+
public String getDel(String key) {
419+
return convertAndReturn(delegate.getDel(serialize(key)), bytesToString);
420+
}
421+
422+
/*
423+
* (non-Javadoc)
424+
* @see org.springframework.data.redis.connection.RedisStringCommands#get(byte[], org.springframework.data.redis.core.types.Expiration)
425+
*/
426+
@Nullable
427+
@Override
428+
public byte[] getEx(byte[] key, Expiration expiration) {
429+
return convertAndReturn(delegate.getEx(key, expiration), Converters.identityConverter());
430+
}
431+
432+
/*
433+
* (non-Javadoc)
434+
* @see org.springframework.data.redis.connection.RedisStringCommands#get(byte[], org.springframework.data.redis.core.types.Expiration)
435+
*/
436+
@Nullable
437+
@Override
438+
public String getEx(String key, Expiration expiration) {
439+
return convertAndReturn(delegate.getEx(serialize(key), expiration), bytesToString);
440+
}
441+
402442
/*
403443
* (non-Javadoc)
404444
* @see org.springframework.data.redis.connection.RedisStringCommands#getBit(byte[], long)

src/main/java/org/springframework/data/redis/connection/DefaultedRedisConnection.java

+14
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,20 @@ default byte[] get(byte[] key) {
268268
return stringCommands().get(key);
269269
}
270270

271+
/** @deprecated in favor of {@link RedisConnection#stringCommands()}}. */
272+
@Override
273+
@Deprecated
274+
default byte[] getEx(byte[] key, Expiration expiration) {
275+
return stringCommands().getEx(key, expiration);
276+
}
277+
278+
/** @deprecated in favor of {@link RedisConnection#stringCommands()}}. */
279+
@Override
280+
@Deprecated
281+
default byte[] getDel(byte[] key) {
282+
return stringCommands().getDel(key);
283+
}
284+
271285
/** @deprecated in favor of {@link RedisConnection#stringCommands()}}. */
272286
@Override
273287
@Deprecated

src/main/java/org/springframework/data/redis/connection/ReactiveStringCommands.java

+103
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,109 @@ default Mono<ByteBuffer> get(ByteBuffer key) {
218218
*/
219219
Flux<ByteBufferResponse<KeyCommand>> get(Publisher<KeyCommand> keys);
220220

221+
/**
222+
* Return the value at {@code key} and delete the key.
223+
*
224+
* @param key must not be {@literal null}.
225+
* @return {@link Mono#empty()} in case {@literal key} does not exist.
226+
* @see <a href="https://redis.io/commands/getdel">Redis Documentation: GETDEL</a>
227+
* @since 2.6
228+
*/
229+
default Mono<ByteBuffer> getDel(ByteBuffer key) {
230+
231+
Assert.notNull(key, "Key must not be null!");
232+
233+
return getDel(Mono.just(new KeyCommand(key))).next().filter(CommandResponse::isPresent)
234+
.map(CommandResponse::getOutput);
235+
}
236+
237+
/**
238+
* Return the value at {@code key} and delete the key.
239+
*
240+
* @param commands must not be {@literal null}.
241+
* @return {@link Flux} of {@link ByteBufferResponse} holding the {@literal key} to get along with the value
242+
* retrieved.
243+
* @see <a href="https://redis.io/commands/getdel">Redis Documentation: GETDEL</a>
244+
* @since 2.6
245+
*/
246+
Flux<ByteBufferResponse<KeyCommand>> getDel(Publisher<KeyCommand> commands);
247+
248+
/**
249+
* {@link Command} for {@code GETEX}.
250+
*
251+
* @author Mark Paluch
252+
* @since 2.6
253+
*/
254+
class GetExCommand extends KeyCommand {
255+
256+
private final Expiration expiration;
257+
258+
private GetExCommand(@Nullable ByteBuffer key, Expiration expiration) {
259+
260+
super(key);
261+
262+
Assert.notNull(expiration, "Expiration must not be null!");
263+
this.expiration = expiration;
264+
}
265+
266+
/**
267+
* Creates a new {@link GetExCommand} given a {@code key}.
268+
*
269+
* @param key must not be {@literal null}.
270+
* @return a new {@link GetExCommand} for {@code key}.
271+
*/
272+
public static GetExCommand key(ByteBuffer key) {
273+
return new GetExCommand(key, Expiration.persistent());
274+
}
275+
276+
/**
277+
* Applies {@link Expiration}. Constructs a new command instance with all previously configured properties.
278+
*
279+
* @param options must not be {@literal null}.
280+
* @return a new {@link GetExCommand} with {@link Expiration} applied.
281+
*/
282+
public GetExCommand withExpiration(Expiration expiration) {
283+
return new GetExCommand(getKey(), expiration);
284+
}
285+
286+
/**
287+
* Get the {@link Expiration} to apply.
288+
*
289+
* @return never {@literal null}.
290+
*/
291+
public Expiration getExpiration() {
292+
return expiration;
293+
}
294+
}
295+
296+
/**
297+
* Return the value at {@code key} and expire the key by applying {@link Expiration}.
298+
*
299+
* @param key must not be {@literal null}.
300+
* @param expiration must not be {@literal null}.
301+
* @return {@link Mono#empty()} in case {@literal key} does not exist.
302+
* @see <a href="https://redis.io/commands/getex">Redis Documentation: GETEX</a>
303+
* @since 2.6
304+
*/
305+
default Mono<ByteBuffer> getEx(ByteBuffer key, Expiration expiration) {
306+
307+
Assert.notNull(key, "Key must not be null!");
308+
309+
return getEx(Mono.just(GetExCommand.key(key).withExpiration(expiration))).next().filter(CommandResponse::isPresent)
310+
.map(CommandResponse::getOutput);
311+
}
312+
313+
/**
314+
* Return the value at {@code key} and expire the key by applying {@link Expiration}.
315+
*
316+
* @param commands must not be {@literal null}.
317+
* @return {@link Flux} of {@link ByteBufferResponse} holding the {@literal key} to get along with the value
318+
* retrieved.
319+
* @see <a href="https://redis.io/commands/getex">Redis Documentation: GETEX</a>
320+
* @since 2.6
321+
*/
322+
Flux<ByteBufferResponse<GetExCommand>> getEx(Publisher<GetExCommand> commands);
323+
221324
/**
222325
* Set {@literal value} for {@literal key} and return the existing value.
223326
*

src/main/java/org/springframework/data/redis/connection/RedisStringCommands.java

+25
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,30 @@ enum BitOperation {
4545
@Nullable
4646
byte[] get(byte[] key);
4747

48+
/**
49+
* Return the value at {@code key} and delete the key.
50+
*
51+
* @param key must not be {@literal null}.
52+
* @return {@literal null} when key does not exist or used in pipeline / transaction.
53+
* @see <a href="https://redis.io/commands/getdel">Redis Documentation: GETDEL</a>
54+
* @since 2.6
55+
*/
56+
@Nullable
57+
byte[] getDel(byte[] key);
58+
59+
/**
60+
* Return the value at {@code key} and expire the key by applying {@link Expiration}.
61+
*
62+
* @param key must not be {@literal null}.
63+
* @param expiration must not be {@literal null}.
64+
* @param unit must not be {@literal null}.
65+
* @return {@literal null} when key does not exist or used in pipeline / transaction.
66+
* @see <a href="https://redis.io/commands/getex">Redis Documentation: GETEX</a>
67+
* @since 2.6
68+
*/
69+
@Nullable
70+
byte[] getEx(byte[] key, Expiration expiration);
71+
4872
/**
4973
* Set {@code value} of {@code key} and return its old value.
5074
*
@@ -403,4 +427,5 @@ public static SetOption ifAbsent() {
403427
return SET_IF_ABSENT;
404428
}
405429
}
430+
406431
}

src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java

+23
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,29 @@ interface StringTuple extends Tuple {
383383
*/
384384
String get(String key);
385385

386+
/**
387+
* Return the value at {@code key} and delete the key.
388+
*
389+
* @param key must not be {@literal null}.
390+
* @return {@literal null} when key does not exist or used in pipeline / transaction.
391+
* @see <a href="https://redis.io/commands/getdel">Redis Documentation: GETDEL</a>
392+
* @since 2.6
393+
*/
394+
@Nullable
395+
String getDel(String key);
396+
397+
/**
398+
* Return the value at {@code key} and expire the key by applying {@link Expiration}.
399+
*
400+
* @param key must not be {@literal null}.
401+
* @param expiration must not be {@literal null}.
402+
* @return {@literal null} when key does not exist or used in pipeline / transaction.
403+
* @see <a href="https://redis.io/commands/getex">Redis Documentation: GETEX</a>
404+
* @since 2.6
405+
*/
406+
@Nullable
407+
String getEx(String key, Expiration expiration);
408+
386409
/**
387410
* Set {@code value} of {@code key} and return its old value.
388411
*

src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterStringCommands.java

+36
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import org.springframework.data.redis.connection.lettuce.LettuceConverters;
3636
import org.springframework.data.redis.core.types.Expiration;
3737
import org.springframework.data.redis.util.ByteUtils;
38+
import org.springframework.lang.Nullable;
3839
import org.springframework.util.Assert;
3940

4041
/**
@@ -68,6 +69,41 @@ public byte[] get(byte[] key) {
6869
}
6970
}
7071

72+
/*
73+
* (non-Javadoc)
74+
* @see org.springframework.data.redis.connection.RedisStringCommands#getDel(byte[])
75+
*/
76+
@Nullable
77+
@Override
78+
public byte[] getDel(byte[] key) {
79+
80+
Assert.notNull(key, "Key must not be null!");
81+
82+
try {
83+
return connection.getCluster().getDel(key);
84+
} catch (Exception ex) {
85+
throw convertJedisAccessException(ex);
86+
}
87+
}
88+
89+
/*
90+
* (non-Javadoc)
91+
* @see org.springframework.data.redis.connection.RedisStringCommands#getEx(byte[], org.springframework.data.redis.core.types.Expiration)
92+
*/
93+
@Nullable
94+
@Override
95+
public byte[] getEx(byte[] key, Expiration expiration) {
96+
97+
Assert.notNull(key, "Key must not be null!");
98+
Assert.notNull(expiration, "Expiration must not be null!");
99+
100+
try {
101+
return connection.getCluster().getEx(key, JedisConverters.toGetExParams(expiration));
102+
} catch (Exception ex) {
103+
throw convertJedisAccessException(ex);
104+
}
105+
}
106+
71107
/*
72108
* (non-Javadoc)
73109
* @see org.springframework.data.redis.connection.RedisStringCommands#getSet(byte[], byte[])

src/main/java/org/springframework/data/redis/connection/jedis/JedisConverters.java

+29
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import redis.clients.jedis.ScanParams;
2424
import redis.clients.jedis.SortingParams;
2525
import redis.clients.jedis.params.GeoRadiusParam;
26+
import redis.clients.jedis.params.GetExParams;
2627
import redis.clients.jedis.params.SetParams;
2728
import redis.clients.jedis.params.ZAddParams;
2829
import redis.clients.jedis.util.SafeEncoder;
@@ -441,6 +442,34 @@ public static SetParams toSetCommandExPxArgument(Expiration expiration, SetParam
441442
return params;
442443
}
443444

445+
/**
446+
* Converts a given {@link Expiration} to the according {@code GETEX} command argument.
447+
* <dl>
448+
* <dt>{@link TimeUnit#MILLISECONDS}</dt>
449+
* <dd>{@code PX}</dd>
450+
* <dt>{@link TimeUnit#SECONDS}</dt>
451+
* <dd>{@code EX}</dd>
452+
* </dl>
453+
*
454+
* @param expiration must not be {@literal null}.
455+
* @return
456+
* @since 2.6
457+
*/
458+
static GetExParams toGetExParams(Expiration expiration) {
459+
460+
GetExParams params = new GetExParams();
461+
462+
if (expiration.isPersistent()) {
463+
return params.persist();
464+
}
465+
466+
if (expiration.getTimeUnit() == TimeUnit.MILLISECONDS) {
467+
return params.px(expiration.getExpirationTime());
468+
}
469+
470+
return params.ex((int) expiration.getExpirationTime());
471+
}
472+
444473
/**
445474
* Converts a given {@link SetOption} to the according {@code SET} command argument.<br />
446475
* <dl>

src/main/java/org/springframework/data/redis/connection/jedis/JedisStringCommands.java

+28
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,34 @@ public byte[] get(byte[] key) {
5757
return connection.invoke().just(BinaryJedis::get, MultiKeyPipelineBase::get, key);
5858
}
5959

60+
/*
61+
* (non-Javadoc)
62+
* @see org.springframework.data.redis.connection.RedisStringCommands#getDel(byte[])
63+
*/
64+
@Nullable
65+
@Override
66+
public byte[] getDel(byte[] key) {
67+
68+
Assert.notNull(key, "Key must not be null!");
69+
70+
return connection.invoke().just(BinaryJedis::getDel, MultiKeyPipelineBase::getDel, key);
71+
}
72+
73+
/*
74+
* (non-Javadoc)
75+
* @see org.springframework.data.redis.connection.RedisStringCommands#getEx(byte[], org.springframework.data.redis.core.types.Expiration)
76+
*/
77+
@Nullable
78+
@Override
79+
public byte[] getEx(byte[] key, Expiration expiration) {
80+
81+
Assert.notNull(key, "Key must not be null!");
82+
Assert.notNull(expiration, "Expiration must not be null!");
83+
84+
return connection.invoke().just(BinaryJedis::getEx, MultiKeyPipelineBase::getEx, key,
85+
JedisConverters.toGetExParams(expiration));
86+
}
87+
6088
/*
6189
* (non-Javadoc)
6290
* @see org.springframework.data.redis.connection.RedisStringCommands#getSet(byte[], byte[])

0 commit comments

Comments
 (0)