Added zRangeStoreByLex and zRangeStoreByScore for ZRANGESTORE command.

Original pull request: #2370.
Closes #2345
This commit is contained in:
Shyngys Sapraliyev
2022-07-17 04:31:08 +06:00
committed by Mark Paluch
parent e61d9e7137
commit 40d078f66d
11 changed files with 405 additions and 0 deletions

View File

@@ -80,6 +80,7 @@ import org.springframework.util.ObjectUtils;
* @author dengliming
* @author ihaohong
* @author Dennis Neufeld
* @author Shyngys Sapraliyev
*/
@SuppressWarnings({ "ConstantConditions", "deprecation" })
public class DefaultStringRedisConnection implements StringRedisConnection, DecoratedRedisConnection {
@@ -2710,6 +2711,37 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco
return convertAndReturn(delegate.zRevRangeByLex(key, range, limit), Converters.identityConverter());
}
@Override
public Long zRangeStoreByLex(byte[] dstKey, byte[] srcKey,
org.springframework.data.domain.Range<byte[]> range,
org.springframework.data.redis.connection.Limit limit) {
return convertAndReturn(delegate.zRangeStoreByLex(dstKey, srcKey, range, limit),
Converters.identityConverter());
}
@Override
public Long zRangeStoreByLex(String dstKey, String srcKey,
org.springframework.data.domain.Range<String> range,
org.springframework.data.redis.connection.Limit limit) {
return convertAndReturn(delegate.zRangeStoreByLex(serialize(dstKey), serialize(srcKey), serialize(range), limit),
Converters.identityConverter());
}
@Override
public Long zRangeStoreByScore(String dstKey, String srcKey, double min, double max,
org.springframework.data.redis.connection.Limit limit) {
return convertAndReturn(delegate.zRangeStoreByScore(serialize(dstKey), serialize(srcKey), min, max, limit),
Converters.identityConverter());
}
@Override
public Long zRangeStoreByScore(byte[] dstKey, byte[] srcKey,
org.springframework.data.domain.Range<Number> range,
org.springframework.data.redis.connection.Limit limit) {
return convertAndReturn(delegate.zRangeStoreByScore(dstKey, srcKey, range, limit),
Converters.identityConverter());
}
@Override
public Set<String> zRevRangeByLex(String key, org.springframework.data.domain.Range<String> range,
org.springframework.data.redis.connection.Limit limit) {

View File

@@ -64,6 +64,7 @@ import org.springframework.lang.Nullable;
* @author dengliming
* @author ihaohong
* @author Dennis Neufeld
* @author Shyngys Sapraliyev
* @since 2.0
*/
@Deprecated
@@ -1835,4 +1836,23 @@ public interface DefaultedRedisConnection extends RedisCommands, RedisCommandsPr
default <T> T evalSha(byte[] scriptSha, ReturnType returnType, int numKeys, byte[]... keysAndArgs) {
return scriptingCommands().evalSha(scriptSha, returnType, numKeys, keysAndArgs);
}
/** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */
@Override
@Deprecated
default Long zRangeStoreByLex(byte[] dstKey, byte[] srcKey,
org.springframework.data.domain.Range<byte[]> range,
org.springframework.data.redis.connection.Limit limit) {
return zSetCommands().zRangeStoreByLex(dstKey, srcKey, range, limit);
}
/** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */
@Override
@Deprecated
default Long zRangeStoreByScore(byte[] dstKey, byte[] srcKey,
org.springframework.data.domain.Range<Number> range,
org.springframework.data.redis.connection.Limit limit) {
return zSetCommands().zRangeStoreByScore(dstKey, srcKey, range, limit);
}
}

View File

