Skip to content

Commit bd20c6d

Browse files
committed
Polishing.
Add getFirst/getLast to Reactive and Bound Operations. Simplify getLast implementation. Reorder methods, tweak Javadoc, add since tags. Original pull request: #2966 See #2937
1 parent a58bfd8 commit bd20c6d

File tree

6 files changed

+136
-85
lines changed

6 files changed

+136
-85
lines changed

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

+18
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,24 @@ public interface BoundListOperations<K, V> extends BoundKeyOperations<K> {
212212
@Nullable
213213
Long remove(long count, Object value);
214214

215+
/**
216+
* Returns the first element from the list at the bound {@code key}.
217+
*
218+
* @return {@literal null} when used in pipeline / transaction.
219+
* @since 3.4
220+
*/
221+
@Nullable
222+
V getFirst();
223+
224+
/**
225+
* Returns the last element from the list at the bound {@code key}.
226+
*
227+
* @return {@literal null} when used in pipeline / transaction.
228+
* @since 3.4
229+
*/
230+
@Nullable
231+
V getLast();
232+
215233
/**
216234
* Get element at {@code index} form list at the bound key.
217235
*

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

+28-32
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,30 @@ default V move(K sourceKey, Direction from, K destinationKey, Direction to, Dura
368368
@Nullable
369369
Long remove(K key, long count, Object value);
370370

371+
/**
372+
* Returns the first element from the list at {@code key}.
373+
*
374+
* @param key must not be {@literal null}.
375+
* @return {@literal null} when used in pipeline / transaction.
376+
* @since 3.4
377+
*/
378+
@Nullable
379+
default V getFirst(K key) {
380+
return index(key, 0);
381+
}
382+
383+
/**
384+
* Returns the last element from the list at {@code key}.
385+
*
386+
* @param key must not be {@literal null}.
387+
* @return {@literal null} when used in pipeline / transaction.
388+
* @since 3.4
389+
*/
390+
@Nullable
391+
default V getLast(K key) {
392+
return index(key, -1);
393+
}
394+
371395
/**
372396
* Get element at {@code index} form list at {@code key}.
373397
*
@@ -526,7 +550,8 @@ default V rightPop(K key, Duration timeout) {
526550
V rightPopAndLeftPush(K sourceKey, K destinationKey);
527551

528552
/**
529-
* Remove the last element from list at {@code sourceKey}, append it to {@code destinationKey} and return its value.<br>
553+
* Remove the last element from list at {@code sourceKey}, append it to {@code destinationKey} and return its
554+
* value.<br>
530555
* <b>Blocks connection</b> until element available or {@code timeout} reached.
531556
*
532557
* @param sourceKey must not be {@literal null}.
@@ -540,7 +565,8 @@ default V rightPop(K key, Duration timeout) {
540565
V rightPopAndLeftPush(K sourceKey, K destinationKey, long timeout, TimeUnit unit);
541566

542567
/**
543-
* Remove the last element from list at {@code sourceKey}, append it to {@code destinationKey} and return its value.<br>
568+
* Remove the last element from list at {@code sourceKey}, append it to {@code destinationKey} and return its
569+
* value.<br>
544570
* <b>Blocks connection</b> until element available or {@code timeout} reached.
545571
*
546572
* @param sourceKey must not be {@literal null}.
@@ -560,35 +586,5 @@ default V rightPopAndLeftPush(K sourceKey, K destinationKey, Duration timeout) {
560586
return rightPopAndLeftPush(sourceKey, destinationKey, TimeoutUtils.toSeconds(timeout), TimeUnit.SECONDS);
561587
}
562588

563-
/**
564-
* Returns the first element from list at {@code key}.
565-
*
566-
* @implSpec
567-
* The implementation in this interface returns the result of calling {@code index(key, 0)}.
568-
*
569-
* @param key must not be {@literal null}.
570-
* @return {@literal null} when used in pipeline / transaction.
571-
*/
572-
@Nullable
573-
default V getFirst(K key) {
574-
return index(key, 0);
575-
}
576-
577-
/**
578-
* Returns the last element from list at {@code key}.
579-
*
580-
* @implSpec
581-
* If the result of calling {@code size(key)} is not null, The implementation in this interface returns the
582-
* result of calling {@code index(key, size - 1)}. Otherwise, it returns null.
583-
*
584-
* @param key must not be {@literal null}.
585-
* @return {@literal null} when used in pipeline / transaction.
586-
*/
587-
@Nullable
588-
default V getLast(K key) {
589-
Long size = size(key);
590-
return size != null ? index(key, size - 1) : null;
591-
}
592-
593589
RedisOperations<K, V> getOperations();
594590
}

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

