Add support for ZREMRANGEBYLEX.

We now support ZREMRANGEBYLEX for Synchronous, Reactive, ZSetOperations and RedisZSet.

Also provide a Kotlin coroutines variant via the extension for ReactiveZSetOperations.

Closes #1816.
Original pull request: #1968.
This commit is contained in:
Christoph Strobl
2021-02-15 09:52:27 +01:00
committed by Mark Paluch
parent 04707ecc27
commit 507a882e93
25 changed files with 516 additions and 0 deletions

View File

@@ -1581,6 +1581,15 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco
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 class DefaultStringRedisConnection implements StringRedisConnection, Deco
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)

View File

@@ -1024,6 +1024,13 @@ public interface DefaultedRedisConnection extends RedisConnection {
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

View File

@@ -1444,6 +1444,82 @@ public interface ReactiveZSetCommands {
*/
Flux<NumericResponse<ZRemRangeByScoreCommand, Long>> zRemRangeByScore(Publisher<ZRemRangeByScoreCommand> commands);
/**
* {@code ZREMRANGEBYLEX} command parameters.
*
* @author Christoph Strobl
* @since 2.5
* @see <a href="https://redis.io/commands/zremrangebylex">Redis Documentation: ZREMRANGEBYLEX</a>
*/
class ZRemRangeByLexCommand extends KeyCommand {
private final Range<String> range;
private ZRemRangeByLexCommand(@Nullable ByteBuffer key, Range<String> 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<String> 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<String> 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 <a href="https://redis.io/commands/zremrangebylex">Redis Documentation: ZREMRANGEBYLEX</a>
*/
default Mono<Long> zRemRangeByLex(ByteBuffer key, Range<String> 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 <a href="https://redis.io/commands/zremrangebylex">Redis Documentation: ZREMRANGEBYLEX</a>
*/
Flux<NumericResponse<ZRemRangeByLexCommand, Long>> zRemRangeByLex(Publisher<ZRemRangeByLexCommand> commands);
/**
* {@code ZUNIONSTORE} command parameters.
*

View File

@@ -814,6 +814,17 @@ public interface RedisZSetCommands {
@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 <a href="https://redis.io/commands/zremrangebylex">Redis Documentation: ZREMRANGEBYLEX</a>
*/
Long zRemRangeByLex(byte[] key, Range range);
/**
* Remove elements with scores between {@code min} and {@code max} from sorted set with {@code key}.
*

View File

@@ -1376,6 +1376,18 @@ public interface StringRedisConnection extends RedisConnection {
*/
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 <a href="https://redis.io/commands/zremrangebylex">Redis Documentation: ZREMRANGEBYLEX</a>
*/
Long zRemRangeByLex(String key, Range range);
/**
* Remove elements with scores between {@code min} and {@code max} from sorted set with {@code key}.
*

View File

@@ -348,6 +348,26 @@ class JedisClusterZSetCommands implements RedisZSetCommands {
}
}
/*
* (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)

View File

@@ -336,6 +336,22 @@ class JedisZSetCommands implements RedisZSetCommands {
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)

View File

@@ -418,6 +418,24 @@ class LettuceReactiveZSetCommands implements ReactiveZSetCommands {
}));
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.ReactiveZSetCommands#zRemRangeByLex(org.reactivestreams.Publisher)
*/
@Override
public Flux<NumericResponse<ZRemRangeByLexCommand, Long>> zRemRangeByLex(Publisher<ZRemRangeByLexCommand> 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.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)

View File

@@ -312,6 +312,20 @@ class LettuceZSetCommands implements RedisZSetCommands {
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.<byte[]> toRange(range, true));
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisZSetCommands#zRemRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range)

View File

@@ -252,6 +252,17 @@ public interface BoundZSetOperations<K, V> extends BoundKeyOperations<K> {
@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 <a href="https://redis.io/commands/zremrangebylex">Redis Documentation: ZREMRANGEBYLEX</a>
*/
@Nullable
Long removeRangeByLex(Range range);
/**
* Remove elements with scores between {@code min} and {@code max} from sorted set with the bound key.
*

View File

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

View File

@@ -383,6 +383,19 @@ class DefaultReactiveZSetOperations<K, V> implements ReactiveZSetOperations<K, V
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<Long> removeRangeByLex(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.zRemRangeByLex(rawKey(key), range));
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.ReactiveZSetOperations#removeRangeByScore(java.lang.Object, org.springframework.data.domain.Range)

View File

@@ -353,6 +353,17 @@ class DefaultZSetOperations<K, V> extends AbstractOperations<K, V> implements ZS
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)

View File

@@ -310,6 +310,17 @@ public interface ReactiveZSetOperations<K, V> {
*/
Mono<Long> removeRange(K key, Range<Long> 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 <a href="https://redis.io/commands/zremrangebyrank">Redis Documentation: ZREMRANGEBYRANK</a>
*/
Mono<Long> removeRangeByLex(K key, Range<String> range);
/**
* Remove elements with scores between {@code min} and {@code max} from sorted set with {@code key}.
*

View File

@@ -344,6 +344,18 @@ public interface ZSetOperations<K, V> {
@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 <a href="https://redis.io/commands/zremrangebylex">Redis Documentation: ZREMRANGEBYLEX</a>
*/
@Nullable
Long removeRangeByLex(K key, Range range);
/**
* Remove elements with scores between {@code min} and {@code max} from sorted set with {@code key}.
*

View File

@@ -226,6 +226,16 @@ public class DefaultRedisZSet<E> extends AbstractRedisCollection<E> implements R
return this;
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.support.collections.RedisZSet#removeRangeByLex(org.springframework.data.redis.connection.RedisZSetCommands.Range)
*/
@Override
public Set<E> removeByLex(Range range) {
boundZSetOps.removeRangeByLex(range);
return this;
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.support.collections.RedisZSet#removeByScore(double, double)

View File

@@ -118,6 +118,15 @@ public interface RedisZSet<E> extends RedisCollection<E>, Set<E> {
RedisZSet<E> 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<E> removeByLex(Range range);
RedisZSet<E> removeByScore(double min, double max);
/**