@@ -38,6 +38,7 @@ import org.springframework.util.ObjectUtils;
* @author David Liu
* @author Mark Paluch
* @author Andrey Shlykov
* @author Shyngys Sapraliyev
*/
public interface RedisZSetCommands {
@@ -1367,4 +1368,103 @@ public interface RedisZSetCommands {
Set<byte[]> zRevRangeByLex(byte[] key, org.springframework.data.domain.Range<byte[]> range,
org.springframework.data.redis.connection.Limit limit);
/**
* This command is like ZRANGE , but stores the result in the {@literal dstKey} destination key.
*
* @param dstKey must not be {@literal null}.
* @param srcKey must not be {@literal null}.
* @param range must not be {@literal null}.
* @return {@literal null} when used in pipeline / transaction.
* @since 3.0
* @see <a href="https://redis.io/commands/zrangestore">Redis Documentation: ZRANGESTORE</a>
*/
@Nullable
default Long zRangeStoreByLex(byte[] dstKey, byte[] srcKey,
org.springframework.data.domain.Range<byte[]> range) {
return zRangeStoreByLex(dstKey, srcKey, range, org.springframework.data.redis.connection.Limit.unlimited());
}
/**
* This command is like ZRANGE , but stores the result in the {@literal dstKey} destination key.
*
* @param dstKey must not be {@literal null}.
* @param srcKey must not be {@literal null}.
* @param range must not be {@literal null}.
* @param limit must not be {@literal null}.
* @return {@literal null} when used in pipeline / transaction.
* @since 3.0
* @see <a href="https://redis.io/commands/zrangestore">Redis Documentation: ZRANGESTORE</a>
*/
@Nullable
Long zRangeStoreByLex(byte[] dstKey, byte[] srcKey,
org.springframework.data.domain.Range<byte[]> range,
org.springframework.data.redis.connection.Limit limit);
/**
* This command is like ZRANGE, but stores the result in the {@literal dstKey} destination key.
*
* @param dstKey must not be {@literal null}.
* @param srcKey must not be {@literal null}.
* @param min minimal inclusive score
* @param max maximal inclusive score
* @return {@literal null} when used in pipeline / transaction.
* @since 3.0
* @see <a href="https://redis.io/commands/zrangestore">Redis Documentation: ZRANGESTORE</a>
*/
@Nullable
default Long zRangeStoreByScore(byte[] dstKey, byte[] srcKey, double min, double max) {
return zRangeStoreByScore(dstKey, srcKey, org.springframework.data.domain.Range.closed(min, max));
}
/**
* This command is like ZRANGE, but stores the result in the {@literal dstKey} destination key.
*
* @param dstKey must not be {@literal null}.
* @param srcKey must not be {@literal null}.
* @param min minimal inclusive score
* @param max maximal inclusive score
* @param limit must not be {@literal null}.
* @return {@literal null} when used in pipeline / transaction.
* @since 3.0
* @see <a href="https://redis.io/commands/zrangestore">Redis Documentation: ZRANGESTORE</a>
*/
@Nullable
default Long zRangeStoreByScore(byte[] dstKey, byte[] srcKey, double min, double max,
org.springframework.data.redis.connection.Limit limit) {
return zRangeStoreByScore(dstKey, srcKey, org.springframework.data.domain.Range.closed(min, max), limit);
}
/**
* This command is like ZRANGE, but stores the result in the {@literal dstKey} destination key.
*
* @param dstKey must not be {@literal null}.
* @param srcKey must not be {@literal null}.
* @param range must not be {@literal null}.
* @return {@literal null} when used in pipeline / transaction.
* @since 3.0
* @see <a href="https://redis.io/commands/zrangestore">Redis Documentation: ZRANGESTORE</a>
*/
@Nullable
default Long zRangeStoreByScore(byte[] dstKey, byte[] srcKey,
org.springframework.data.domain.Range<Number> range) {
return zRangeStoreByScore(dstKey, srcKey, range,
org.springframework.data.redis.connection.Limit.unlimited());
}
/**
* This command is like ZRANGE, but stores the result in the {@literal dstKey} destination key.
*
* @param dstKey must not be {@literal null}.
* @param srcKey must not be {@literal null}.
* @param range must not be {@literal null}.
* @param limit must not be {@literal null}.
* @return {@literal null} when used in pipeline / transaction.
* @since 3.0
* @see <a href="https://redis.io/commands/zrangestore">Redis Documentation: ZRANGESTORE</a>
*/
@Nullable
Long zRangeStoreByScore(byte[] dstKey, byte[] srcKey,
org.springframework.data.domain.Range<Number> range,
org.springframework.data.redis.connection.Limit limit);
}

View File

@@ -70,6 +70,7 @@ import org.springframework.util.CollectionUtils;
* @author Dengliming
* @author Andrey Shlykov
* @author ihaohong
* @author Shyngys Sapraliyev
*
* @see RedisCallback
* @see RedisSerializer
@@ -1987,6 +1988,71 @@ public interface StringRedisConnection extends RedisConnection {
Set<String> zRevRangeByLex(String key, org.springframework.data.domain.Range<String> range,
org.springframework.data.redis.connection.Limit limit);
/**
* This command is like ZRANGE , but stores the result in the {@literal dstKey} destination key.
*
* @param dstKey must not be {@literal null}.
* @param srcKey must not be {@literal null}.
* @param range must not be {@literal null}.
* @return {@literal null} when used in pipeline / transaction.
* @since 3.0
* @see <a href="https://redis.io/commands/zrangestore">Redis Documentation: ZRANGESTORE</a>
*/
@Nullable
default Long zRangeStoreByLex(String dstKey, String srcKey,
org.springframework.data.domain.Range<String> range) {
return zRangeStoreByLex(dstKey, srcKey, range, org.springframework.data.redis.connection.Limit.unlimited());
}
/**
* This command is like ZRANGE , but stores the result in the {@literal dstKey} destination key.
*
* @param dstKey must not be {@literal null}.
* @param srcKey must not be {@literal null}.
* @param range must not be {@literal null}.
* @param limit must not be {@literal null}.
* @return {@literal null} when used in pipeline / transaction.
* @since 3.0
* @see <a href="https://redis.io/commands/zrangestore">Redis Documentation: ZRANGESTORE</a>
*/
@Nullable
Long zRangeStoreByLex(String dstKey, String srcKey,
org.springframework.data.domain.Range<String> range,
org.springframework.data.redis.connection.Limit limit);
/**
* This command is like ZRANGE, but stores the result in the {@literal dstKey} destination key.
*
* @param dstKey must not be {@literal null}.
* @param srcKey must not be {@literal null}.
* @param min minimal inclusive score
* @param max maximal inclusive score
* @return {@literal null} when used in pipeline / transaction.
* @since 3.0
* @see <a href="https://redis.io/commands/zrangestore">Redis Documentation: ZRANGESTORE</a>
*/
@Nullable
default Long zRangeStoreByScore(String dstKey, String srcKey, double min, double max) {
return zRangeStoreByScore(dstKey, srcKey, min, max, org.springframework.data.redis.connection.Limit.unlimited());
}
/**
* This command is like ZRANGE, but stores the result in the {@literal dstKey} destination key.
*
* @param dstKey must not be {@literal null}.
* @param srcKey must not be {@literal null}.
* @param min minimal inclusive score
* @param max maximal inclusive score
* @param limit must not be {@literal null}.
* @return {@literal null} when used in pipeline / transaction.
* @since 3.0
* @see <a href="https://redis.io/commands/zrangestore">Redis Documentation: ZRANGESTORE</a>
*/
@Nullable
Long zRangeStoreByScore(String dstKey, String srcKey, double min, double max,
org.springframework.data.redis.connection.Limit limit);
// -------------------------------------------------------------------------
// Methods dealing with Redis Hashes
// -------------------------------------------------------------------------

View File

@@ -15,8 +15,10 @@
*/
package org.springframework.data.redis.connection.jedis;
import redis.clients.jedis.Protocol;
import redis.clients.jedis.params.ScanParams;
import redis.clients.jedis.params.ZParams;
import redis.clients.jedis.params.ZRangeParams;
import redis.clients.jedis.resps.ScanResult;
import java.util.ArrayList;
@@ -49,6 +51,7 @@ import org.springframework.util.Assert;
* @author Clement Ong
* @author Andrey Shlykov
* @author Jens Deppe
* @author Shyngys Sapraliyev
* @since 2.0
*/
class JedisClusterZSetCommands implements RedisZSetCommands {
@@ -493,6 +496,52 @@ class JedisClusterZSetCommands implements RedisZSetCommands {
}
}
@Override
public Long zRangeStoreByLex(byte[] dstKey, byte[] srcKey,
org.springframework.data.domain.Range<byte[]> range,
org.springframework.data.redis.connection.Limit limit) {
Assert.notNull(dstKey, "Destination key must not be null");
Assert.notNull(srcKey, "Source key must not be null");
Assert.notNull(range, "Range for ZRANGESTORE BYLEX must not be null");
Assert.notNull(limit, "Limit must not be null. Use Limit.unlimited() instead.");
byte[] min = JedisConverters.boundaryToBytesForZRangeByLex(range.getLowerBound(), JedisConverters.MINUS_BYTES);
byte[] max = JedisConverters.boundaryToBytesForZRangeByLex(range.getUpperBound(), JedisConverters.PLUS_BYTES);
ZRangeParams zRangeParams = new ZRangeParams(Protocol.Keyword.BYLEX, min, max)
.limit(limit.getOffset(), limit.getCount());
try {
return connection.getCluster().zrangestore(dstKey, srcKey, zRangeParams);
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
@Override
public Long zRangeStoreByScore(byte[] dstKey, byte[] srcKey,
org.springframework.data.domain.Range<Number> range,
org.springframework.data.redis.connection.Limit limit) {
Assert.notNull(dstKey, "Destination key must not be null");
Assert.notNull(srcKey, "Source key must not be null");
Assert.notNull(range, "Range for ZRANGESTORE BYSCORE must not be null");
Assert.notNull(limit, "Limit must not be null. Use Limit.unlimited() instead.");
byte[] min = JedisConverters
.boundaryToBytesForZRange(range.getLowerBound(), JedisConverters.NEGATIVE_INFINITY_BYTES);
byte[] max = JedisConverters
.boundaryToBytesForZRange(range.getUpperBound(), JedisConverters.POSITIVE_INFINITY_BYTES);
ZRangeParams zRangeParams = new ZRangeParams(Protocol.Keyword.BYSCORE, min, max)
.limit(limit.getOffset(), limit.getCount());
try {
return connection.getCluster().zrangestore(dstKey, srcKey, zRangeParams);
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
@Override
public Set<Tuple> zRangeWithScores(byte[] key, long start, long end) {

View File

@@ -16,9 +16,11 @@
package org.springframework.data.redis.connection.jedis;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Protocol;
import redis.clients.jedis.commands.PipelineBinaryCommands;
import redis.clients.jedis.params.ScanParams;
import redis.clients.jedis.params.ZParams;
import redis.clients.jedis.params.ZRangeParams;
import redis.clients.jedis.resps.ScanResult;
import java.util.LinkedHashSet;
@@ -44,6 +46,7 @@ import org.springframework.util.Assert;
* @author Clement Ong
* @author Mark Paluch
* @author Andrey Shlykov
* @author Shyngys Sapraliyev
* @since 2.0
*/
class JedisZSetCommands implements RedisZSetCommands {
@@ -676,6 +679,50 @@ class JedisZSetCommands implements RedisZSetCommands {
.get(LinkedHashSet::new);
}
@Override
public Long zRangeStoreByLex(byte[] dstKey, byte[] srcKey,
org.springframework.data.domain.Range<byte[]> range,
org.springframework.data.redis.connection.Limit limit) {
Assert.notNull(dstKey, "Destination key must not be null");
Assert.notNull(srcKey, "Source key must not be null");
Assert.notNull(range, "Range for ZRANGESTORE BYLEX must not be null");
Assert.notNull(limit, "Limit must not be null. Use Limit.unlimited() instead.");
byte[] min = JedisConverters
.boundaryToBytesForZRangeByLex(range.getLowerBound(), JedisConverters.MINUS_BYTES);
byte[] max = JedisConverters
.boundaryToBytesForZRangeByLex(range.getUpperBound(), JedisConverters.PLUS_BYTES);
ZRangeParams zRangeParams = new ZRangeParams(Protocol.Keyword.BYLEX, min, max)
.limit(limit.getOffset(), limit.getCount());
return connection.invoke().just(Jedis::zrangestore, PipelineBinaryCommands::zrangestore,
dstKey, srcKey, zRangeParams);
}
@Override
public Long zRangeStoreByScore(byte[] dstKey, byte[] srcKey,
org.springframework.data.domain.Range<Number> range,
org.springframework.data.redis.connection.Limit limit) {
Assert.notNull(dstKey, "Destination key must not be null");
Assert.notNull(srcKey, "Source key must not be null");
Assert.notNull(range, "Range for ZRANGESTORE BYSCORE must not be null");
Assert.notNull(limit, "Limit must not be null. Use Limit.unlimited() instead.");
byte[] min = JedisConverters
.boundaryToBytesForZRange(range.getLowerBound(), JedisConverters.NEGATIVE_INFINITY_BYTES);
byte[] max = JedisConverters
.boundaryToBytesForZRange(range.getUpperBound(), JedisConverters.POSITIVE_INFINITY_BYTES);
ZRangeParams zRangeParams = new ZRangeParams(Protocol.Keyword.BYSCORE, min, max)
.limit(limit.getOffset(), limit.getCount());
return connection.invoke().just(Jedis::zrangestore, PipelineBinaryCommands::zrangestore,
dstKey, srcKey, zRangeParams);
}
private boolean isPipelined() {
return connection.isPipelined();
}

View File

@@ -46,6 +46,7 @@ import org.springframework.util.Assert;
* @author Christoph Strobl
* @author Mark Paluch
* @author Andrey Shlykov
* @author Shyngys Sapraliyev
* @since 2.0
*/
class LettuceZSetCommands implements RedisZSetCommands {
@@ -643,6 +644,34 @@ class LettuceZSetCommands implements RedisZSetCommands {
LettuceConverters.<byte[]> toRange(range, true), LettuceConverters.toLimit(limit)).toSet();
}
@Override
public Long zRangeStoreByLex(byte[] dstKey, byte[] srcKey,
org.springframework.data.domain.Range<byte[]> range,
org.springframework.data.redis.connection.Limit limit) {
Assert.notNull(dstKey, "Destination key must not be null");
Assert.notNull(srcKey, "Source key must not be null");
Assert.notNull(range, "Range for ZRANGESTORE BYLEX must not be null");
Assert.notNull(limit, "Limit must not be null. Use Limit.unlimited() instead.");
return connection.invoke().just(RedisSortedSetAsyncCommands::zrangestorebylex, dstKey, srcKey,
LettuceConverters.<byte[]>toRange(range, true), LettuceConverters.toLimit(limit));
}
@Override
public Long zRangeStoreByScore(byte[] dstKey, byte[] srcKey,
org.springframework.data.domain.Range<Number> range,
org.springframework.data.redis.connection.Limit limit) {
Assert.notNull(dstKey, "Destination key must not be null");
Assert.notNull(srcKey, "Source key must not be null");
Assert.notNull(range, "Range for ZRANGESTORE BYSCORE must not be null");
Assert.notNull(limit, "Limit must not be null. Use Limit.unlimited() instead.");
return connection.invoke().just(RedisSortedSetAsyncCommands::zrangestorebyscore, dstKey, srcKey,
LettuceConverters.toRange(range), LettuceConverters.toLimit(limit));
}
public RedisClusterCommands<byte[], byte[]> getConnection() {
return connection.getConnection();
}

View File

@@ -41,6 +41,7 @@ import org.springframework.util.Assert;
* @author Mark Paluch
* @author Wongoo (望哥)
* @author Andrey Shlykov
* @author Shyngys Sapraliyev
*/
class DefaultZSetOperations<K, V> extends AbstractOperations<K, V> implements ZSetOperations<K, V> {
@@ -226,6 +227,20 @@ class DefaultZSetOperations<K, V> extends AbstractOperations<K, V> implements ZS
return deserializeValues(rawValues);
}
@Override
public Long rangeStoreByLex(K dstKey, K srcKey, Range<String> range, Limit limit) {
byte[] rawDstKey = rawKey(dstKey);
byte[] rawSrcKey = rawKey(srcKey);
return execute(connection -> connection.zRangeStoreByLex(rawDstKey, rawSrcKey, serialize(range), limit));
}
@Override
public Long rangeStoreByScore(K dstKey, K srcKey, Range<Number> range, Limit limit) {
byte[] rawDstKey = rawKey(dstKey);
byte[] rawSrcKey = rawKey(srcKey);
return execute(connection -> connection.zRangeStoreByScore(rawDstKey, rawSrcKey, range, limit));
}
@Override
public Set<V> rangeByScore(K key, double min, double max) {

View File

@@ -39,6 +39,7 @@ import org.springframework.util.Assert;
* @author Rosty Kerei
* @author Wongoo (望哥)
* @author Andrey Shlykov
* @author Shyngys Sapraliyev
*/
public interface ZSetOperations<K, V> {
@@ -1130,6 +1131,12 @@ public interface ZSetOperations<K, V> {
@Nullable
Set<V> reverseRangeByLex(K key, Range<String> range, Limit limit);
@Nullable
Long rangeStoreByLex(K dstKey, K srcKey, Range<String> range, Limit limit);
@Nullable
Long rangeStoreByScore(K dstKey, K srcKey, Range<Number> range, Limit limit);
/**
* @return never {@literal null}.
*/