diff --git a/pom.xml b/pom.xml
index b20e7c9dcc..edcc275364 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
org.springframework.data
spring-data-redis
- 2.5.0-SNAPSHOT
+ 2.5.0-GH-1816-SNAPSHOT
Spring Data Redis
diff --git a/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java b/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java
index 00023ea611..90976449bb 100644
--- a/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java
+++ b/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java
@@ -1581,6 +1581,15 @@ public Long zRemRange(byte[] key, long start, long end) {
return convertAndReturn(delegate.zRemRange(key, start, end), Converters.identityConverter());
}
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.redis.connection.RedisZSetCommands#zRemRangeByLex(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range)
+ */
+ @Override
+ public Long zRemRangeByLex(byte[] key, Range range) {
+ return convertAndReturn(delegate.zRemRangeByLex(key, range), Converters.identityConverter());
+ }
+
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisZSetCommands#zRemRangeByScore(byte[], double, double)
@@ -2829,6 +2838,15 @@ public Long zRemRange(String key, long start, long end) {
return zRemRange(serialize(key), start, end);
}
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.redis.connection.StringRedisConnection#zRemRange(java.lang.String, org.springframework.data.redis.connection.RedisZSetCommands.Range)
+ */
+ @Override
+ public Long zRemRangeByLex(String key, Range range) {
+ return zRemRangeByLex(serialize(key), range);
+ }
+
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.StringRedisConnection#zRemRangeByScore(java.lang.String, double, double)
diff --git a/src/main/java/org/springframework/data/redis/connection/DefaultedRedisConnection.java b/src/main/java/org/springframework/data/redis/connection/DefaultedRedisConnection.java
index 8594d8f50d..41c50d7f18 100644
--- a/src/main/java/org/springframework/data/redis/connection/DefaultedRedisConnection.java
+++ b/src/main/java/org/springframework/data/redis/connection/DefaultedRedisConnection.java
@@ -1024,6 +1024,13 @@ default Long zRemRange(byte[] key, long start, long end) {
return zSetCommands().zRemRange(key, start, end);
}
+ /** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */
+ @Override
+ @Deprecated
+ default Long zRemRangeByLex(byte[] key, Range range) {
+ return zSetCommands().zRemRangeByLex(key, range);
+ }
+
/** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */
@Override
@Deprecated
diff --git a/src/main/java/org/springframework/data/redis/connection/ReactiveZSetCommands.java b/src/main/java/org/springframework/data/redis/connection/ReactiveZSetCommands.java
index e9a7aeadd8..27e24253cf 100644
--- a/src/main/java/org/springframework/data/redis/connection/ReactiveZSetCommands.java
+++ b/src/main/java/org/springframework/data/redis/connection/ReactiveZSetCommands.java
@@ -1444,6 +1444,82 @@ default Mono zRemRangeByScore(ByteBuffer key, Range range) {
*/
Flux> zRemRangeByScore(Publisher commands);
+ /**
+ * {@code ZREMRANGEBYLEX} command parameters.
+ *
+ * @author Christoph Strobl
+ * @since 2.5
+ * @see Redis Documentation: ZREMRANGEBYLEX
+ */
+ class ZRemRangeByLexCommand extends KeyCommand {
+
+ private final Range range;
+
+ private ZRemRangeByLexCommand(@Nullable ByteBuffer key, Range range) {
+
+ super(key);
+ this.range = range;
+ }
+
+ /**
+ * Creates a new {@link ZRemRangeByLexCommand} given a {@link Range}.
+ *
+ * @param range must not be {@literal null}.
+ * @return a new {@link ZRemRangeByScoreCommand} for {@link Range}.
+ */
+ public static ZRemRangeByLexCommand lexWithin(Range range) {
+ return new ZRemRangeByLexCommand(null, range);
+ }
+
+ /**
+ * Applies the {@literal key}. Constructs a new command instance with all previously configured properties.
+ *
+ * @param key must not be {@literal null}.
+ * @return a new {@link ZRemRangeByLexCommand} with {@literal key} applied.
+ */
+ public ZRemRangeByLexCommand from(ByteBuffer key) {
+
+ Assert.notNull(key, "Key must not be null!");
+
+ return new ZRemRangeByLexCommand(key, range);
+ }
+
+ /**
+ * @return
+ */
+ public Range getRange() {
+ return range;
+ }
+ }
+
+ /**
+ * Remove elements in {@link Range} from sorted set with {@literal key}.
+ *
+ * @param key must not be {@literal null}.
+ * @param range must not be {@literal null}.
+ * @return a {@link Mono} emitting the number of removed elements.
+ * @since 2.5
+ * @see Redis Documentation: ZREMRANGEBYLEX
+ */
+ default Mono zRemRangeByLex(ByteBuffer key, Range range) {
+
+ Assert.notNull(key, "Key must not be null!");
+ Assert.notNull(range, "Range must not be null!");
+
+ return zRemRangeByLex(Mono.just(ZRemRangeByLexCommand.lexWithin(range).from(key))).next()
+ .map(NumericResponse::getOutput);
+ }
+
+ /**
+ * Remove elements in {@link Range} from sorted set with {@link ZRemRangeByLexCommand#getKey()}.
+ *
+ * @param commands must not be {@literal null}.
+ * @return
+ * @since 2.5
+ * @see Redis Documentation: ZREMRANGEBYLEX
+ */
+ Flux> zRemRangeByLex(Publisher commands);
+
/**
* {@code ZUNIONSTORE} command parameters.
*
diff --git a/src/main/java/org/springframework/data/redis/connection/RedisZSetCommands.java b/src/main/java/org/springframework/data/redis/connection/RedisZSetCommands.java
index a9ced62400..d26e5af2f6 100644
--- a/src/main/java/org/springframework/data/redis/connection/RedisZSetCommands.java
+++ b/src/main/java/org/springframework/data/redis/connection/RedisZSetCommands.java
@@ -814,6 +814,17 @@ default Long zCount(byte[] key, double min, double max) {
@Nullable
Long zRemRange(byte[] key, long start, long end);
+ /**
+ * Remove all elements between the lexicographical {@link Range}.
+ *
+ * @param key must not be {@literal null}.
+ * @param range must not be {@literal null}.
+ * @return the number of elements removed, or {@literal null} when used in pipeline / transaction.
+ * @since 2.5
+ * @see Redis Documentation: ZREMRANGEBYLEX
+ */
+ Long zRemRangeByLex(byte[] key, Range range);
+
/**
* Remove elements with scores between {@code min} and {@code max} from sorted set with {@code key}.
*
diff --git a/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java b/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java
index 7b353ba3b7..8633ea3a57 100644
--- a/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java
+++ b/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java
@@ -1376,6 +1376,18 @@ default Long lPos(String key, String element) {
*/
Long zRemRange(String key, long start, long end);
+
+ /**
+ * Remove all elements between the lexicographical {@link Range}.
+ *
+ * @param key must not be {@literal null}.
+ * @param range must not be {@literal null}.
+ * @return the number of elements removed, or {@literal null} when used in pipeline / transaction.
+ * @since 2.5
+ * @see Redis Documentation: ZREMRANGEBYLEX
+ */
+ Long zRemRangeByLex(String key, Range range);
+
/**
* Remove elements with scores between {@code min} and {@code max} from sorted set with {@code key}.
*
diff --git a/src/main/java/org/springframework/data/redis/connection/convert/SetConverter.java b/src/main/java/org/springframework/data/redis/connection/convert/SetConverter.java
index b01e9adfd1..ff25069835 100644
--- a/src/main/java/org/springframework/data/redis/connection/convert/SetConverter.java
+++ b/src/main/java/org/springframework/data/redis/connection/convert/SetConverter.java
@@ -15,7 +15,6 @@
*/
package org.springframework.data.redis.connection.convert;
-import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.stream.Collectors;
@@ -24,7 +23,7 @@
import org.springframework.util.Assert;
/**
- * Converts a Set of values of one type to a Set of values of another type
+ * Converts a Set of values of one type to a Set of values of another type preserving item order.
*
* @author Jennifer Hickey
* @author Christoph Strobl
@@ -50,9 +49,7 @@ public SetConverter(Converter itemConverter) {
*/
@Override
public Set convert(Set source) {
-
- return source.stream().map(itemConverter::convert)
- .collect(Collectors.toCollection(source instanceof LinkedHashSet ? LinkedHashSet::new : HashSet::new));
+ return source.stream().map(itemConverter::convert).collect(Collectors.toCollection(LinkedHashSet::new));
}
}
diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterZSetCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterZSetCommands.java
index e64492dbf3..a37359fc7c 100644
--- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterZSetCommands.java
+++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterZSetCommands.java
@@ -348,6 +348,26 @@ public Set zRangeByLex(byte[] key, Range range, Limit limit) {
}
}
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.redis.connection.RedisZSetCommands#zRemRangeByLex(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range)
+ */
+ @Override
+ public Long zRemRangeByLex(byte[] key, Range range) {
+
+ Assert.notNull(key, "Key must not be null!");
+ Assert.notNull(range, "Range must not be null for ZREMRANGEBYLEX!");
+
+ byte[] min = JedisConverters.boundaryToBytesForZRangeByLex(range.getMin(), JedisConverters.MINUS_BYTES);
+ byte[] max = JedisConverters.boundaryToBytesForZRangeByLex(range.getMax(), JedisConverters.PLUS_BYTES);
+
+ try {
+ return connection.getCluster().zremrangeByLex(key, min, max);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByLex(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit)
diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisZSetCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisZSetCommands.java
index 48c70d506f..d9c396a8e1 100644
--- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisZSetCommands.java
+++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisZSetCommands.java
@@ -336,6 +336,22 @@ public Long zRemRange(byte[] key, long start, long end) {
end);
}
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.redis.connection.RedisZSetCommands#zRemRangeByLex(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range)
+ */
+ @Override
+ public Long zRemRangeByLex(byte[] key, Range range) {
+
+ Assert.notNull(key, "Key must not be null!");
+ Assert.notNull(range, "Range must not be null for ZREMRANGEBYLEX!");
+
+ byte[] min = JedisConverters.boundaryToBytesForZRangeByLex(range.getMin(), JedisConverters.MINUS_BYTES);
+ byte[] max = JedisConverters.boundaryToBytesForZRangeByLex(range.getMax(), JedisConverters.PLUS_BYTES);
+
+ return connection.invoke().just(BinaryJedis::zremrangeByLex, MultiKeyPipelineBase::zremrangeByLex, key, min, max);
+ }
+
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisZSetCommands#zRemRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range)
diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveZSetCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveZSetCommands.java
index 254dba78d3..1cc6ae1c3f 100644
--- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveZSetCommands.java
+++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveZSetCommands.java
@@ -418,6 +418,24 @@ public Flux> zRemRangeByScore(
}));
}
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.redis.connection.ReactiveZSetCommands#zRemRangeByLex(org.reactivestreams.Publisher)
+ */
+ @Override
+ public Flux> zRemRangeByLex(Publisher commands) {
+
+ return connection.execute(cmd -> Flux.from(commands).concatMap(command -> {
+
+ Assert.notNull(command.getKey(), "Key must not be null!");
+ Assert.notNull(command.getRange(), "Range must not be null!");
+
+ Mono result = cmd.zremrangebylex(command.getKey(), RangeConverter.toRange(command.getRange()));
+
+ return result.map(value -> new NumericResponse<>(command, value));
+ }));
+ }
+
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.ReactiveZSetCommands#zUnionStore(org.reactivestreams.Publisher)
diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceZSetCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceZSetCommands.java
index da17bd1957..9d011364ce 100644
--- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceZSetCommands.java
+++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceZSetCommands.java
@@ -312,6 +312,20 @@ public Long zRemRange(byte[] key, long start, long end) {
return connection.invoke().just(RedisSortedSetAsyncCommands::zremrangebyrank, key, start, end);
}
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.redis.connection.RedisZSetCommands#zRemRangeByLex(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range)
+ */
+ @Override
+ public Long zRemRangeByLex(byte[] key, Range range) {
+
+ Assert.notNull(key, "Key must not be null!");
+ Assert.notNull(range, "Range must not be null for ZREMRANGEBYLEX!");
+
+ return connection.invoke().just(RedisSortedSetAsyncCommands::zremrangebylex, key,
+ LettuceConverters. toRange(range, true));
+ }
+
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisZSetCommands#zRemRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range)
diff --git a/src/main/java/org/springframework/data/redis/core/BoundZSetOperations.java b/src/main/java/org/springframework/data/redis/core/BoundZSetOperations.java
index 69cb3facfe..5baa3572ef 100644
--- a/src/main/java/org/springframework/data/redis/core/BoundZSetOperations.java
+++ b/src/main/java/org/springframework/data/redis/core/BoundZSetOperations.java
@@ -252,6 +252,17 @@ public interface BoundZSetOperations extends BoundKeyOperations {
@Nullable
Long removeRange(long start, long end);
+ /**
+ * Remove elements in {@link Range} from sorted set with the bound key.
+ *
+ * @param range must not be {@literal null}.
+ * @return {@literal null} when used in pipeline / transaction.
+ * @since 2.5
+ * @see Redis Documentation: ZREMRANGEBYLEX
+ */
+ @Nullable
+ Long removeRangeByLex(Range range);
+
/**
* Remove elements with scores between {@code min} and {@code max} from sorted set with the bound key.
*
diff --git a/src/main/java/org/springframework/data/redis/core/DefaultBoundZSetOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultBoundZSetOperations.java
index 7b2efd1062..fc3b5f9b73 100644
--- a/src/main/java/org/springframework/data/redis/core/DefaultBoundZSetOperations.java
+++ b/src/main/java/org/springframework/data/redis/core/DefaultBoundZSetOperations.java
@@ -249,6 +249,15 @@ public Long removeRange(long start, long end) {
return ops.removeRange(getKey(), start, end);
}
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.redis.core.BoundZSetOperations#removeRangeByLex(org.springframework.data.redis.connection.RedisZSetCommands.Range)
+ */
+ @Override
+ public Long removeRangeByLex(Range range) {
+ return ops.removeRangeByLex(getKey(), range);
+ }
+
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.BoundZSetOperations#removeRangeByScore(double, double)
diff --git a/src/main/java/org/springframework/data/redis/core/DefaultReactiveZSetOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultReactiveZSetOperations.java
index 327a9cd3a8..0995bc96d0 100644
--- a/src/main/java/org/springframework/data/redis/core/DefaultReactiveZSetOperations.java
+++ b/src/main/java/org/springframework/data/redis/core/DefaultReactiveZSetOperations.java
@@ -383,6 +383,19 @@ public Mono removeRange(K key, Range range) {
return createMono(connection -> connection.zRemRangeByRank(rawKey(key), range));
}
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.redis.core.ReactiveZSetOperations#removeRangebyLex(java.lang.Object, org.springframework.data.domain.Range)
+ */
+ @Override
+ public Mono removeRangeByLex(K key, Range range) {
+
+ Assert.notNull(key, "Key must not be null!");
+ Assert.notNull(range, "Range must not be null!");
+
+ return createMono(connection -> connection.zRemRangeByLex(rawKey(key), range));
+ }
+
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.ReactiveZSetOperations#removeRangeByScore(java.lang.Object, org.springframework.data.domain.Range)
diff --git a/src/main/java/org/springframework/data/redis/core/DefaultZSetOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultZSetOperations.java
index 3c2dac203f..1c14991326 100644
--- a/src/main/java/org/springframework/data/redis/core/DefaultZSetOperations.java
+++ b/src/main/java/org/springframework/data/redis/core/DefaultZSetOperations.java
@@ -353,6 +353,17 @@ public Long removeRange(K key, long start, long end) {
return execute(connection -> connection.zRemRange(rawKey, start, end), true);
}
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.redis.core.ZSetOperations#removeRangeByLex(java.lang.Object, Range)
+ */
+ @Override
+ public Long removeRangeByLex(K key, Range range) {
+
+ byte[] rawKey = rawKey(key);
+ return execute(connection -> connection.zRemRangeByLex(rawKey, range), true);
+ }
+
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.ZSetOperations#removeRangeByScore(java.lang.Object, double, double)
diff --git a/src/main/java/org/springframework/data/redis/core/ReactiveZSetOperations.java b/src/main/java/org/springframework/data/redis/core/ReactiveZSetOperations.java
index 0db8491a27..1914da9664 100644
--- a/src/main/java/org/springframework/data/redis/core/ReactiveZSetOperations.java
+++ b/src/main/java/org/springframework/data/redis/core/ReactiveZSetOperations.java
@@ -310,6 +310,17 @@ default Flux> scan(K key) {
*/
Mono removeRange(K key, Range range);
+ /**
+ * Remove elements in range from sorted set with {@code key}.
+ *
+ * @param key must not be {@literal null}.
+ * @param range must not be {@literal null}.
+ * @return a {@link Mono} emitting the number or removed elements.
+ * @since 2.5
+ * @see Redis Documentation: ZREMRANGEBYRANK
+ */
+ Mono removeRangeByLex(K key, Range range);
+
/**
* Remove elements with scores between {@code min} and {@code max} from sorted set with {@code key}.
*
diff --git a/src/main/java/org/springframework/data/redis/core/ZSetOperations.java b/src/main/java/org/springframework/data/redis/core/ZSetOperations.java
index 61b7cc55ae..4aa5c82634 100644
--- a/src/main/java/org/springframework/data/redis/core/ZSetOperations.java
+++ b/src/main/java/org/springframework/data/redis/core/ZSetOperations.java
@@ -344,6 +344,18 @@ interface TypedTuple extends Comparable> {
@Nullable
Long removeRange(K key, long start, long end);
+ /**
+ * Remove elements in {@link Range} from sorted set with {@literal key}.
+ *
+ * @param key must not be {@literal null}.
+ * @param range must not be {@literal null}.
+ * @return {@literal null} when used in pipeline / transaction.
+ * @since 2.5
+ * @see Redis Documentation: ZREMRANGEBYLEX
+ */
+ @Nullable
+ Long removeRangeByLex(K key, Range range);
+
/**
* Remove elements with scores between {@code min} and {@code max} from sorted set with {@code key}.
*
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 1b3d29d6a7..4fda95ea62 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
@@ -226,6 +226,16 @@ public RedisZSet remove(long start, long end) {
return this;
}
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.redis.support.collections.RedisZSet#removeRangeByLex(org.springframework.data.redis.connection.RedisZSetCommands.Range)
+ */
+ @Override
+ public Set removeByLex(Range range) {
+ boundZSetOps.removeRangeByLex(range);
+ return this;
+ }
+
/*
* (non-Javadoc)
* @see org.springframework.data.redis.support.collections.RedisZSet#removeByScore(double, double)
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 53777114c7..e6af859e57 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
@@ -118,6 +118,15 @@ default Set reverseRangeByLex(Range range) {
RedisZSet remove(long start, long end);
+ /**
+ * Remove all elements in range.
+ *
+ * @param range must not be {@literal null}.
+ * @return never {@literal null}.
+ * @since 2.5
+ */
+ Set removeByLex(Range range);
+
RedisZSet removeByScore(double min, double max);
/**
diff --git a/src/main/kotlin/org/springframework/data/redis/core/ReactiveZSetOperationsExtensions.kt b/src/main/kotlin/org/springframework/data/redis/core/ReactiveZSetOperationsExtensions.kt
index fc28bca965..494da393b6 100644
--- a/src/main/kotlin/org/springframework/data/redis/core/ReactiveZSetOperationsExtensions.kt
+++ b/src/main/kotlin/org/springframework/data/redis/core/ReactiveZSetOperationsExtensions.kt
@@ -186,6 +186,15 @@ suspend fun ReactiveZSetOperations.scoreAndAwait(key: K
suspend fun ReactiveZSetOperations.removeRangeAndAwait(key: K, range: Range): Long =
removeRange(key, range).awaitSingle()
+/**
+ * Coroutines variant of [ReactiveZSetOperations.removeRangeByLex].
+ *
+ * @author Christoph Strobl
+ * @since 2.5
+ */
+suspend fun ReactiveZSetOperations.removeRangeByLexAndAwait(key: K, range: Range): Long =
+ removeRangeByLex(key, range).awaitSingle()
+
/**
* Coroutines variant of [ReactiveZSetOperations.removeRangeByScore].
*
diff --git a/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java
index 00980b8bd2..8defccb3d4 100644
--- a/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java
+++ b/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java
@@ -1905,6 +1905,25 @@ void testZRemRangeByRank() {
verifyResults(Arrays.asList(new Object[] { true, true, 2L, new LinkedHashSet(0) }));
}
+ @Test // GH-1816
+ void testZRemRangeByLex() {
+
+ actual.add(connection.zAdd("myset", 0, "aaaa"));
+ actual.add(connection.zAdd("myset", 0, "b"));
+ actual.add(connection.zAdd("myset", 0, "c"));
+ actual.add(connection.zAdd("myset", 0, "d"));
+ actual.add(connection.zAdd("myset", 0, "e"));
+ actual.add(connection.zAdd("myset", 0, "foo"));
+ actual.add(connection.zAdd("myset", 0, "zap"));
+ actual.add(connection.zAdd("myset", 0, "zip"));
+ actual.add(connection.zAdd("myset", 0, "ALPHA"));
+ actual.add(connection.zAdd("myset", 0, "alpha"));
+ actual.add(connection.zRemRangeByLex("myset", Range.range().gte("alpha").lte("omega")));
+
+ actual.add(connection.zRange("myset", 0L, -1L));
+ verifyResults(Arrays.asList(new Object[] { true, true, true,true, true, true,true, true, true,true, 6L, new LinkedHashSet(Arrays.asList("ALPHA", "aaaa", "zap", "zip")) }));
+ }
+
@Test
void testZRemRangeByScore() {
actual.add(connection.zAdd("myset", 2, "Bob"));
diff --git a/src/test/java/org/springframework/data/redis/connection/RedisConnectionUnitTests.java b/src/test/java/org/springframework/data/redis/connection/RedisConnectionUnitTests.java
index 1b0d88e564..b5a995fea0 100644
--- a/src/test/java/org/springframework/data/redis/connection/RedisConnectionUnitTests.java
+++ b/src/test/java/org/springframework/data/redis/connection/RedisConnectionUnitTests.java
@@ -948,6 +948,11 @@ public Long zRemRangeByScore(byte[] key, Range range) {
return delegate.zRemRangeByScore(key, range);
}
+ @Override
+ public Long zRemRangeByLex(byte[] key, Range range) {
+ return delegate.zRemRangeByLex(key, range);
+ }
+
@Override
public Set zRangeByScore(byte[] key, Range range) {
return delegate.zRangeByScore(key, range);
diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveZSetCommandsIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveZSetCommandsIntegrationTests.java
index 3fcf219e74..0e4cb2de42 100644
--- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveZSetCommandsIntegrationTests.java
+++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveZSetCommandsIntegrationTests.java
@@ -412,6 +412,26 @@ void zRemRangeByRankShouldRemoveValuesCorrectly() {
assertThat(connection.zSetCommands().zRemRangeByRank(KEY_1_BBUFFER, ONE_TO_TWO).block()).isEqualTo(2L);
}
+ @ParameterizedRedisTest // GH-1816
+ void zRemRangeByLexRemovesValuesCorrectly() {
+
+ nativeCommands.zadd(KEY_1, 0D, "aaaa");
+ nativeCommands.zadd(KEY_1, 0D, "b");
+ nativeCommands.zadd(KEY_1, 0D, "c");
+ nativeCommands.zadd(KEY_1, 0D, "d");
+ nativeCommands.zadd(KEY_1, 0D, "e");
+ nativeCommands.zadd(KEY_1, 0D, "foo");
+ nativeCommands.zadd(KEY_1, 0D, "zap");
+ nativeCommands.zadd(KEY_1, 0D, "zip");
+ nativeCommands.zadd(KEY_1, 0D, "ALPHA");
+ nativeCommands.zadd(KEY_1, 0D, "alpha");
+
+ connection.zSetCommands().zRemRangeByLex(KEY_1_BBUFFER, Range.closed("alpha", "omega")) //
+ .as(StepVerifier::create) //
+ .expectNext(6L) //
+ .verifyComplete();
+ }
+
@ParameterizedRedisTest // DATAREDIS-525
void zRemRangeByScoreShouldRemoveValuesCorrectly() {
diff --git a/src/test/java/org/springframework/data/redis/core/ConnectionMockingRedisTemplate.java b/src/test/java/org/springframework/data/redis/core/ConnectionMockingRedisTemplate.java
new file mode 100644
index 0000000000..a59efb08fb
--- /dev/null
+++ b/src/test/java/org/springframework/data/redis/core/ConnectionMockingRedisTemplate.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2021 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.redis.core;
+
+import org.mockito.Mockito;
+import org.springframework.data.redis.connection.RedisConnection;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.serializer.RedisSerializer;
+
+/**
+ * @author Christoph Strobl
+ */
+public class ConnectionMockingRedisTemplate extends RedisTemplate {
+
+ private RedisConnection connectionMock;
+
+ private ConnectionMockingRedisTemplate() {
+
+ connectionMock = Mockito.mock(RedisConnection.class);
+
+ RedisConnectionFactory connectionFactory = Mockito.mock(RedisConnectionFactory.class);
+ Mockito.when(connectionFactory.getConnection()).thenReturn(connectionMock);
+
+ setConnectionFactory(connectionFactory);
+ }
+
+ static ConnectionMockingRedisTemplate template() {
+ return builder().build();
+ }
+
+ static MockTemplateBuilder builder() {
+ return new MockTemplateBuilder();
+ }
+
+ public RedisConnection verify() {
+ return Mockito.verify(connectionMock);
+ }
+
+ public byte[] serializeKey(K key) {
+ return ((RedisSerializer) getKeySerializer()).serialize(key);
+ }
+
+ public RedisConnection never() {
+ return Mockito.verify(connectionMock, Mockito.never());
+ }
+
+ public RedisConnection doReturn(Object o) {
+ return Mockito.doReturn(o).when(connectionMock);
+ }
+
+ public static class MockTemplateBuilder {
+
+ private ConnectionMockingRedisTemplate template = new ConnectionMockingRedisTemplate();
+
+ public ConnectionMockingRedisTemplate build() {
+
+ template.afterPropertiesSet();
+ return template;
+ }
+
+ }
+
+}
diff --git a/src/test/java/org/springframework/data/redis/core/DefaultBoundZSetOperationsUnitTests.java b/src/test/java/org/springframework/data/redis/core/DefaultBoundZSetOperationsUnitTests.java
new file mode 100644
index 0000000000..a94dca5560
--- /dev/null
+++ b/src/test/java/org/springframework/data/redis/core/DefaultBoundZSetOperationsUnitTests.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2021 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.redis.core;
+
+import static org.mockito.ArgumentMatchers.*;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.data.redis.connection.RedisZSetCommands.Range;
+
+/**
+ * @author Christoph Strobl
+ */
+class DefaultBoundZSetOperationsUnitTests {
+
+ DefaultBoundZSetOperations zSetOperations;
+ ConnectionMockingRedisTemplate template;
+
+ @BeforeEach
+ void beforeEach() {
+
+ template = ConnectionMockingRedisTemplate.template();
+ zSetOperations = new DefaultBoundZSetOperations<>("key", template);
+ }
+
+ @Test // GH-1816
+ void delegatesRemoveRangeByLex() {
+
+ Range range = Range.range().gte("alpha").lte("omega");
+ zSetOperations.removeRangeByLex(range);
+
+ template.verify().zRemRangeByLex(eq(template.serializeKey("key")), eq(range));
+ }
+}
diff --git a/src/test/java/org/springframework/data/redis/core/DefaultZSetOperationsUnitTests.java b/src/test/java/org/springframework/data/redis/core/DefaultZSetOperationsUnitTests.java
new file mode 100644
index 0000000000..47ef7564f4
--- /dev/null
+++ b/src/test/java/org/springframework/data/redis/core/DefaultZSetOperationsUnitTests.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2021 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.redis.core;
+
+import static org.mockito.ArgumentMatchers.*;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.data.redis.connection.RedisZSetCommands.Range;
+
+/**
+ * @author Christoph Strobl
+ */
+class DefaultZSetOperationsUnitTests {
+
+ DefaultZSetOperations zSetOperations;
+ ConnectionMockingRedisTemplate template;
+
+ @BeforeEach
+ void beforeEach() {
+
+ template = ConnectionMockingRedisTemplate.template();
+ zSetOperations = new DefaultZSetOperations<>(template);
+ }
+
+ @Test // GH-1816
+ void delegatesRemoveRangeByLex() {
+
+ Range range = Range.range().gte("alpha").lte("omega");
+ zSetOperations.removeRangeByLex("key", range);
+
+ template.verify().zRemRangeByLex(eq(template.serializeKey("key")), eq(range));
+ }
+}
diff --git a/src/test/kotlin/org/springframework/data/redis/core/ReactiveZSetOperationsExtensionsUnitTests.kt b/src/test/kotlin/org/springframework/data/redis/core/ReactiveZSetOperationsExtensionsUnitTests.kt
index 64e138d373..ead3ea627d 100644
--- a/src/test/kotlin/org/springframework/data/redis/core/ReactiveZSetOperationsExtensionsUnitTests.kt
+++ b/src/test/kotlin/org/springframework/data/redis/core/ReactiveZSetOperationsExtensionsUnitTests.kt
@@ -366,6 +366,21 @@ class ReactiveZSetOperationsExtensionsUnitTests {
}
}
+ @Test // GH-1816
+ fun removeRangeByLex() {
+
+ val operations = mockk>()
+ every { operations.removeRangeByLex(any(), any()) } returns Mono.just(1)
+
+ runBlocking {
+ assertThat(operations.removeRangeByLexAndAwait("foo", Range.unbounded())).isEqualTo(1)
+ }
+
+ verify {
+ operations.removeRangeByLex("foo", Range.unbounded())
+ }
+ }
+
@Test // DATAREDIS-937
fun removeRangeByScore() {