DATAREDIS-729 - Polishing.

Reorder methods so lexCount(…) comes after count(…). Tweak Javadoc wording. Simplify tests.

Original pull request: #569.
This commit is contained in:
Mark Paluch
2020-10-14 09:46:58 +02:00
parent bd1332ec5c
commit 1964ed15c6
21 changed files with 411 additions and 412 deletions

View File

@@ -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

View File

@@ -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)

View File

@@ -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()}}. */

View File

@@ -1121,6 +1121,82 @@ public interface ReactiveZSetCommands {
*/
Flux<NumericResponse<ZCountCommand, Long>> zCount(Publisher<ZCountCommand> commands);
/**
* {@code ZLEXCOUNT} command parameters.
*
* @author Andrey Shlykov
* @since 2.4
* @see <a href="https://redis.io/commands/zlexcount">Redis Documentation: ZLEXCOUNT</a>
*/
class ZLexCountCommand extends KeyCommand {
private final Range<String> range;
private ZLexCountCommand(@Nullable ByteBuffer key, Range<String> 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<String> 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<String> 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 <a href="https://redis.io/commands/zlexcount">Redis Documentation: ZLEXCOUNT</a>
*/
default Mono<Long> zLexCount(ByteBuffer key, Range<String> 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 <a href="https://redis.io/commands/zlexcount">Redis Documentation: ZLEXCOUNT</a>
*/
Flux<NumericResponse<ZLexCountCommand, Long>> zLexCount(Publisher<ZLexCountCommand> commands);
/**
* Get the size of sorted set with {@literal key}.
*
@@ -1937,78 +2013,4 @@ public interface ReactiveZSetCommands {
*/
Flux<CommandResponse<ZRangeByLexCommand, Flux<ByteBuffer>>> zRangeByLex(Publisher<ZRangeByLexCommand> commands);
/**
* {@code ZLEXCOUNT} command parameters.
*
* @author Andrey Shlykov
* @see <a href="https://redis.io/commands/zlexcount">Redis Documentation: ZLEXCOUNT</a>
*/
class ZLexCountCommand extends KeyCommand {
private final Range<String> range;
private ZLexCountCommand(@Nullable ByteBuffer key, Range<String> 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<String> 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<String> 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 <a href="https://redis.io/commands/zlexcount">Redis Documentation: ZLEXCOUNT</a>
*/
default Mono<Long> zLexCount(ByteBuffer key, Range<String> 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 <a href="https://redis.io/commands/zlexcount">Redis Documentation: ZLEXCOUNT</a>
*/
Flux<NumericResponse<ZLexCountCommand, Long>> zLexCount(Publisher<ZLexCountCommand> commands);
}

View File

@@ -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 <a href="https://redis.io/commands/zlexcount">Redis Documentation: ZLEXCOUNT</a>
*/
@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<byte[]> 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 <a href="https://redis.io/commands/zlexcount">Redis Documentation: ZLEXCOUNT</a>
*/
@Nullable
Long zLexCount(byte[] key, Range range);
}

View File

@@ -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 <a href="https://redis.io/commands/zlexcount">Redis Documentation: ZLEXCOUNT</a>
* @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<String> 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 <a href="https://redis.io/commands/zlexcount">Redis Documentation: ZLEXCOUNT</a>
* @see RedisZSetCommands#zLexCount(byte[], Range)
*/
@Nullable
Long zLexCount(String key, Range range);
// -------------------------------------------------------------------------
// Methods dealing with Redis Hashes
// -------------------------------------------------------------------------

View File

@@ -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);
}

View File

@@ -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();
}

View File

@@ -327,6 +327,24 @@ class LettuceReactiveZSetCommands implements ReactiveZSetCommands {
}));
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.ReactiveZSetCommands#zLexCount(org.reactivestreams.Publisher)
*/
@Override
public Flux<NumericResponse<ZLexCountCommand, Long>> zLexCount(Publisher<ZLexCountCommand> 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<Long> 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<NumericResponse<ZLexCountCommand, Long>> zLexCount(Publisher<ZLexCountCommand> 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<Long> 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<Double> weights) {
ZStoreArgs args = new ZStoreArgs();

View File

@@ -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();
}

View File

@@ -199,6 +199,18 @@ public interface BoundZSetOperations<K, V> extends BoundKeyOperations<K> {
@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 <a href="https://redis.io/commands/zlexcount">Redis Documentation: ZLEXCOUNT</a>
*/
@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<K, V> extends BoundKeyOperations<K> {
@Nullable
Set<V> 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 <a href="https://redis.io/commands/zlexcount">Redis Documentation: ZLEXCOUNT</a>
*/
@Nullable
Long lexCount(Range range);
/**
* @return never {@literal null}.
*/

View File

@@ -276,6 +276,15 @@ class DefaultBoundZSetOperations<K, V> extends DefaultBoundKeyOperations<K> 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<K, V> extends DefaultBoundKeyOperations<K> 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()

View File

@@ -332,6 +332,19 @@ class DefaultReactiveZSetOperations<K, V> implements ReactiveZSetOperations<K, V
return createMono(connection -> 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<Long> lexCount(K key, Range<String> 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<K, V> implements ReactiveZSetOperations<K, V
return template.createMono(connection -> 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<Long> lexCount(K key, Range<String> 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 <T> Mono<T> createMono(Function<ReactiveZSetCommands, Publisher<T>> function) {
Assert.notNull(function, "Function must not be null!");

View File

@@ -387,6 +387,17 @@ class DefaultZSetOperations<K, V> extends AbstractOperations<K, V> 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<K, V> extends AbstractOperations<K, V> 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);
}
}

View File

@@ -269,6 +269,18 @@ public interface ReactiveZSetOperations<K, V> {
*/
Mono<Long> count(K key, Range<Double> 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 <a href="https://redis.io/commands/ZLEXCOUNT">Redis Documentation: ZLEXCOUNT</a>
*/
Mono<Long> lexCount(K key, Range<String> range);
/**
* Returns the number of elements of the sorted set stored with given {@code key}.
*
@@ -463,14 +475,4 @@ public interface ReactiveZSetOperations<K, V> {
*/
Mono<Boolean> 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 <a href="https://redis.io/commands/ZLEXCOUNT">Redis Documentation: ZLEXCOUNT</a>
*/
Mono<Long> lexCount(K key, Range<String> range);
}

View File

@@ -286,6 +286,19 @@ public interface ZSetOperations<K, V> {
@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 <a href="https://redis.io/commands/zlexcount">Redis Documentation: ZLEXCOUNT</a>
*/
@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<K, V> {
@Nullable
Set<V> 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 <a href="https://redis.io/commands/zlexcount">Redis Documentation: ZLEXCOUNT</a>
*/
@Nullable
Long lexCount(K key, Range range);
/**
* @return never {@literal null}.
*/

View File

@@ -135,6 +135,17 @@ public interface RedisZSet<E> extends RedisCollection<E>, Set<E> {
*/
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 <a href="https://redis.io/commands/zlexcount">Redis Documentation: ZLEXCOUNT</a>
*/
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<E> extends RedisCollection<E>, Set<E> {
*/
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 <a href="https://redis.io/commands/zlexcount">Redis Documentation: ZLEXCOUNT</a>
*/
Long lexCount(Range range);
/**
* Returns the first (lowest) element currently in this sorted set.
*

View File

@@ -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<Object> 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<String>) 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<Object> 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() {

View File

@@ -430,6 +430,26 @@ public class DefaultReactiveZSetOperationsIntegrationTests<K, V> {
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<K, V> {
.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();
}
}

View File

@@ -117,6 +117,42 @@ public class DefaultZSetOperationsTests<K, V> {
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<K, V> {
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);
}
}

View File

@@ -190,6 +190,40 @@ public abstract class AbstractRedisZSetTest<T> 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<T> 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<T> 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));
}
}