diff --git a/src/main/asciidoc/new-features.adoc b/src/main/asciidoc/new-features.adoc index 2ae5881f1..e758b109e 100644 --- a/src/main/asciidoc/new-features.adoc +++ b/src/main/asciidoc/new-features.adoc @@ -9,6 +9,7 @@ This section briefly covers items that are new and noteworthy in the latest rele * `RedisCache` now exposes `CacheStatistics`. * ACL authentication support for Redis Standalone, Redis Cluster and Master/Replica. * Password support for Redis Sentinel using Jedis. +* Support for `ZREVRANGEBYLEX` and `ZLEXCOUNT` commands. [[new-in-2.3.0]] == New in Spring Data Redis 2.3 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 2e6cd2bb2..bb2f6431b 100644 --- a/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java @@ -1659,15 +1659,6 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco return convertAndReturn(delegate.zUnionStore(destKey, sets), identityConverter); } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zLexCount(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) - */ - @Override - public Long zLexCount(byte[] key, Range range) { - return delegate.zLexCount(key, range); - } - /* * (non-Javadoc) * @see org.springframework.data.redis.connection.StringRedisConnection#zLexCount(java.lang.String, org.springframework.data.redis.connection.RedisZSetCommands.Range) @@ -2727,6 +2718,15 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco return zCount(serialize(key), min, max); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zLexCount(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) + */ + @Override + public Long zLexCount(byte[] key, Range range) { + return delegate.zLexCount(key, range); + } + /* * (non-Javadoc) * @see org.springframework.data.redis.connection.StringRedisConnection#zIncrBy(java.lang.String, double, java.lang.String) 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 f0ca15ca0..e02019721 100644 --- a/src/main/java/org/springframework/data/redis/connection/DefaultedRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/DefaultedRedisConnection.java @@ -898,6 +898,13 @@ public interface DefaultedRedisConnection extends RedisConnection { return zSetCommands().zCount(key, min, max); } + /** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */ + @Override + @Deprecated + default Long zLexCount(byte[] key, Range range) { + return zSetCommands().zLexCount(key, range); + } + /** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */ @Override @Deprecated @@ -1094,13 +1101,6 @@ public interface DefaultedRedisConnection extends RedisConnection { return zSetCommands().zRangeByScore(key, min, max, offset, count); } - /** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */ - @Override - @Deprecated - default Long zLexCount(byte[] key, Range range) { - return zSetCommands().zLexCount(key, range); - } - // HASH COMMANDS /** @deprecated in favor of {@link RedisConnection#hashCommands()}}. */ 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 98fdd036e..c21999e84 100644 --- a/src/main/java/org/springframework/data/redis/connection/ReactiveZSetCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/ReactiveZSetCommands.java @@ -1121,6 +1121,82 @@ public interface ReactiveZSetCommands { */ Flux> zCount(Publisher commands); + /** + * {@code ZLEXCOUNT} command parameters. + * + * @author Andrey Shlykov + * @since 2.4 + * @see Redis Documentation: ZLEXCOUNT + */ + class ZLexCountCommand extends KeyCommand { + + private final Range range; + + private ZLexCountCommand(@Nullable ByteBuffer key, Range range) { + super(key); + this.range = range; + } + + /** + * Creates a new {@link ZLexCountCommand} given a {@link Range} of {@link String} to retrieve elements count. + * + * @param range must not be {@literal null}. + * @return a new {@link ZLexCountCommand} for {@link Range}. + */ + public static ZLexCountCommand stringsWithin(Range range) { + + Assert.notNull(range, "Range must not be null!"); + + return new ZLexCountCommand(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 ZLexCountCommand} with {@literal key} applied. + */ + public ZLexCountCommand forKey(ByteBuffer key) { + + Assert.notNull(key, "Key must not be null!"); + + return new ZLexCountCommand(key, range); + } + + /** + * @return + */ + public Range getRange() { + return range; + } + } + + /** + * Count number of elements within sorted set with value between {@code Range#min} and {@code Range#max} applying + * lexicographical ordering. + * + * @param key must not be {@literal null}. + * @param range must not be {@literal null}. + * @return + * @since 2.4 + * @see Redis Documentation: ZLEXCOUNT + */ + default Mono zLexCount(ByteBuffer key, Range range) { + return zLexCount(Mono.just(ZLexCountCommand.stringsWithin(range).forKey(key))).next() + .map(NumericResponse::getOutput); + } + + /** + * Count number of elements within sorted set with value between {@code Range#min} and {@code Range#max} applying + * lexicographical ordering. + * + * @param commands must not be {@literal null}. + * @return + * @since 2.4 + * @see Redis Documentation: ZLEXCOUNT + */ + Flux> zLexCount(Publisher commands); + /** * Get the size of sorted set with {@literal key}. * @@ -1937,78 +2013,4 @@ public interface ReactiveZSetCommands { */ Flux>> zRangeByLex(Publisher commands); - /** - * {@code ZLEXCOUNT} command parameters. - * - * @author Andrey Shlykov - * @see Redis Documentation: ZLEXCOUNT - */ - class ZLexCountCommand extends KeyCommand { - - private final Range range; - - private ZLexCountCommand(@Nullable ByteBuffer key, Range range) { - super(key); - this.range = range; - } - - /** - * Creates a new {@link ZLexCountCommand} given a {@link Range} of {@link String} to retrieve elements - * count. - * - * @param range must not be {@literal null}. - * @return a new {@link ZLexCountCommand} for {@link Range}. - */ - public static ZLexCountCommand stringsWithin(Range range) { - - Assert.notNull(range, "Range must not be null!"); - - return new ZLexCountCommand(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 ZLexCountCommand} with {@literal key} applied. - */ - public ZLexCountCommand forKey(ByteBuffer key) { - - Assert.notNull(key, "Key must not be null!"); - - return new ZLexCountCommand(key, range); - } - - /** - * @return - */ - public Range getRange() { - return range; - } - } - - /** - * Count number of elements within sorted set with value within {@link Range}. - * - * @param key must not be {@literal null}. - * @param range must not be {@literal null}. - * @return - * @since 2.4 - * @see Redis Documentation: ZLEXCOUNT - */ - default Mono zLexCount(ByteBuffer key, Range range) { - return zLexCount(Mono.just(ZLexCountCommand.stringsWithin(range).forKey(key))).next() - .map(NumericResponse::getOutput); - } - - /** - * Count number of elements within sorted set with value within {@link Range}. - * - * @param commands must not be {@literal null}. - * @return - * @since 2.4 - * @see Redis Documentation: ZLEXCOUNT - */ - Flux> zLexCount(Publisher commands); - } 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 5aa49421b..c8708bff5 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisZSetCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisZSetCommands.java @@ -768,6 +768,19 @@ public interface RedisZSetCommands { @Nullable Long zCount(byte[] key, Range range); + /** + * Count number of elements within sorted set with value between {@code Range#min} and {@code Range#max} applying + * lexicographical ordering. + * + * @param key must not be {@literal null}. + * @param range must not be {@literal null}. + * @return {@literal null} when used in pipeline / transaction. + * @since 2.4 + * @see Redis Documentation: ZLEXCOUNT + */ + @Nullable + Long zLexCount(byte[] key, Range range); + /** * Get the size of sorted set with {@code key}. * @@ -1059,16 +1072,4 @@ public interface RedisZSetCommands { @Nullable Set zRevRangeByLex(byte[] key, Range range, Limit limit); - /** - * Count number of elements within sorted set with value between {@code Range#min} and {@code Range#max}. - * - * @param key must not be {@literal null}. - * @param range must not be {@literal null}. - * @return {@literal null} when used in pipeline / transaction. - * @since 2.4 - * @see Redis Documentation: ZLEXCOUNT - */ - @Nullable - Long zLexCount(byte[] key, Range range); - } 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 5852d3f47..aa3e6efa4 100644 --- a/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java @@ -1329,6 +1329,20 @@ public interface StringRedisConnection extends RedisConnection { */ Long zCount(String key, double min, double max); + /** + * Count number of elements within sorted set with value between {@code Range#min} and {@code Range#max} applying + * lexicographical ordering. + * + * @param key must not be {@literal null}. + * @param range must not be {@literal null}. + * @return {@literal null} when used in pipeline / transaction. + * @since 2.4 + * @see Redis Documentation: ZLEXCOUNT + * @see RedisZSetCommands#zLexCount(byte[], Range) + */ + @Nullable + Long zLexCount(String key, Range range); + /** * Get the size of sorted set with {@code key}. * @@ -1541,19 +1555,6 @@ public interface StringRedisConnection extends RedisConnection { */ Set zRevRangeByLex(String key, Range range, Limit limit); - /** - * Count number of elements within sorted set with value between {@code Range#min} and {@code Range#max}. - * - * @param key must not be {@literal null}. - * @param range must not be {@literal null}. - * @return {@literal null} when used in pipeline / transaction. - * @since 2.4 - * @see Redis Documentation: ZLEXCOUNT - * @see RedisZSetCommands#zLexCount(byte[], Range) - */ - @Nullable - Long zLexCount(String key, Range range); - // ------------------------------------------------------------------------- // Methods dealing with Redis Hashes // ------------------------------------------------------------------------- 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 51757c8d1..5f28dff6a 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 @@ -257,6 +257,26 @@ class JedisClusterZSetCommands implements RedisZSetCommands { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zLexCount(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) + */ + @Override + public Long zLexCount(byte[] key, Range range) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(range, "Range must not be null!"); + + byte[] min = JedisConverters.boundaryToBytesForZRangeByLex(range.getMin(), JedisConverters.MINUS_BYTES); + byte[] max = JedisConverters.boundaryToBytesForZRangeByLex(range.getMax(), JedisConverters.PLUS_BYTES); + + try { + return connection.getCluster().zlexcount(key, min, max); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisZSetCommands#zRemRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) @@ -795,26 +815,6 @@ class JedisClusterZSetCommands implements RedisZSetCommands { } } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zLexCount(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) - */ - @Override - public Long zLexCount(byte[] key, Range range) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(range, "Range must not be null!"); - - byte[] min = JedisConverters.boundaryToBytesForZRangeByLex(range.getMin(), JedisConverters.MINUS_BYTES); - byte[] max = JedisConverters.boundaryToBytesForZRangeByLex(range.getMax(), JedisConverters.PLUS_BYTES); - - try { - return connection.getCluster().zlexcount(key, min, max); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - private DataAccessException convertJedisAccessException(Exception ex) { return connection.convertJedisAccessException(ex); } 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 3143bc7fd..c786c00a1 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 @@ -491,6 +491,34 @@ class JedisZSetCommands implements RedisZSetCommands { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zLexCount(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) + */ + @Override + public Long zLexCount(byte[] key, Range range) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(range, "Range must not be null!"); + + byte[] min = JedisConverters.boundaryToBytesForZRangeByLex(range.getMin(), JedisConverters.MINUS_BYTES); + byte[] max = JedisConverters.boundaryToBytesForZRangeByLex(range.getMax(), JedisConverters.PLUS_BYTES); + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getRequiredPipeline().zlexcount(key, min, max))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getRequiredTransaction().zlexcount(key, min, max))); + return null; + } + return connection.getJedis().zlexcount(key, min, max); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisZSetCommands#zCard(byte[]) @@ -942,34 +970,6 @@ class JedisZSetCommands implements RedisZSetCommands { } } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zLexCount(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) - */ - @Override - public Long zLexCount(byte[] key, Range range) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(range, "Range must not be null!"); - - byte[] min = JedisConverters.boundaryToBytesForZRangeByLex(range.getMin(), JedisConverters.MINUS_BYTES); - byte[] max = JedisConverters.boundaryToBytesForZRangeByLex(range.getMax(), JedisConverters.PLUS_BYTES); - - try { - if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getRequiredPipeline().zlexcount(key, min, max))); - return null; - } - if (isQueueing()) { - transaction(connection.newJedisResult(connection.getRequiredTransaction().zlexcount(key, min, max))); - return null; - } - return connection.getJedis().zlexcount(key, min, max); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - private boolean isPipelined() { return connection.isPipelined(); } 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 ea493be63..ed2eaa39a 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 @@ -327,6 +327,24 @@ class LettuceReactiveZSetCommands implements ReactiveZSetCommands { })); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.ReactiveZSetCommands#zLexCount(org.reactivestreams.Publisher) + */ + @Override + public Flux> zLexCount(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.zlexcount(command.getKey(), RangeConverter.toRange(command.getRange())); + + return result.map(value -> new NumericResponse<>(command, value)); + })); + } + /* * (non-Javadoc) * @see org.springframework.data.redis.connection.ReactiveZSetCommands#zCard(org.reactivestreams.Publisher) @@ -485,24 +503,6 @@ class LettuceReactiveZSetCommands implements ReactiveZSetCommands { })); } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.ReactiveZSetCommands#zLexCount(org.reactivestreams.Publisher) - */ - @Override - public Flux> zLexCount(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.zlexcount(command.getKey(), RangeConverter.toRange(command.getRange())); - - return result.map(value -> new NumericResponse<>(command, value)); - })); - } - private static ZStoreArgs zStoreArgs(@Nullable Aggregate aggregate, @Nullable List weights) { ZStoreArgs args = new ZStoreArgs(); 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 8355dbe10..d0dfd2dd1 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 @@ -471,6 +471,31 @@ class LettuceZSetCommands implements RedisZSetCommands { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zLexCount(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) + */ + @Override + public Long zLexCount(byte[] key, Range range) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(range, "Range must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().zlexcount(key, LettuceConverters.toRange(range)))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceResult(getAsyncConnection().zlexcount(key, LettuceConverters.toRange(range)))); + return null; + } + return getConnection().zlexcount(key, LettuceConverters.toRange(range, true)); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisZSetCommands#zCard(byte[]) @@ -927,31 +952,6 @@ class LettuceZSetCommands implements RedisZSetCommands { } } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zLexCount(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) - */ - @Override - public Long zLexCount(byte[] key, Range range) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(range, "Range must not be null!"); - - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().zlexcount(key, LettuceConverters.toRange(range)))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().zlexcount(key, LettuceConverters.toRange(range)))); - return null; - } - return getConnection().zlexcount(key, LettuceConverters.toRange(range, true)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - private boolean isPipelined() { return connection.isPipelined(); } 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 c0474ccf8..cf4569ddc 100644 --- a/src/main/java/org/springframework/data/redis/core/BoundZSetOperations.java +++ b/src/main/java/org/springframework/data/redis/core/BoundZSetOperations.java @@ -199,6 +199,18 @@ public interface BoundZSetOperations extends BoundKeyOperations { @Nullable Long count(double min, double max); + /** + * Count number of elements within sorted set with value between {@code Range#min} and {@code Range#max} applying + * lexicographical ordering. + * + * @param range must not be {@literal null}. + * @return {@literal null} when used in pipeline / transaction. + * @since 2.4 + * @see Redis Documentation: ZLEXCOUNT + */ + @Nullable + Long lexCount(Range range); + /** * Returns the number of elements of the sorted set stored with given the bound key. * @@ -415,17 +427,6 @@ public interface BoundZSetOperations extends BoundKeyOperations { @Nullable Set reverseRangeByLex(Range range, Limit limit); - /** - * Count number of elements within sorted set with value between {@code Range#min} and {@code Range#max}. - * - * @param range must not be {@literal null}. - * @return {@literal null} when used in pipeline / transaction. - * @since 2.4 - * @see Redis Documentation: ZLEXCOUNT - */ - @Nullable - Long lexCount(Range range); - /** * @return never {@literal null}. */ 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 b453716ef..3a644d5a1 100644 --- a/src/main/java/org/springframework/data/redis/core/DefaultBoundZSetOperations.java +++ b/src/main/java/org/springframework/data/redis/core/DefaultBoundZSetOperations.java @@ -276,6 +276,15 @@ class DefaultBoundZSetOperations extends DefaultBoundKeyOperations impl return ops.count(getKey(), min, max); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundZSetOperations#lexCount(org.springframework.data.redis.connection.RedisZSetCommands.Range) + */ + @Override + public Long lexCount(Range range) { + return ops.lexCount(getKey(), range); + } + /* * (non-Javadoc) * @see org.springframework.data.redis.core.BoundZSetOperations#size() @@ -330,15 +339,6 @@ class DefaultBoundZSetOperations extends DefaultBoundKeyOperations impl return ops.unionAndStore(getKey(), otherKeys, destKey, aggregate, weights); } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.core.BoundZSetOperations#lexCount(org.springframework.data.redis.connection.RedisZSetCommands.Range) - */ - @Override - public Long lexCount(Range range) { - return ops.lexCount(getKey(), range); - } - /* * (non-Javadoc) * @see org.springframework.data.redis.core.BoundKeyOperations#getType() 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 03d46e9b8..c927b1bf0 100644 --- a/src/main/java/org/springframework/data/redis/core/DefaultReactiveZSetOperations.java +++ b/src/main/java/org/springframework/data/redis/core/DefaultReactiveZSetOperations.java @@ -332,6 +332,19 @@ class DefaultReactiveZSetOperations implements ReactiveZSetOperations connection.zCount(rawKey(key), range)); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.ReactiveZSetOperations#lexCount(java.lang.Object, org.springframework.data.domain.Range) + */ + @Override + public Mono lexCount(K key, Range range) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(range, "Range must not be null!"); + + return createMono(connection -> connection.zLexCount(rawKey(key), range)); + } + /* * (non-Javadoc) * @see org.springframework.data.redis.core.ReactiveZSetOperations#size(java.lang.Object) @@ -549,20 +562,6 @@ class DefaultReactiveZSetOperations implements ReactiveZSetOperations connection.keyCommands().del(rawKey(key))).map(l -> l != 0); } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.core.ReactiveZSetOperations#lexCount(java.lang.Object, org.springframework.data.domain.Range) - */ - @Override - public Mono lexCount(K key, Range range) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(range, "Range must not be null!"); - - - return createMono(connection -> connection.zLexCount(rawKey(key), range)); - } - private Mono createMono(Function> function) { Assert.notNull(function, "Function must not be null!"); 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 31512bc1f..294bfb738 100644 --- a/src/main/java/org/springframework/data/redis/core/DefaultZSetOperations.java +++ b/src/main/java/org/springframework/data/redis/core/DefaultZSetOperations.java @@ -387,6 +387,17 @@ class DefaultZSetOperations extends AbstractOperations implements ZS return execute(connection -> connection.zCount(rawKey, min, max), true); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.ZSetOperations#lexCount(java.lang.Object, org.springframework.data.redis.connection.RedisZSetCommands.Range) + */ + @Override + public Long lexCount(K key, Range range) { + + byte[] rawKey = rawKey(key); + return execute(connection -> connection.zLexCount(rawKey, range), true); + } + /* * (non-Javadoc) * @see org.springframework.data.redis.core.ZSetOperations#size(java.lang.Object) @@ -468,10 +479,4 @@ class DefaultZSetOperations extends AbstractOperations implements ZS return execute(connection -> connection.zRangeByScore(rawKey, min, max, offset, count), true); } - @Override - public Long lexCount(K key, Range range) { - - byte[] rawKey = rawKey(key); - return execute(connection -> connection.zLexCount(rawKey, range), true); - } } 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 19152b86c..025940f04 100644 --- a/src/main/java/org/springframework/data/redis/core/ReactiveZSetOperations.java +++ b/src/main/java/org/springframework/data/redis/core/ReactiveZSetOperations.java @@ -269,6 +269,18 @@ public interface ReactiveZSetOperations { */ Mono count(K key, Range range); + /** + * Count number of elements within sorted set with a value between {@link Range#getLowerBound()} and + * {@link Range#getUpperBound()} applying lexicographical ordering. + * + * @param key must not be {@literal null}. + * @param range must not be {@literal null} + * @return + * @since 2.4 + * @see Redis Documentation: ZLEXCOUNT + */ + Mono lexCount(K key, Range range); + /** * Returns the number of elements of the sorted set stored with given {@code key}. * @@ -463,14 +475,4 @@ public interface ReactiveZSetOperations { */ Mono delete(K key); - /** - * Count number of elements within sorted set with a value between - * {@link Range#getLowerBound()} and {@link Range#getUpperBound()}. - * - * @param key must not be {@literal null}. - * @param range must not be {@literal null} - * @return - * @see Redis Documentation: ZLEXCOUNT - */ - Mono lexCount(K key, Range range); } 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 0cda46d92..5f1768804 100644 --- a/src/main/java/org/springframework/data/redis/core/ZSetOperations.java +++ b/src/main/java/org/springframework/data/redis/core/ZSetOperations.java @@ -286,6 +286,19 @@ public interface ZSetOperations { @Nullable Long count(K key, double min, double max); + /** + * Count number of elements within sorted set with value between {@code Range#min} and {@code Range#max} applying + * lexicographical ordering. + * + * @param key must not be {@literal null}. + * @param range must not be {@literal null}. + * @return {@literal null} when used in pipeline / transaction. + * @since 2.4 + * @see Redis Documentation: ZLEXCOUNT + */ + @Nullable + Long lexCount(K key, Range range); + /** * Returns the number of elements of the sorted set stored with given {@code key}. * @@ -525,18 +538,6 @@ public interface ZSetOperations { @Nullable Set reverseRangeByLex(K key, Range range, Limit limit); - /** - * Count number of elements within sorted set with value between {@code Range#min} and {@code Range#max}. - * - * @param key must not be {@literal null}. - * @param range must not be {@literal null}. - * @return {@literal null} when used in pipeline / transaction. - * @since 2.4 - * @see Redis Documentation: ZLEXCOUNT - */ - @Nullable - Long lexCount(K key, Range range); - /** * @return never {@literal null}. */ 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 da873af6a..d91fee3c1 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 @@ -135,6 +135,17 @@ public interface RedisZSet extends RedisCollection, Set { */ boolean add(E e); + /** + * Count number of elements within sorted set with value between {@code Range#min} and {@code Range#max} applying + * lexicographical ordering. + * + * @param range must not be {@literal null}. + * @return + * @since 2.4 + * @see Redis Documentation: ZLEXCOUNT + */ + Long lexCount(Range range); + /** * Returns the score of the given element. Returns null if the element is not contained by the set. * @@ -168,16 +179,6 @@ public interface RedisZSet extends RedisCollection, Set { */ Double getDefaultScore(); - /** - * Count number of elements within sorted set with value between {@code Range#min} and {@code Range#max}. - * - * @param range must not be {@literal null}. - * @return - * @since 2.4 - * @see Redis Documentation: ZLEXCOUNT - */ - Long lexCount(Range range); - /** * Returns the first (lowest) element currently in this sorted set. * 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 6cc1d521b..2344d131e 100644 --- a/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java @@ -1791,6 +1791,34 @@ public abstract class AbstractConnectionIntegrationTests { verifyResults(Arrays.asList(new Object[] { true, true, true, 2l })); } + @Test // DATAREDIS-729 + @IfProfileValue(name = "redisVersion", value = "2.9.0+") + @WithRedisDriver({ RedisDriver.JEDIS, RedisDriver.LETTUCE }) + public void zLexCountTest() { + + actual.add(connection.zAdd("myzset", 0, "a")); + actual.add(connection.zAdd("myzset", 0, "b")); + actual.add(connection.zAdd("myzset", 0, "c")); + actual.add(connection.zAdd("myzset", 0, "d")); + actual.add(connection.zAdd("myzset", 0, "e")); + actual.add(connection.zAdd("myzset", 0, "f")); + actual.add(connection.zAdd("myzset", 0, "g")); + + actual.add(connection.zLexCount("myzset", Range.unbounded())); + actual.add(connection.zLexCount("myzset", Range.range().lt("c"))); + actual.add(connection.zLexCount("myzset", Range.range().lte("c"))); + actual.add(connection.zLexCount("myzset", Range.range().gte("aaa").lt("g"))); + actual.add(connection.zLexCount("myzset", Range.range().gte("e"))); + + List results = getResults(); + + assertThat((Long) results.get(7)).isEqualTo(7); + assertThat((Long) results.get(8)).isEqualTo(2); + assertThat((Long) results.get(9)).isEqualTo(3); + assertThat((Long) results.get(10)).isEqualTo(5); + assertThat((Long) results.get(11)).isEqualTo(3); + } + @Test public void testZIncrBy() { actual.add(connection.zAdd("myset", 2, "Bob")); @@ -2454,43 +2482,6 @@ public abstract class AbstractConnectionIntegrationTests { assertThat((Set) results.get(13)).contains("c", "b").doesNotContain("a", "d", "e", "f", "g"); } - @Test // DATAREDIS-729 - @IfProfileValue(name = "redisVersion", value = "2.9.0+") - @WithRedisDriver({ RedisDriver.JEDIS, RedisDriver.LETTUCE }) - public void zLexCountTest() { - - actual.add(connection.zAdd("myzset", 0, "a")); - actual.add(connection.zAdd("myzset", 0, "b")); - actual.add(connection.zAdd("myzset", 0, "c")); - actual.add(connection.zAdd("myzset", 0, "d")); - actual.add(connection.zAdd("myzset", 0, "e")); - actual.add(connection.zAdd("myzset", 0, "f")); - actual.add(connection.zAdd("myzset", 0, "g")); - - actual.add(connection.zLexCount("myzset", Range.unbounded())); - actual.add(connection.zLexCount("myzset", Range.range().lt("c"))); - actual.add(connection.zLexCount("myzset", Range.range().lte("c"))); - actual.add(connection.zLexCount("myzset", Range.range().gte("aaa").lt("g"))); - actual.add(connection.zLexCount("myzset", Range.range().gte("e"))); - - List results = getResults(); - - Long count = (Long) results.get(7); - assertThat(count).isEqualTo(7); - - count = (Long) results.get(8); - assertThat(count).isEqualTo(2); - - count = (Long) results.get(9); - assertThat(count).isEqualTo(3); - - count = (Long) results.get(10); - assertThat(count).isEqualTo(5); - - count = (Long) results.get(11); - assertThat(count).isEqualTo(3); - } - @Test(expected = IllegalArgumentException.class) // DATAREDIS-316, DATAREDIS-692 @WithRedisDriver({ RedisDriver.JEDIS, RedisDriver.LETTUCE }) public void setWithExpirationAndNullOpionShouldThrowException() { diff --git a/src/test/java/org/springframework/data/redis/core/DefaultReactiveZSetOperationsIntegrationTests.java b/src/test/java/org/springframework/data/redis/core/DefaultReactiveZSetOperationsIntegrationTests.java index 2c290b04a..025a1f4e4 100644 --- a/src/test/java/org/springframework/data/redis/core/DefaultReactiveZSetOperationsIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/core/DefaultReactiveZSetOperationsIntegrationTests.java @@ -430,6 +430,26 @@ public class DefaultReactiveZSetOperationsIntegrationTests { zSetOperations.count(key, Range.closed(0d, 10d)).as(StepVerifier::create).expectNext(1L).verifyComplete(); } + @Test // DATAREDIS-729 + public void lexCount() { + + assumeTrue(serializer instanceof StringRedisSerializer); + + K key = keyFactory.instance(); + + zSetOperations.add(key, (V) "a", 0).as(StepVerifier::create).expectNext(true).verifyComplete(); + zSetOperations.add(key, (V) "b", 0).as(StepVerifier::create).expectNext(true).verifyComplete(); + zSetOperations.add(key, (V) "c", 0).as(StepVerifier::create).expectNext(true).verifyComplete(); + zSetOperations.add(key, (V) "d", 0).as(StepVerifier::create).expectNext(true).verifyComplete(); + zSetOperations.add(key, (V) "e", 0).as(StepVerifier::create).expectNext(true).verifyComplete(); + zSetOperations.add(key, (V) "f", 0).as(StepVerifier::create).expectNext(true).verifyComplete(); + zSetOperations.add(key, (V) "g", 0).as(StepVerifier::create).expectNext(true).verifyComplete(); + + zSetOperations.lexCount(key, Range.unbounded()).as(StepVerifier::create).expectNext(7L).verifyComplete(); + zSetOperations.lexCount(key, Range.leftOpen("b", "f")).as(StepVerifier::create).expectNext(4L).verifyComplete(); + zSetOperations.lexCount(key, Range.rightOpen("b", "f")).as(StepVerifier::create).expectNext(4L).verifyComplete(); + } + @Test // DATAREDIS-602 public void size() { @@ -695,31 +715,4 @@ public class DefaultReactiveZSetOperationsIntegrationTests { .verifyComplete(); } - @Test // DATAREDIS-729 - public void lexCount() { - - assumeTrue(serializer instanceof StringRedisSerializer); - - K key = keyFactory.instance(); - - zSetOperations.add(key, (V) "a", 0).as(StepVerifier::create).expectNext(true).verifyComplete(); - zSetOperations.add(key, (V) "b", 0).as(StepVerifier::create).expectNext(true).verifyComplete(); - zSetOperations.add(key, (V) "c", 0).as(StepVerifier::create).expectNext(true).verifyComplete(); - zSetOperations.add(key, (V) "d", 0).as(StepVerifier::create).expectNext(true).verifyComplete(); - zSetOperations.add(key, (V) "e", 0).as(StepVerifier::create).expectNext(true).verifyComplete(); - zSetOperations.add(key, (V) "f", 0).as(StepVerifier::create).expectNext(true).verifyComplete(); - zSetOperations.add(key, (V) "g", 0).as(StepVerifier::create).expectNext(true).verifyComplete(); - - zSetOperations.lexCount(key, Range.unbounded()).as(StepVerifier::create) - .expectNext(7L) - .verifyComplete(); - - zSetOperations.lexCount(key, Range.leftOpen("b", "f")).as(StepVerifier::create) - .expectNext(4L) - .verifyComplete(); - - zSetOperations.lexCount(key, Range.rightOpen("b", "f")).as(StepVerifier::create) - .expectNext(4L) - .verifyComplete(); - } } diff --git a/src/test/java/org/springframework/data/redis/core/DefaultZSetOperationsTests.java b/src/test/java/org/springframework/data/redis/core/DefaultZSetOperationsTests.java index a30ebd1a3..89892de99 100644 --- a/src/test/java/org/springframework/data/redis/core/DefaultZSetOperationsTests.java +++ b/src/test/java/org/springframework/data/redis/core/DefaultZSetOperationsTests.java @@ -117,6 +117,42 @@ public class DefaultZSetOperationsTests { assertThat(zSetOps.count(key1, 2.7, 5.7)).isEqualTo(Long.valueOf(1)); } + @Test // DATAREDIS-729 + public void testLexCountUnbounded() { + + assumeThat(valueFactory).isOfAnyClassIn(DoubleObjectFactory.class, DoubleAsStringObjectFactory.class, + LongAsStringObjectFactory.class, LongObjectFactory.class); + + K key = keyFactory.instance(); + V value1 = valueFactory.instance(); + V value2 = valueFactory.instance(); + V value3 = valueFactory.instance(); + + zSetOps.add(key, value1, 0); + zSetOps.add(key, value2, 0); + zSetOps.add(key, value3, 0); + + assertThat(zSetOps.lexCount(key, RedisZSetCommands.Range.unbounded())).isEqualTo(3); + } + + @Test // DATAREDIS-729 + public void testLexCountBounded() { + + assumeThat(valueFactory).isOfAnyClassIn(DoubleObjectFactory.class, DoubleAsStringObjectFactory.class, + LongAsStringObjectFactory.class, LongObjectFactory.class); + + K key = keyFactory.instance(); + V value1 = valueFactory.instance(); + V value2 = valueFactory.instance(); + V value3 = valueFactory.instance(); + + zSetOps.add(key, value1, 0); + zSetOps.add(key, value2, 0); + zSetOps.add(key, value3, 0); + + assertThat(zSetOps.lexCount(key, RedisZSetCommands.Range.range().gt(value1))).isEqualTo(2); + } + @Test public void testIncrementScore() { @@ -461,39 +497,4 @@ public class DefaultZSetOperationsTests { assertThat(zSetOps.score(key1, value1)).isCloseTo(6.0, offset(0.1)); } - @Test // DATAREDIS-729 - public void testLexCountUnbounded() { - - assumeThat(valueFactory).isOfAnyClassIn(DoubleObjectFactory.class, DoubleAsStringObjectFactory.class, - LongAsStringObjectFactory.class, LongObjectFactory.class); - - K key = keyFactory.instance(); - V value1 = valueFactory.instance(); - V value2 = valueFactory.instance(); - V value3 = valueFactory.instance(); - - zSetOps.add(key, value1, 0); - zSetOps.add(key, value2, 0); - zSetOps.add(key, value3, 0); - - assertThat(zSetOps.lexCount(key, RedisZSetCommands.Range.unbounded())).isEqualTo(3); - } - - @Test // DATAREDIS-729 - public void testLexCountBounded() { - - assumeThat(valueFactory).isOfAnyClassIn(DoubleObjectFactory.class, DoubleAsStringObjectFactory.class, - LongAsStringObjectFactory.class, LongObjectFactory.class); - - K key = keyFactory.instance(); - V value1 = valueFactory.instance(); - V value2 = valueFactory.instance(); - V value3 = valueFactory.instance(); - - zSetOps.add(key, value1, 0); - zSetOps.add(key, value2, 0); - zSetOps.add(key, value3, 0); - - assertThat(zSetOps.lexCount(key, RedisZSetCommands.Range.range().gt(value1))).isEqualTo(2); - } } diff --git a/src/test/java/org/springframework/data/redis/support/collections/AbstractRedisZSetTest.java b/src/test/java/org/springframework/data/redis/support/collections/AbstractRedisZSetTest.java index 88facd89b..44927ca90 100644 --- a/src/test/java/org/springframework/data/redis/support/collections/AbstractRedisZSetTest.java +++ b/src/test/java/org/springframework/data/redis/support/collections/AbstractRedisZSetTest.java @@ -190,6 +190,40 @@ public abstract class AbstractRedisZSetTest extends AbstractRedisCollectionTe assertThat(zSet.rank(getT())).isNull(); } + @Test // DATAREDIS-729 + public void testLexCountUnbounded() { + + assumeThat(factory).isOfAnyClassIn(DoubleObjectFactory.class, DoubleAsStringObjectFactory.class, + LongAsStringObjectFactory.class, LongObjectFactory.class); + + T t1 = getT(); + T t2 = getT(); + T t3 = getT(); + + zSet.add(t1, 1); + zSet.add(t2, 1); + zSet.add(t3, 1); + + assertThat(zSet.lexCount(RedisZSetCommands.Range.unbounded())).isEqualTo(Long.valueOf(3)); + } + + @Test // DATAREDIS-729 + public void testLexCountBounded() { + + assumeThat(factory).isOfAnyClassIn(DoubleObjectFactory.class, DoubleAsStringObjectFactory.class, + LongAsStringObjectFactory.class, LongObjectFactory.class); + + T t1 = getT(); + T t2 = getT(); + T t3 = getT(); + + zSet.add(t1, 1); + zSet.add(t2, 1); + zSet.add(t3, 1); + + assertThat(zSet.lexCount(RedisZSetCommands.Range.range().gt(t1))).isEqualTo(Long.valueOf(2)); + } + @Test public void testScore() { T t1 = getT(); @@ -392,7 +426,7 @@ public abstract class AbstractRedisZSetTest extends AbstractRedisCollectionTe @Test // DATAREDIS-407 public void testRangeByLexBoundedWithLimit() { - assumeThat(factory).isOfAnyClassIn(DoubleObjectFactory.class, DoubleAsStringObjectFactory.class, + assumeThat(factory).isOfAnyClassIn(DoubleObjectFactory.class, LongAsStringObjectFactory.class, LongObjectFactory.class); T t1 = getT(); @@ -661,38 +695,4 @@ public abstract class AbstractRedisZSetTest extends AbstractRedisCollectionTe cursor.close(); } - - @Test // DATAREDIS-729 - public void testLexCountUnbounded() { - - assumeThat(factory).isOfAnyClassIn(DoubleObjectFactory.class, DoubleAsStringObjectFactory.class, - LongAsStringObjectFactory.class, LongObjectFactory.class); - - T t1 = getT(); - T t2 = getT(); - T t3 = getT(); - - zSet.add(t1, 1); - zSet.add(t2, 1); - zSet.add(t3, 1); - - assertThat(zSet.lexCount(RedisZSetCommands.Range.unbounded())).isEqualTo(Long.valueOf(3)); - } - - @Test // DATAREDIS-729 - public void testLexCountBounded() { - - assumeThat(factory).isOfAnyClassIn(DoubleObjectFactory.class, DoubleAsStringObjectFactory.class, - LongAsStringObjectFactory.class, LongObjectFactory.class); - - T t1 = getT(); - T t2 = getT(); - T t3 = getT(); - - zSet.add(t1, 1); - zSet.add(t2, 1); - zSet.add(t3, 1); - - assertThat(zSet.lexCount(RedisZSetCommands.Range.range().gt(t1))).isEqualTo(Long.valueOf(2)); - } }