Skip to content

Commit ceba810

Browse files
Introduce ScanCursor limitation check method to.
This commit moves the limit field to the delegating sub class. This way it is possible to override the newly introduced limitReached(long) method without polluting the ScanCursor implementation with the limit check itself.
1 parent 315fbd7 commit ceba810

File tree

2 files changed

+84
-11
lines changed

2 files changed

+84
-11
lines changed

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

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ public abstract class ScanCursor<T> implements Cursor<T> {
4343
private Iterator<T> delegate;
4444
private final ScanOptions scanOptions;
4545
private long position;
46-
private final long limit;
4746

4847
/**
4948
* Crates new {@link ScanCursor} with {@code id=0} and {@link ScanOptions#NONE}
@@ -82,23 +81,20 @@ public ScanCursor(long cursorId, @Nullable ScanOptions options) {
8281
this.cursorId = cursorId;
8382
this.state = CursorState.READY;
8483
this.delegate = Collections.emptyIterator();
85-
this.limit = -1;
8684
}
8785

8886
/**
8987
* Crates a new {@link ScanCursor}.
9088
*
9189
* @param source source cursor.
92-
* @param limit
9390
* @since 2.5
9491
*/
95-
private ScanCursor(ScanCursor<T> source, long limit) {
92+
private ScanCursor(ScanCursor<T> source) {
9693

9794
this.scanOptions = source.scanOptions;
9895
this.cursorId = source.cursorId;
9996
this.state = source.state;
10097
this.delegate = source.delegate;
101-
this.limit = limit;
10298
}
10399

104100
private void scan(long cursorId) {
@@ -189,7 +185,7 @@ public boolean hasNext() {
189185

190186
assertCursorIsOpen();
191187

192-
if (limit != -1 && getPosition() > limit - 1) {
188+
if (limitReached(getPosition())) {
193189
return false;
194190
}
195191

@@ -204,6 +200,17 @@ public boolean hasNext() {
204200
return cursorId > 0;
205201
}
206202

203+
/**
204+
* Evaluate if the current cursor position has reached a point where it should stop.
205+
*
206+
* @param currentPosition the current position.
207+
* @return {@literal false} by default.
208+
* @since 2.5
209+
*/
210+
protected boolean limitReached(long currentPosition) {
211+
return false;
212+
}
213+
207214
private void assertCursorIsOpen() {
208215

209216
if (isReady() || isClosed()) {
@@ -303,7 +310,7 @@ public ScanCursor<T> limit(long count) {
303310

304311
Assert.isTrue(count >= 0, "Count must be greater or equal to zero");
305312

306-
return new ScanCursorWrapper<>(this, count);
313+
return new LimitingCursor<>(this, count);
307314
}
308315

309316
/**
@@ -318,30 +325,57 @@ enum CursorState {
318325
* {@link #isClosed()}.
319326
*
320327
* @param <T>
328+
* @author Mark Paluch
329+
* @author Christoph Strobl
321330
* @since 2.5
322331
*/
323-
private static class ScanCursorWrapper<T> extends ScanCursor<T> {
332+
private static class LimitingCursor<T> extends ScanCursor<T> {
324333

325334
private final ScanCursor<T> delegate;
335+
private final long limit;
336+
337+
LimitingCursor(ScanCursor<T> delegate, long limit) {
338+
339+
super(delegate);
326340

327-
public ScanCursorWrapper(ScanCursor<T> delegate, long limit) {
328-
super(delegate, limit);
329341
this.delegate = delegate;
342+
this.limit = limit;
330343
}
331344

345+
/*
346+
* (non-Javadoc)
347+
* @see org.springframework.data.redis.core.ScanCursor#doScan(long, ScanOptions)
348+
*/
332349
@Override
333350
protected ScanIteration<T> doScan(long cursorId, ScanOptions options) {
334351
return delegate.doScan(cursorId, options);
335352
}
336353

354+
/*
355+
* (non-Javadoc)
356+
* @see org.springframework.data.redis.core.ScanCursor#doClose()
357+
*/
337358
@Override
338359
protected void doClose() {
339360
delegate.close();
340361
}
341362

363+
/*
364+
* (non-Javadoc)
365+
* @see org.springframework.data.redis.core.Cursor#isClosed()
366+
*/
342367
@Override
343368
public boolean isClosed() {
344369
return delegate.isClosed();
345370
}
371+
372+
/*
373+
* (non-Javadoc)
374+
* @see org.springframework.data.redis.core.ScanCursor#limitReached(long)
375+
*/
376+
@Override
377+
protected boolean limitReached(long currentPosition) {
378+
return delegate.limitReached(currentPosition) || (limit != -1 && currentPosition > limit - 1);
379+
}
346380
}
347381
}

src/test/java/org/springframework/data/redis/core/ScanCursorUnitTests.java

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import java.util.Queue;
2727

2828
import org.junit.jupiter.api.Test;
29-
3029
import org.springframework.dao.InvalidDataAccessApiUsageException;
3130

3231
/**
@@ -236,6 +235,46 @@ void limitShouldNotLimitOriginalCursor() {
236235
assertThat(result).hasSize(3);
237236
}
238237

238+
@Test // GH-1575
239+
void limitAlreadyLimitedCursorToLess() {
240+
241+
LinkedList<ScanIteration<String>> values = new LinkedList<>();
242+
values.add(createIteration(1, "spring"));
243+
values.add(createIteration(2, "data"));
244+
values.add(createIteration(3, "redis"));
245+
values.add(createIteration(0));
246+
Cursor<String> cursor = initCursor(values);
247+
Cursor<String> limitedTo3 = cursor.limit(3);
248+
Cursor<String> limitedTo2 = limitedTo3.limit(2);
249+
250+
List<String> result = new ArrayList<>();
251+
while (limitedTo2.hasNext()) {
252+
result.add(limitedTo2.next());
253+
}
254+
255+
assertThat(result).hasSize(2);
256+
}
257+
258+
@Test // GH-1575
259+
void limitAlreadyLimitedCursorToMore/*should not work obviously*/() {
260+
261+
LinkedList<ScanIteration<String>> values = new LinkedList<>();
262+
values.add(createIteration(1, "spring"));
263+
values.add(createIteration(2, "data"));
264+
values.add(createIteration(3, "redis"));
265+
values.add(createIteration(0));
266+
Cursor<String> cursor = initCursor(values);
267+
Cursor<String> limitedTo2 = cursor.limit(2);
268+
Cursor<String> limitedTo3 = limitedTo2.limit(3);
269+
270+
List<String> result = new ArrayList<>();
271+
while (limitedTo3.hasNext()) {
272+
result.add(limitedTo3.next());
273+
}
274+
275+
assertThat(result).hasSize(2);
276+
}
277+
239278
@Test // GH-1575
240279
void decoratedCursorShouldForwardClose() {
241280

0 commit comments

Comments
 (0)