+25
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
import org.springframework.data.redis.core.ListOperations.MoveFrom;
2828
import org.springframework.data.redis.core.ListOperations.MoveTo;
29+
import org.springframework.lang.Nullable;
2930
import org.springframework.util.Assert;
3031

3132
/**
@@ -276,6 +277,30 @@ default Mono<V> move(MoveFrom<K> from, MoveTo<K> to, Duration timeout) {
276277
*/
277278
Mono<Long> remove(K key, long count, Object value);
278279

280+
/**
281+
* Returns the first element from the list at {@code key}.
282+
*
283+
* @param key must not be {@literal null}.
284+
* @return
285+
* @since 3.4
286+
*/
287+
@Nullable
288+
default Mono<V> getFirst(K key) {
289+
return index(key, 0);
290+
}
291+
292+
/**
293+
* Returns the last element from the list at {@code key}.
294+
*
295+
* @param key must not be {@literal null}.
296+
* @return
297+
* @since 3.4
298+
*/
299+
@Nullable
300+
default Mono<V> getLast(K key) {
301+
return index(key, -1);
302+
}
303+
279304
/**
280305
* Get element at {@code index} form list at {@code key}.
281306
*

src/main/java/org/springframework/data/redis/support/collections/DefaultRedisList.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ public boolean offer(E element) {
349349
@Override
350350
@Nullable
351351
public E peek() {
352-
return listOps.index(0);
352+
return listOps.getFirst();
353353
}
354354

355355
@Override
@@ -426,7 +426,7 @@ public E peekFirst() {
426426
@Override
427427
@Nullable
428428
public E peekLast() {
429-
return listOps.index(-1);
429+
return listOps.getLast();
430430
}
431431

432432
@Override

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

+29-29
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,7 @@ public class DefaultListOperationsIntegrationIntegrationTests<K, V> {
5656
private final ListOperations<K, V> listOps;
5757

5858
public DefaultListOperationsIntegrationIntegrationTests(RedisTemplate<K, V> redisTemplate,
59-
ObjectFactory<K> keyFactory,
60-
ObjectFactory<V> valueFactory) {
59+
ObjectFactory<K> keyFactory, ObjectFactory<V> valueFactory) {
6160

6261
this.redisTemplate = redisTemplate;
6362
this.keyFactory = keyFactory;
@@ -347,62 +346,63 @@ void moveWithTimeout() {
347346
assertThat(listOps.range(target, 0, -1)).containsExactly(v4, v1);
348347
}
349348

350-
@ParameterizedRedisTest // DATAREDIS-1196
351-
@EnabledOnCommand("LPOS")
352-
void indexOf() {
349+
@ParameterizedRedisTest // GH-2937
350+
void getFirst() {
353351

354352
K key = keyFactory.instance();
355353
V v1 = valueFactory.instance();
356354
V v2 = valueFactory.instance();
357355
V v3 = valueFactory.instance();
358356

359-
assertThat(listOps.rightPush(key, v1)).isEqualTo(Long.valueOf(1));
360-
assertThat(listOps.rightPush(key, v2)).isEqualTo(Long.valueOf(2));
361-
assertThat(listOps.rightPush(key, v1, v3)).isEqualTo(Long.valueOf(3));
362-
assertThat(listOps.indexOf(key, v1)).isEqualTo(0);
357+
listOps.rightPush(key, v1);
358+
listOps.rightPush(key, v2);
359+
listOps.rightPush(key, v3);
360+
assertThat(listOps.getFirst(key)).isEqualTo(v1);
363361
}
364362

365-
@ParameterizedRedisTest // DATAREDIS-1196
366-
@EnabledOnCommand("LPOS")
367-
void lastIndexOf() {
363+
@ParameterizedRedisTest // GH-2937
364+
void getLast() {
368365

369366
K key = keyFactory.instance();
370367
V v1 = valueFactory.instance();
371368
V v2 = valueFactory.instance();
372369
V v3 = valueFactory.instance();
373370

374-
assertThat(listOps.rightPush(key, v1)).isEqualTo(Long.valueOf(1));
375-
assertThat(listOps.rightPush(key, v2)).isEqualTo(Long.valueOf(2));
376-
assertThat(listOps.rightPush(key, v1)).isEqualTo(Long.valueOf(3));
377-
assertThat(listOps.rightPush(key, v3)).isEqualTo(Long.valueOf(4));
378-
assertThat(listOps.lastIndexOf(key, v1)).isEqualTo(2);
371+
listOps.rightPush(key, v1);
372+
listOps.rightPush(key, v2);
373+
listOps.rightPush(key, v3);
374+
assertThat(listOps.getLast(key)).isEqualTo(v3);
379375
}
380376

381-
@ParameterizedRedisTest // GH-2937
382-
void getFirst() {
377+
@ParameterizedRedisTest // DATAREDIS-1196
378+
@EnabledOnCommand("LPOS")
379+
void indexOf() {
383380

384381
K key = keyFactory.instance();
385382
V v1 = valueFactory.instance();
386383
V v2 = valueFactory.instance();
387384
V v3 = valueFactory.instance();
388385

389-
listOps.rightPush(key, v1);
390-
listOps.rightPush(key, v2);
391-
listOps.rightPush(key, v3);
392-
assertThat(listOps.getFirst(key)).isEqualTo(v1);
386+
assertThat(listOps.rightPush(key, v1)).isEqualTo(Long.valueOf(1));
387+
assertThat(listOps.rightPush(key, v2)).isEqualTo(Long.valueOf(2));
388+
assertThat(listOps.rightPush(key, v1, v3)).isEqualTo(Long.valueOf(3));
389+
assertThat(listOps.indexOf(key, v1)).isEqualTo(0);
393390
}
394391

395-
@ParameterizedRedisTest // GH-2937
396-
void getLast() {
392+
@ParameterizedRedisTest // DATAREDIS-1196
393+
@EnabledOnCommand("LPOS")
394+
void lastIndexOf() {
397395

398396
K key = keyFactory.instance();
399397
V v1 = valueFactory.instance();
400398
V v2 = valueFactory.instance();
401399
V v3 = valueFactory.instance();
402400

403-
listOps.rightPush(key, v1);
404-
listOps.rightPush(key, v2);
405-
listOps.rightPush(key, v3);
406-
assertThat(listOps.getLast(key)).isEqualTo(v3);
401+
assertThat(listOps.rightPush(key, v1)).isEqualTo(Long.valueOf(1));
402+
assertThat(listOps.rightPush(key, v2)).isEqualTo(Long.valueOf(2));
403+
assertThat(listOps.rightPush(key, v1)).isEqualTo(Long.valueOf(3));
404+
assertThat(listOps.rightPush(key, v3)).isEqualTo(Long.valueOf(4));
405+
assertThat(listOps.lastIndexOf(key, v1)).isEqualTo(2);
407406
}
407+
408408
}

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

+34-22
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@
1515
*/
1616
package org.springframework.data.redis.core;
1717

