From 739b9179220ca836cdc31e2b4cee79bbe9285d68 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 16 Jun 2021 13:59:36 +0200 Subject: [PATCH] Add popFirst and popLast methods to RedisZSet. See #2007 Original Pull Request: #2088 --- .../support/collections/DefaultRedisZSet.java | 65 ++++++++++++++++++ .../redis/support/collections/RedisZSet.java | 45 +++++++++++++ .../AbstractRedisZSetTestIntegration.java | 67 +++++++++++++++++++ 3 files changed, 177 insertions(+) diff --git a/src/main/java/org/springframework/data/redis/support/collections/DefaultRedisZSet.java b/src/main/java/org/springframework/data/redis/support/collections/DefaultRedisZSet.java index d9b9add8a..0cca0c8a3 100644 --- a/src/main/java/org/springframework/data/redis/support/collections/DefaultRedisZSet.java +++ b/src/main/java/org/springframework/data/redis/support/collections/DefaultRedisZSet.java @@ -19,6 +19,7 @@ import java.util.Collection; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.Set; +import java.util.concurrent.TimeUnit; import org.springframework.data.redis.connection.DataType; import org.springframework.data.redis.connection.RedisZSetCommands.Limit; @@ -380,6 +381,38 @@ public class DefaultRedisZSet extends AbstractRedisCollection implements R throw new NoSuchElementException(); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#popFirst() + */ + @Override + public E popFirst() { + + TypedTuple tuple = boundZSetOps.popMin(); + + if (tuple != null) { + return tuple.getValue(); + } + + throw new NoSuchElementException(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#popFirst(long, java.util.concurrent.TimeUnit) + */ + @Override + public E popFirst(long timeout, TimeUnit unit) { + + TypedTuple tuple = boundZSetOps.popMin(timeout, unit); + + if (tuple != null) { + return tuple.getValue(); + } + + throw new NoSuchElementException(); + } + /* * (non-Javadoc) * @see org.springframework.data.redis.support.collections.RedisZSet#last() @@ -397,6 +430,38 @@ public class DefaultRedisZSet extends AbstractRedisCollection implements R throw new NoSuchElementException(); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#popLast() + */ + @Override + public E popLast() { + + TypedTuple tuple = boundZSetOps.popMax(); + + if (tuple != null) { + return tuple.getValue(); + } + + throw new NoSuchElementException(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#popLast(long, java.util.concurrent.TimeUnit) + */ + @Override + public E popLast(long timeout, TimeUnit unit) { + + TypedTuple tuple = boundZSetOps.popMax(timeout, unit); + + if (tuple != null) { + return tuple.getValue(); + } + + throw new NoSuchElementException(); + } + /* * (non-Javadoc) * @see org.springframework.data.redis.support.collections.RedisZSet#rank(java.lang.Object) diff --git a/src/main/java/org/springframework/data/redis/support/collections/RedisZSet.java b/src/main/java/org/springframework/data/redis/support/collections/RedisZSet.java index 86fc8646e..e3ccf919a 100644 --- a/src/main/java/org/springframework/data/redis/support/collections/RedisZSet.java +++ b/src/main/java/org/springframework/data/redis/support/collections/RedisZSet.java @@ -21,6 +21,7 @@ import java.util.Iterator; import java.util.NoSuchElementException; import java.util.Set; import java.util.SortedSet; +import java.util.concurrent.TimeUnit; import org.springframework.data.redis.connection.RedisZSetCommands.Limit; import org.springframework.data.redis.connection.RedisZSetCommands.Range; @@ -217,6 +218,28 @@ public interface RedisZSet extends RedisCollection, Set { */ E first(); + /** + * Removes the first (lowest) object at the top of this sorted set and returns that object as the value of this + * function. + * + * @return the first (lowest) element currently in this sorted set. + * @throws NoSuchElementException sorted set is empty. + * @since 2.6 + */ + E popFirst(); + + /** + * Removes the first (lowest) object at the top of this sorted set and returns that object as the value of this + * function. Blocks connection until element available or {@code timeout} reached. + * + * @param timeout + * @param unit must not be {@literal null}. + * @return the first (lowest) element currently in this sorted set. + * @throws NoSuchElementException sorted set is empty. + * @since 2.6 + */ + E popFirst(long timeout, TimeUnit unit); + /** * Returns the last (highest) element currently in this sorted set. * @@ -225,6 +248,28 @@ public interface RedisZSet extends RedisCollection, Set { */ E last(); + /** + * Removes the last (highest) object at the top of this sorted set and returns that object as the value of this + * function. + * + * @return the last (highest) element currently in this sorted set. + * @throws NoSuchElementException sorted set is empty. + * @since 2.6 + */ + E popLast(); + + /** + * Removes the last (highest) object at the top of this sorted set and returns that object as the value of this + * function. Blocks connection until element available or {@code timeout} reached. + * + * @param timeout + * @param unit must not be {@literal null}. + * @return the last (highest) element currently in this sorted set. + * @throws NoSuchElementException sorted set is empty. + * @since 2.6 + */ + E popLast(long timeout, TimeUnit unit); + /** * @since 1.4 * @return diff --git a/src/test/java/org/springframework/data/redis/support/collections/AbstractRedisZSetTestIntegration.java b/src/test/java/org/springframework/data/redis/support/collections/AbstractRedisZSetTestIntegration.java index ee42ccb61..28b429baf 100644 --- a/src/test/java/org/springframework/data/redis/support/collections/AbstractRedisZSetTestIntegration.java +++ b/src/test/java/org/springframework/data/redis/support/collections/AbstractRedisZSetTestIntegration.java @@ -23,6 +23,7 @@ import java.util.Arrays; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.Set; +import java.util.concurrent.TimeUnit; import org.assertj.core.data.Offset; import org.junit.jupiter.api.BeforeEach; @@ -37,6 +38,7 @@ import org.springframework.data.redis.core.BoundZSetOperations; import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.ZSetOperations.TypedTuple; +import org.springframework.data.redis.test.condition.EnabledOnCommand; import org.springframework.data.redis.test.extension.parametrized.ParameterizedRedisTest; /** @@ -119,6 +121,38 @@ public abstract class AbstractRedisZSetTestIntegration extends AbstractRedisC assertThat(zSet.first()).isEqualTo(t1); } + @ParameterizedRedisTest + @EnabledOnCommand("ZPOPMIN") + void testPopFirst() { + + T t1 = getT(); + T t2 = getT(); + T t3 = getT(); + + zSet.add(t1, 3); + zSet.add(t2, 4); + zSet.add(t3, 5); + + assertThat(zSet.popFirst()).isEqualTo(t1); + assertThat(zSet).hasSize(2); + } + + @ParameterizedRedisTest + @EnabledOnCommand("ZPOPMIN") + void testPopFirstWithTimeout() { + + T t1 = getT(); + T t2 = getT(); + T t3 = getT(); + + zSet.add(t1, 3); + zSet.add(t2, 4); + zSet.add(t3, 5); + + assertThat(zSet.popFirst(1, TimeUnit.SECONDS)).isEqualTo(t1); + assertThat(zSet).hasSize(2); + } + @ParameterizedRedisTest void testFirstException() { assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(() -> zSet.first()); @@ -126,6 +160,7 @@ public abstract class AbstractRedisZSetTestIntegration extends AbstractRedisC @ParameterizedRedisTest void testLast() { + T t1 = getT(); T t2 = getT(); T t3 = getT(); @@ -138,6 +173,38 @@ public abstract class AbstractRedisZSetTestIntegration extends AbstractRedisC assertThat(zSet.last()).isEqualTo(t3); } + @ParameterizedRedisTest + @EnabledOnCommand("ZPOPMAX") + void testPopLast() { + + T t1 = getT(); + T t2 = getT(); + T t3 = getT(); + + zSet.add(t1, 3); + zSet.add(t2, 4); + zSet.add(t3, 5); + + assertThat(zSet.popLast()).isEqualTo(t3); + assertThat(zSet).hasSize(2); + } + + @ParameterizedRedisTest + @EnabledOnCommand("ZPOPMAX") + void testPopLastWithTimeout() { + + T t1 = getT(); + T t2 = getT(); + T t3 = getT(); + + zSet.add(t1, 3); + zSet.add(t2, 4); + zSet.add(t3, 5); + + assertThat(zSet.popLast(1, TimeUnit.SECONDS)).isEqualTo(t3); + assertThat(zSet).hasSize(2); + } + @ParameterizedRedisTest void testLastException() { assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(() -> zSet.last());