Skip to content

Commit cdf9dc3

Browse files
marcingrzejszczakmp911de
authored andcommitted
Adds support for Redis SET … GET command.
Closes #2853 Original pull request: #3017
1 parent ea4d728 commit cdf9dc3

17 files changed

+280
-0
lines changed

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,11 @@ public Boolean set(byte[] key, byte[] value, Expiration expiration, SetOption op
770770
return convertAndReturn(delegate.set(key, value, expiration, option), Converters.identityConverter());
771771
}
772772

773+
@Override
774+
public byte[] setGet(byte[] key, byte[] value, Expiration expiration, SetOption option) {
775+
return convertAndReturn(delegate.setGet(key, value, expiration, option), Converters.identityConverter());
776+
}
777+
773778
@Override
774779
public Boolean setBit(byte[] key, long offset, boolean value) {
775780
return convertAndReturn(delegate.setBit(key, offset, value), Converters.identityConverter());

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,13 @@ default Boolean set(byte[] key, byte[] value, Expiration expiration, SetOption o
326326
return stringCommands().set(key, value, expiration, option);
327327
}
328328

329+
/** @deprecated in favor of {@link RedisConnection#stringCommands()}}. */
330+
@Override
331+
@Deprecated
332+
default byte[] setGet(byte[] key, byte[] value, Expiration expiration, SetOption option) {
333+
return stringCommands().setGet(key, value, expiration, option);
334+
}
335+
329336
/** @deprecated in favor of {@link RedisConnection#stringCommands()}}. */
330337
@Override
331338
@Deprecated

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

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
*
4848
* @author Christoph Strobl
4949
* @author Mark Paluch
50+
* @author Marcin Grzejszczak
5051
* @since 2.0
5152
*/
5253
public interface ReactiveStringCommands {
@@ -193,6 +194,41 @@ default Mono<Boolean> set(ByteBuffer key, ByteBuffer value, Expiration expiratio
193194
*/
194195
Flux<BooleanResponse<SetCommand>> set(Publisher<SetCommand> commands);
195196

197+
/**
198+
* Set {@literal value} for {@literal key} with {@literal expiration} and {@literal options}. Return the old
199+
* string stored at key, or nil if key did not exist. An error is returned and SET aborted if the value
200+
* stored at key is not a string.
201+
*
202+
* @param key must not be {@literal null}.
203+
* @param value must not be {@literal null}.
204+
* @param expiration must not be {@literal null}. Use {@link Expiration#persistent()} for no expiration time or
205+
* {@link Expiration#keepTtl()} to keep the existing.
206+
* @param option must not be {@literal null}.
207+
* @return
208+
* @see <a href="https://redis.io/commands/set">Redis Documentation: SET</a>
209+
* @since 3.4
210+
*/
211+
@Nullable
212+
default Mono<ByteBuffer> setGet(ByteBuffer key, ByteBuffer value, Expiration expiration, SetOption option) {
213+
214+
Assert.notNull(key, "Key must not be null");
215+
Assert.notNull(value, "Value must not be null");
216+
217+
return setGet(Mono.just(SetCommand.set(key).value(value).withSetOption(option).expiring(expiration))).next()
218+
.map(CommandResponse::getOutput);
219+
}
220+
221+
/**
222+
* Set each and every item separately by invoking {@link SetCommand}. Return the old
223+
* string stored at key, or nil if key did not exist. An error is returned and SET aborted if the value
224+
* stored at key is not a string.
225+
*
226+
* @param commands must not be {@literal null}.
227+
* @return {@link Flux} of {@link ByteBufferResponse} holding the {@link SetCommand} along with the command result.
228+
* @see <a href="https://redis.io/commands/set">Redis Documentation: SET</a>
229+
*/
230+
Flux<ByteBufferResponse<SetCommand>> setGet(Publisher<SetCommand> commands);
231+
196232
/**
197233
* Get single element stored at {@literal key}.
198234
*

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,22 @@ enum BitOperation {
122122
@Nullable
123123
Boolean set(byte[] key, byte[] value, Expiration expiration, SetOption option);
124124

125+
/**
126+
* Set {@code value} for {@code key}. Return the old string stored at key, or nil if key did not exist.
127+
* An error is returned and SET aborted if the value stored at key is not a string.
128+
*
129+
* @param key must not be {@literal null}.
130+
* @param value must not be {@literal null}.
131+
* @param expiration must not be {@literal null}. Use {@link Expiration#persistent()} to not set any ttl or
132+
* {@link Expiration#keepTtl()} to keep the existing expiration.
133+
* @param option must not be {@literal null}. Use {@link SetOption#upsert()} to add non existing.
134+
* @return {@literal null} when used in pipeline / transaction.
135+
* @since 3.4
136+
* @see <a href="https://redis.io/commands/set">Redis Documentation: SET</a>
137+
*/
138+
@Nullable
139+
byte[] setGet(byte[] key, byte[] value, Expiration expiration, SetOption option);
140+
125141
/**
126142
* Set {@code value} for {@code key}, only if {@code key} does not exist.
127143
*

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,24 @@ public Boolean set(byte[] key, byte[] value, Expiration expiration, SetOption op
150150
}
151151
}
152152

153+
@Override
154+
public byte[] setGet(byte[] key, byte[] value, Expiration expiration, SetOption option) {
155+
156+
Assert.notNull(key, "Key must not be null");
157+
Assert.notNull(value, "Value must not be null");
158+
Assert.notNull(expiration, "Expiration must not be null");
159+
Assert.notNull(option, "Option must not be null");
160+
161+
SetParams setParams = JedisConverters.toSetCommandExPxArgument(expiration,
162+
JedisConverters.toSetCommandNxXxArgument(option));
163+
164+
try {
165+
return connection.getCluster().setGet(key, value, setParams);
166+
} catch (Exception ex) {
167+
throw convertJedisAccessException(ex);
168+
}
169+
}
170+
153171
@Override
154172
public Boolean setNX(byte[] key, byte[] value) {
155173

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,20 @@ public Boolean set(byte[] key, byte[] value, Expiration expiration, SetOption op
116116
.getOrElse(Converters.stringToBooleanConverter(), () -> false);
117117
}
118118

119+
@Override
120+
@Nullable
121+
public byte[] setGet(byte[] key, byte[] value, Expiration expiration, SetOption option) {
122+
Assert.notNull(key, "Key must not be null");
123+
Assert.notNull(value, "Value must not be null");
124+
Assert.notNull(expiration, "Expiration must not be null");
125+
Assert.notNull(option, "Option must not be null");
126+
127+
SetParams params = JedisConverters.toSetCommandExPxArgument(expiration,
128+
JedisConverters.toSetCommandNxXxArgument(option));
129+
130+
return connection.invoke().just(Jedis::setGet, PipelineBinaryCommands::setGet, key, value, params);
131+
}
132+
119133
@Override
120134
public Boolean setNX(byte[] key, byte[] value) {
121135

src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveStringCommands.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,19 @@ public Flux<BooleanResponse<SetCommand>> set(Publisher<SetCommand> commands) {
105105
}));
106106
}
107107

108+
@Override
109+
public Flux<ByteBufferResponse<SetCommand>> setGet(Publisher<SetCommand> commands) {
110+
return this.connection.execute(reactiveCommands -> Flux.from(commands).concatMap((command) -> {
111+
112+
Assert.notNull(command.getKey(), "Key must not be null");
113+
Assert.notNull(command.getValue(), "Value must not be null");
114+
115+
return reactiveCommands.setGet(command.getKey(), command.getValue())
116+
.map(v -> new ByteBufferResponse<>(command, v))
117+
.defaultIfEmpty(new AbsentByteBufferResponse<>(command));
118+
}));
119+
}
120+
108121
@Override
109122
public Flux<ByteBufferResponse<SetCommand>> getSet(Publisher<SetCommand> commands) {
110123

src/main/java/org/springframework/data/redis/connection/lettuce/LettuceStringCommands.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,18 @@ public Boolean set(byte[] key, byte[] value, Expiration expiration, SetOption op
115115
.orElse(LettuceConverters.stringToBooleanConverter(), false);
116116
}
117117

118+
@Override
119+
@Nullable
120+
public byte[] setGet(byte[] key, byte[] value, Expiration expiration, SetOption option) {
121+
Assert.notNull(key, "Key must not be null");
122+
Assert.notNull(value, "Value must not be null");
123+
Assert.notNull(expiration, "Expiration must not be null");
124+
Assert.notNull(option, "Option must not be null");
125+
126+
return connection.invoke()
127+
.just(RedisStringAsyncCommands::setGet, key, value, LettuceConverters.toSetArgs(expiration, option));
128+
}
129+
118130
@Override
119131
public Boolean setNX(byte[] key, byte[] value) {
120132

src/main/java/org/springframework/data/redis/core/BoundValueOperations.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,19 @@ public interface BoundValueOperations<K, V> extends BoundKeyOperations<K> {
4949
*/
5050
void set(V value, long timeout, TimeUnit unit);
5151

52+
/**
53+
* Set the {@code value} and expiration {@code timeout} for the bound key. Return the old
54+
* string stored at key, or nil if key did not exist. An error is returned and SET aborted if the value
55+
* stored at key is not a string.
56+
*
57+
* @param value must not be {@literal null}.
58+
* @param timeout
59+
* @param unit must not be {@literal null}.
60+
* @see <a href="https://redis.io/commands/set">Redis Documentation: SET</a>
61+
* @since 3.4
62+
*/
63+
V setGet(V value, long timeout, TimeUnit unit);
64+
5265
/**
5366
* Set the {@code value} and expiration {@code timeout} for the bound key.
5467
*

src/main/java/org/springframework/data/redis/core/DefaultReactiveValueOperations.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,18 @@ public Mono<Boolean> set(K key, V value, Duration timeout) {
7777
stringCommands.set(rawKey(key), rawValue(value), Expiration.from(timeout), SetOption.UPSERT));
7878
}
7979

80+
@Override
81+
public Mono<V> setGet(K key, V value, Duration timeout) {
82+
83+
Assert.notNull(key, "Key must not be null");
84+
Assert.notNull(value, "Value must not be null");
85+
Assert.notNull(timeout, "Duration must not be null");
86+
87+
return createMono(stringCommands ->
88+
stringCommands.setGet(rawKey(key), rawValue(value), Expiration.from(timeout), SetOption.UPSERT))
89+
.map(this::readRequiredValue);
90+
}
91+
8092
@Override
8193
public Mono<Boolean> setIfAbsent(K key, V value) {
8294

0 commit comments

Comments
 (0)