18-
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
19-
import static org.assertj.core.api.Assumptions.assumeThat;
18+
import static org.assertj.core.api.Assertions.*;
19+
import static org.assertj.core.api.Assumptions.*;
20+
21+
import reactor.test.StepVerifier;
2022

2123
import java.time.Duration;
2224
import java.util.Collection;
@@ -33,8 +35,6 @@
3335
import org.springframework.data.redis.test.extension.parametrized.MethodSource;
3436
import org.springframework.data.redis.test.extension.parametrized.ParameterizedRedisTest;
3537

36-
import reactor.test.StepVerifier;
37-
3838
/**
3939
* Integration tests for {@link DefaultReactiveListOperations}.
4040
*
@@ -417,6 +417,32 @@ void index() {
417417
listOperations.index(key, 1).as(StepVerifier::create).expectNext(value2).verifyComplete();
418418
}
419419

420+
@ParameterizedRedisTest // GH-2937
421+
void getFirst() {
422+
423+
K key = keyFactory.instance();
424+
V v1 = valueFactory.instance();
425+
V v2 = valueFactory.instance();
426+
V v3 = valueFactory.instance();
427+
428+
listOperations.rightPushAll(key, v1, v2, v3).as(StepVerifier::create).expectNext(3L).verifyComplete();
429+
430+
listOperations.getFirst(key).as(StepVerifier::create).expectNext(v1).verifyComplete();
431+
}
432+
433+
@ParameterizedRedisTest // GH-2937
434+
void getLast() {
435+
436+
K key = keyFactory.instance();
437+
V v1 = valueFactory.instance();
438+
V v2 = valueFactory.instance();
439+
V v3 = valueFactory.instance();
440+
441+
listOperations.rightPushAll(key, v1, v2, v3).as(StepVerifier::create).expectNext(3L).verifyComplete();
442+
443+
listOperations.getLast(key).as(StepVerifier::create).expectNext(v3).verifyComplete();
444+
}
445+
420446
@ParameterizedRedisTest // DATAREDIS-1196
421447
@EnabledOnCommand("LPOS")
422448
void indexOf() {
@@ -469,16 +495,9 @@ void leftPopWithCount() {
469495
V value2 = valueFactory.instance();
470496
V value3 = valueFactory.instance();
471497

472-
listOperations.leftPushAll(key, value1, value2, value3)
473-
.as(StepVerifier::create)
474-
.expectNext(3L)
475-
.verifyComplete();
498+
listOperations.leftPushAll(key, value1, value2, value3).as(StepVerifier::create).expectNext(3L).verifyComplete();
476499

477-
listOperations.leftPop(key, 2)
478-
.as(StepVerifier::create)
479-
.expectNext(value3)
480-
.expectNext(value2)
481-
.verifyComplete();
500+
listOperations.leftPop(key, 2).as(StepVerifier::create).expectNext(value3).expectNext(value2).verifyComplete();
482501
}
483502

484503
@ParameterizedRedisTest // DATAREDIS-602
@@ -505,16 +524,9 @@ void rightPopWithCount() {
505524
V value2 = valueFactory.instance();
506525
V value3 = valueFactory.instance();
507526

508-
listOperations.rightPushAll(key, value3, value2, value1)
509-
.as(StepVerifier::create)
510-
.expectNext(3L)
511-
.verifyComplete();
527+
listOperations.rightPushAll(key, value3, value2, value1).as(StepVerifier::create).expectNext(3L).verifyComplete();
512528

513-
listOperations.rightPop(key, 2)
514-
.as(StepVerifier::create)
515-
.expectNext(value1)
516-
.expectNext(value2)
517-
.verifyComplete();
529+
listOperations.rightPop(key, 2).as(StepVerifier::create).expectNext(value1).expectNext(value2).verifyComplete();
518530
}
519531

520532
@ParameterizedRedisTest // DATAREDIS-602

0 commit comments

Comments
 (0)