Skip to content

Commit 1b6737e

Browse files
Switch from plain String to DataType for ScanOptions.
Move the type method from KeyScanOptionsBuilder to the ScanOptionsBuilder to allow removal of the former. Add a test for the reactive variant and allow SCAN tests with TYPE option to be executed starting with Redis 6.0. Original Pull Request: spring-projects#2109
1 parent 674401c commit 1b6737e

File tree

4 files changed

+75
-72
lines changed

4 files changed

+75
-72
lines changed

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

+7-68
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@
1717

1818
import java.util.StringJoiner;
1919

20+
import org.springframework.data.redis.connection.DataType;
2021
import org.springframework.lang.Nullable;
2122
import org.springframework.util.StringUtils;
2223

2324
/**
2425
* Options to be used for with {@literal SCAN} commands.
2526
*
2627
* @author Mark Paluch
28+
* @author Christoph Strobl
2729
* @since 2.6
2830
*/
2931
public class KeyScanOptions extends ScanOptions {
@@ -35,20 +37,21 @@ public class KeyScanOptions extends ScanOptions {
3537

3638
private final @Nullable String type;
3739

38-
private KeyScanOptions(@Nullable Long count, @Nullable String pattern, @Nullable byte[] bytePattern,
40+
KeyScanOptions(@Nullable Long count, @Nullable String pattern, @Nullable byte[] bytePattern,
3941
@Nullable String type) {
4042

4143
super(count, pattern, bytePattern);
4244
this.type = type;
4345
}
4446

4547
/**
46-
* Static factory method that returns a new {@link KeyScanOptionsBuilder}.
48+
* Static factory method that returns a new {@link ScanOptionsBuilder}.
4749
*
50+
* @param type
4851
* @return
4952
*/
50-
public static KeyScanOptionsBuilder scanOptions() {
51-
return new KeyScanOptionsBuilder();
53+
public static ScanOptionsBuilder scanOptions(DataType type) {
54+
return new ScanOptionsBuilder().type(type);
5255
}
5356

5457
@Nullable
@@ -71,68 +74,4 @@ public String toOptionString() {
7174

7275
return joiner.toString();
7376
}
74-
75-
public static class KeyScanOptionsBuilder extends ScanOptionsBuilder {
76-
77-
private @Nullable String type;
78-
79-
private KeyScanOptionsBuilder() {}
80-
81-
/**
82-
* Returns the current {@link KeyScanOptionsBuilder} configured with the given {@code count}.
83-
*
84-
* @param count
85-
* @return
86-
*/
87-
@Override
88-
public KeyScanOptionsBuilder count(long count) {
89-
super.count(count);
90-
return this;
91-
}
92-
93-
/**
94-
* Returns the current {@link KeyScanOptionsBuilder} configured with the given {@code pattern}.
95-
*
96-
* @param pattern
97-
* @return
98-
*/
99-
@Override
100-
public KeyScanOptionsBuilder match(String pattern) {
101-
super.match(pattern);
102-
return this;
103-
}
104-
105-
/**
106-
* Returns the current {@link KeyScanOptionsBuilder} configured with the given {@code pattern}.
107-
*
108-
* @param pattern
109-
* @return
110-
*/
111-
@Override
112-
public KeyScanOptionsBuilder match(byte[] pattern) {
113-
super.match(pattern);
114-
return this;
115-
}
116-
117-
/**
118-
* Returns the current {@link KeyScanOptionsBuilder} configured with the given {@code type}.
119-
*
120-
* @param type
121-
* @return
122-
*/
123-
public KeyScanOptionsBuilder type(String type) {
124-
this.type = type;
125-
return this;
126-
}
127-
128-
/**
129-
* Builds a new {@link KeyScanOptions} objects.
130-
*
131-
* @return a new {@link KeyScanOptions} objects.
132-
*/
133-
@Override
134-
public KeyScanOptions build() {
135-
return new KeyScanOptions(count, pattern, bytePattern, type);
136-
}
137-
}
13877
}

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

+41-3
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717

1818
import java.util.StringJoiner;
1919

20+
import org.springframework.data.redis.connection.DataType;
2021
import org.springframework.lang.Nullable;
22+
import org.springframework.util.Assert;
2123
import org.springframework.util.StringUtils;
2224

2325
/**
@@ -41,6 +43,7 @@ public class ScanOptions {
4143
private final @Nullable byte[] bytePattern;
4244

4345
ScanOptions(@Nullable Long count, @Nullable String pattern, @Nullable byte[] bytePattern) {
46+
4447
this.count = count;
4548
this.pattern = pattern;
4649
this.bytePattern = bytePattern;
@@ -110,14 +113,15 @@ public static class ScanOptionsBuilder {
110113
@Nullable Long count;
111114
@Nullable String pattern;
112115
@Nullable byte[] bytePattern;
116+
@Nullable DataType type;
113117

114118
ScanOptionsBuilder() {}
115119

116120
/**
117121
* Returns the current {@link ScanOptionsBuilder} configured with the given {@code count}.
118122
*
119123
* @param count
120-
* @return
124+
* @return this.
121125
*/
122126
public ScanOptionsBuilder count(long count) {
123127
this.count = count;
@@ -128,7 +132,7 @@ public ScanOptionsBuilder count(long count) {
128132
* Returns the current {@link ScanOptionsBuilder} configured with the given {@code pattern}.
129133
*
130134
* @param pattern
131-
* @return
135+
* @return this.
132136
*/
133137
public ScanOptionsBuilder match(String pattern) {
134138
this.pattern = pattern;
@@ -139,20 +143,54 @@ public ScanOptionsBuilder match(String pattern) {
139143
* Returns the current {@link ScanOptionsBuilder} configured with the given {@code pattern}.
140144
*
141145
* @param pattern
142-
* @return
146+
* @return this.
143147
* @since 2.6
144148
*/
145149
public ScanOptionsBuilder match(byte[] pattern) {
146150
this.bytePattern = pattern;
147151
return this;
148152
}
149153

154+
/**
155+
* Returns the current {@link ScanOptionsBuilder} configured with the given {@code type}. <br />
156+
* Please verify the the targeted command supports the
157+
* <a href="https://redis.io/commands/SCAN#the-type-option">TYPE</a> option before use.
158+
*
159+
* @param type must not be {@literal null}. Either do not set or use {@link DataType#NONE}.
160+
* @return this.
161+
* @since 2.6
162+
*/
163+
public ScanOptionsBuilder type(DataType type) {
164+
165+
Assert.notNull(type, "Type must not be null! Use NONE instead.");
166+
167+
this.type = type;
168+
return this;
169+
}
170+
171+
/**
172+
* Returns the current {@link ScanOptionsBuilder} configured with the given {@code type}.
173+
*
174+
* @param type the textual representation of {@link DataType#fromCode(String)}. Must not be {@literal null}.
175+
* @return this.
176+
* @throws IllegalArgumentException if given type is {@literal null} or unknown.
177+
*/
178+
public ScanOptionsBuilder type(String type) {
179+
180+
Assert.notNull(type, "Type must not be null!");
181+
return type(DataType.fromCode(type));
182+
}
183+
150184
/**
151185
* Builds a new {@link ScanOptions} objects.
152186
*
153187
* @return a new {@link ScanOptions} objects.
154188
*/
155189
public ScanOptions build() {
190+
191+
if (type != null && !DataType.NONE.equals(type)) {
192+
return new KeyScanOptions(count, pattern, bytePattern, type.code());
193+
}
156194
return new ScanOptions(count, pattern, bytePattern);
157195
}
158196
}

src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -2598,7 +2598,7 @@ void scanShouldReadEntireValueRange() {
25982598

25992599
@Test // GH-2089
26002600
@EnabledOnRedisDriver(RedisDriver.LETTUCE)
2601-
@EnabledOnRedisVersion("6.2")
2601+
@EnabledOnRedisVersion("6.0")
26022602
void scanWithType() {
26032603

26042604
assumeThat(connection.isPipelined() || connection.isQueueing())

src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveKeyCommandsIntegrationTests.java

+26
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,10 @@
3535
import org.springframework.data.redis.connection.ReactiveRedisConnection.KeyCommand;
3636
import org.springframework.data.redis.connection.ReactiveRedisConnection.NumericResponse;
3737
import org.springframework.data.redis.connection.ValueEncoding.RedisValueEncoding;
38+
import org.springframework.data.redis.core.KeyScanOptions;
3839
import org.springframework.data.redis.core.ScanOptions;
3940
import org.springframework.data.redis.test.condition.EnabledOnCommand;
41+
import org.springframework.data.redis.test.condition.EnabledOnRedisVersion;
4042
import org.springframework.data.redis.test.extension.parametrized.ParameterizedRedisTest;
4143

4244
/**
@@ -115,6 +117,30 @@ void scanShouldShouldIterateOverKeyspace() {
115117
.verifyComplete();
116118
}
117119

120+
@ParameterizedRedisTest // GH-2089
121+
@EnabledOnRedisVersion("6.0")
122+
void scanWithType() {
123+
124+
nativeCommands.set(KEY_1, VALUE_1);
125+
nativeCommands.lpush(KEY_2, VALUE_2);
126+
nativeCommands.sadd(KEY_3, VALUE_3);
127+
128+
connection.keyCommands().scan(KeyScanOptions.scanOptions(DataType.STRING).build()) //
129+
.as(StepVerifier::create) //
130+
.expectNext(KEY_1_BBUFFER) //
131+
.verifyComplete();
132+
133+
connection.keyCommands().scan(KeyScanOptions.scanOptions(DataType.SET).build()) //
134+
.as(StepVerifier::create) //
135+
.expectNext(KEY_3_BBUFFER) //
136+
.verifyComplete();
137+
138+
connection.keyCommands().scan(KeyScanOptions.scanOptions(DataType.NONE).build()) //
139+
.as(StepVerifier::create) //
140+
.expectNextCount(3) //
141+
.verifyComplete();
142+
}
143+
118144
@ParameterizedRedisTest // DATAREDIS-525
119145
void randomKeyShouldReturnAnyKey() {
120146

0 commit comments

Comments
 (0)