Add support for ZRANDMEMBER.

Closes: #2049
Original Pull Request: #2104
This commit is contained in:
Mark Paluch
2021-06-28 14:12:03 +02:00
committed by Christoph Strobl
parent 0b8fbae2c3
commit a523b821c5
23 changed files with 1182 additions and 11 deletions

View File

@@ -85,6 +85,7 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco
private final TupleConverter tupleConverter = new TupleConverter();
private SetConverter<Tuple, StringTuple> tupleToStringTuple = new SetConverter<>(tupleConverter);
private SetConverter<StringTuple, Tuple> stringTupleToTuple = new SetConverter<>(new StringTupleConverter());
private ListConverter<Tuple, StringTuple> tupleListToStringTuple = new ListConverter<>(new TupleConverter());
private ListConverter<byte[], String> byteListToStringList = new ListConverter<>(bytesToString);
private MapConverter<byte[], String> byteMapToStringMap = new MapConverter<>(bytesToString);
private MapConverter<String, byte[]> stringMapToByteMap = new MapConverter<>(stringToBytes);
@@ -3296,6 +3297,78 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco
return zInterStore(serialize(destKey), serializeMulti(sets));
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisZSetCommands#zRandMember(byte[])
*/
@Override
public byte[] zRandMember(byte[] key) {
return delegate.zRandMember(key);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisZSetCommands#zRandMember(byte[], long)
*/
@Override
public List<byte[]> zRandMember(byte[] key, long count) {
return delegate.zRandMember(key, count);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisZSetCommands#zRandMemberWithScore(byte[])
*/
@Override
public Tuple zRandMemberWithScore(byte[] key) {
return delegate.zRandMemberWithScore(key);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisZSetCommands#zRandMemberWithScore(byte[], long)
*/
@Override
public List<Tuple> zRandMemberWithScore(byte[] key, long count) {
return delegate.zRandMemberWithScore(key, count);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.StringRedisConnection#zRandMember(java.lang.String)
*/
@Override
public String zRandMember(String key) {
return convertAndReturn(delegate.zRandMember(serialize(key)), bytesToString);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.StringRedisConnection#zRandMember(java.lang.String, long)
*/
@Override
public List<String> zRandMember(String key, long count) {
return convertAndReturn(delegate.zRandMember(serialize(key), count), byteListToStringList);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.StringRedisConnection#zRandMemberWithScore(java.lang.String)
*/
@Override
public StringTuple zRandMemberWithScore(String key) {
return convertAndReturn(delegate.zRandMemberWithScore(serialize(key)), new TupleConverter());
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.StringRedisConnection#zRandMemberWithScores(java.lang.String, long)
*/
@Override
public List<StringTuple> zRandMemberWithScores(String key, long count) {
return convertAndReturn(delegate.zRandMemberWithScore(serialize(key), count), tupleListToStringTuple);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.StringRedisConnection#zRange(java.lang.String, long, long)

View File

@@ -1068,6 +1068,34 @@ public interface DefaultedRedisConnection extends RedisConnection {
return zSetCommands().zInterStore(destKey, sets);
}
/** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */
@Override
@Deprecated
default byte[] zRandMember(byte[] key) {
return zSetCommands().zRandMember(key);
}
/** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */
@Override
@Deprecated
default List<byte[]> zRandMember(byte[] key, long count) {
return zSetCommands().zRandMember(key, count);
}
/** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */
@Override
@Deprecated
default Tuple zRandMemberWithScore(byte[] key) {
return zSetCommands().zRandMemberWithScore(key);
}
/** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */
@Override
@Deprecated
default List<Tuple> zRandMemberWithScore(byte[] key, long count) {
return zSetCommands().zRandMemberWithScore(key, count);
}
/** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */
@Override
@Deprecated

View File

@@ -477,6 +477,142 @@ public interface ReactiveZSetCommands {
*/
Flux<NumericResponse<ZIncrByCommand, Double>> zIncrBy(Publisher<ZIncrByCommand> commands);
/**
* {@code ZRANDMEMBER} command parameters.
*
* @author Mark Paluch
* @since 2.6
* @see <a href="https://redis.io/commands/srandmember">Redis Documentation: ZRANDMEMBER</a>
*/
class ZRandMemberCommand extends KeyCommand {
private final long count;
private ZRandMemberCommand(@Nullable ByteBuffer key, long count) {
super(key);
this.count = count;
}
/**
* Creates a new {@link ZRandMemberCommand} given the number of values to retrieve.
*
* @param nrValuesToRetrieve
* @return a new {@link ZRandMemberCommand} for a number of values to retrieve.
*/
public static ZRandMemberCommand valueCount(long nrValuesToRetrieve) {
return new ZRandMemberCommand(null, nrValuesToRetrieve);
}
/**
* Creates a new {@link ZRandMemberCommand} to retrieve one random member.
*
* @return a new {@link ZRandMemberCommand} to retrieve one random member.
*/
public static ZRandMemberCommand singleValue() {
return new ZRandMemberCommand(null, 1);
}
/**
* 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 ZRandMemberCommand} with {@literal key} applied.
*/
public ZRandMemberCommand from(ByteBuffer key) {
Assert.notNull(key, "Key must not be null!");
return new ZRandMemberCommand(key, count);
}
/**
* @return
*/
public long getCount() {
return count;
}
}
/**
* Get random element from sorted set at {@code key}.
*
* @param key must not be {@literal null}.
* @return
* @since 2.6
* @see <a href="https://redis.io/commands/zrandmember">Redis Documentation: ZRANDMEMBER</a>
*/
default Mono<ByteBuffer> zRandMember(ByteBuffer key) {
return zRandMember(Mono.just(ZRandMemberCommand.singleValue().from(key))).flatMap(CommandResponse::getOutput)
.next();
}
/**
* Get {@code count} random elements from sorted set at {@code key}.
*
* @param key must not be {@literal null}.
* @param count if the provided {@code count} argument is positive, return a list of distinct fields, capped either at
* {@code count} or the set size. If {@code count} is negative, the behavior changes and the command is
* allowed to return the same value multiple times. In this case, the number of returned values is the
* absolute value of the specified count.
* @return
* @since 2.6
* @see <a href="https://redis.io/commands/zrandmember">Redis Documentation: ZRANDMEMBER</a>
*/
default Flux<ByteBuffer> zRandMember(ByteBuffer key, long count) {
return zRandMember(Mono.just(ZRandMemberCommand.valueCount(count).from(key))).flatMap(CommandResponse::getOutput);
}
/**
* Get random elements from sorted set at {@code key}.
*
* @param commands must not be {@literal null}.
* @return
* @since 2.6
* @see <a href="https://redis.io/commands/zrandmember">Redis Documentation: ZRANDMEMBER</a>
*/
Flux<CommandResponse<ZRandMemberCommand, Flux<ByteBuffer>>> zRandMember(Publisher<ZRandMemberCommand> commands);
/**
* Get random element from sorted set at {@code key}.
*
* @param key must not be {@literal null}.
* @return
* @since 2.6
* @see <a href="https://redis.io/commands/zrandmember">Redis Documentation: ZRANDMEMBER</a>
*/
default Mono<Tuple> zRandMemberWithScore(ByteBuffer key) {
return zRandMemberWithScore(Mono.just(ZRandMemberCommand.singleValue().from(key)))
.flatMap(CommandResponse::getOutput).next();
}
/**
* Get {@code count} random elements from sorted set at {@code key}.
*
* @param key must not be {@literal null}.
* @param count if the provided {@code count} argument is positive, return a list of distinct fields, capped either at
* {@code count} or the set size. If {@code count} is negative, the behavior changes and the command is
* allowed to return the same value multiple times. In this case, the number of returned values is the
* absolute value of the specified count.
* @return
* @since 2.6
* @see <a href="https://redis.io/commands/zrandmember">Redis Documentation: ZRANDMEMBER</a>
*/
default Flux<Tuple> zRandMemberWithScore(ByteBuffer key, long count) {
return zRandMemberWithScore(Mono.just(ZRandMemberCommand.valueCount(count).from(key)))
.flatMap(CommandResponse::getOutput);
}
/**
* Get random elements from sorted set at {@code key}.
*
* @param commands must not be {@literal null}.
* @return
* @since 2.6
* @see <a href="https://redis.io/commands/zrandmember">Redis Documentation: ZRANDMEMBER</a>
*/
Flux<CommandResponse<ZRandMemberCommand, Flux<Tuple>>> zRandMemberWithScore(Publisher<ZRandMemberCommand> commands);
/**
* {@code ZRANK}/{@literal ZREVRANK} command parameters.
*

View File

@@ -634,6 +634,58 @@ public interface RedisZSetCommands {
@Nullable
Double zIncrBy(byte[] key, double increment, byte[] value);
/**
* Get random element from sorted set at {@code key}.
*
* @param key must not be {@literal null}.
* @return can be {@literal null}.
* @since 2.6
* @see <a href="https://redis.io/commands/zrandmember">Redis Documentation: ZRANDMEMBER</a>
*/
@Nullable
byte[] zRandMember(byte[] key);
/**
* Get {@code count} random elements from sorted set at {@code key}.
*
* @param key must not be {@literal null}.
* @param count if the provided {@code count} argument is positive, return a list of distinct fields, capped either at
* {@code count} or the set size. If {@code count} is negative, the behavior changes and the command is
* allowed to return the same value multiple times. In this case, the number of returned values is the
* absolute value of the specified count.
* @return {@literal null} when used in pipeline / transaction.
* @since 2.6
* @see <a href="https://redis.io/commands/zrandmember">Redis Documentation: ZRANDMEMBER</a>
*/
@Nullable
List<byte[]> zRandMember(byte[] key, long count);
/**
* Get random element from sorted set at {@code key}.
*
* @param key must not be {@literal null}.
* @return can be {@literal null}.
* @since 2.6
* @see <a href="https://redis.io/commands/zrandmember">Redis Documentation: ZRANDMEMBER</a>
*/
@Nullable
Tuple zRandMemberWithScore(byte[] key);
/**
* Get {@code count} random elements from sorted set at {@code key}.
*
* @param key must not be {@literal null}.
* @param count if the provided {@code count} argument is positive, return a list of distinct fields, capped either at
* {@code count} or the set size. If {@code count} is negative, the behavior changes and the command is
* allowed to return the same value multiple times. In this case, the number of returned values is the
* absolute value of the specified count.
* @return {@literal null} when used in pipeline / transaction.
* @since 2.6
* @see <a href="https://redis.io/commands/zrandmember">Redis Documentation: ZRANDMEMBER</a>
*/
@Nullable
List<Tuple> zRandMemberWithScore(byte[] key, long count);
/**
* Determine the index of element with {@code value} in a sorted set.
*

View File

@@ -1229,6 +1229,58 @@ public interface StringRedisConnection extends RedisConnection {
*/
Double zIncrBy(String key, double increment, String value);
/**
* Get random element from sorted set at {@code key}.
*
* @param key must not be {@literal null}.
* @return can be {@literal null}.
* @since 2.6
* @see <a href="https://redis.io/commands/zrandmember">Redis Documentation: ZRANDMEMBER</a>
*/
@Nullable
String zRandMember(String key);
/**
* Get {@code count} random elements from sorted set at {@code key}.
*
* @param key must not be {@literal null}.
* @param count if the provided {@code count} argument is positive, return a list of distinct fields, capped either at
* {@code count} or the set size. If {@code count} is negative, the behavior changes and the command is
* allowed to return the same value multiple times. In this case, the number of returned values is the
* absolute value of the specified count.
* @return {@literal null} when used in pipeline / transaction.
* @since 2.6
* @see <a href="https://redis.io/commands/zrandmember">Redis Documentation: ZRANDMEMBER</a>
*/
@Nullable
List<String> zRandMember(String key, long count);
/**
* Get random element from sorted set at {@code key}.
*
* @param key must not be {@literal null}.
* @return can be {@literal null}.
* @since 2.6
* @see <a href="https://redis.io/commands/zrandmember">Redis Documentation: ZRANDMEMBER</a>
*/
@Nullable
StringTuple zRandMemberWithScore(String key);
/**
* Get {@code count} random elements from sorted set at {@code key}.
*
* @param key must not be {@literal null}.
* @param count if the provided {@code count} argument is positive, return a list of distinct fields, capped either at
* {@code count} or the set size. If {@code count} is negative, the behavior changes and the command is
* allowed to return the same value multiple times. In this case, the number of returned values is the
* absolute value of the specified count.
* @return {@literal null} when used in pipeline / transaction.
* @since 2.6
* @see <a href="https://redis.io/commands/zrandmember">Redis Documentation: ZRANDMEMBER</a>
*/
@Nullable
List<StringTuple> zRandMemberWithScores(String key, long count);
/**
* Determine the index of element with {@code value} in a sorted set.
*

View File

@@ -18,9 +18,11 @@ package org.springframework.data.redis.connection.jedis;
import redis.clients.jedis.ScanParams;
import redis.clients.jedis.ZParams;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
@@ -124,6 +126,74 @@ class JedisClusterZSetCommands implements RedisZSetCommands {
}
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisZSetCommands#zRandMember(byte[])
*/
@Override
public byte[] zRandMember(byte[] key) {
Assert.notNull(key, "Key must not be null!");
try {
return connection.getCluster().zrandmember(key);
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisZSetCommands#zRandMember(byte[], long)
*/
@Override
public List<byte[]> zRandMember(byte[] key, long count) {
Assert.notNull(key, "Key must not be null!");
try {
return new ArrayList<>(connection.getCluster().zrandmember(key, count));
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisZSetCommands#zRandMemberWithScore(byte[])
*/
@Override
public Tuple zRandMemberWithScore(byte[] key) {
Assert.notNull(key, "Key must not be null!");
try {
Set<redis.clients.jedis.Tuple> tuples = connection.getCluster().zrandmemberWithScores(key, 1);
return tuples.isEmpty() ? null : JedisConverters.toTuple(tuples.iterator().next());
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisZSetCommands#zRandMemberWithScore(byte[], long)
*/
@Override
public List<Tuple> zRandMemberWithScore(byte[] key, long count) {
Assert.notNull(key, "Key must not be null!");
try {
Set<redis.clients.jedis.Tuple> tuples = connection.getCluster().zrandmemberWithScores(key, count);
return tuples.stream().map(JedisConverters::toTuple).collect(Collectors.toList());
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisZSetCommands#zRank(byte[], byte[])

View File

@@ -62,7 +62,8 @@ class JedisZSetCommands implements RedisZSetCommands {
Assert.notNull(key, "Key must not be null!");
Assert.notNull(value, "Value must not be null!");
return connection.invoke().from(BinaryJedis::zadd, MultiKeyPipelineBase::zadd, key, score, value, JedisConverters.toZAddParams(args))
return connection.invoke()
.from(BinaryJedis::zadd, MultiKeyPipelineBase::zadd, key, score, value, JedisConverters.toZAddParams(args))
.get(JedisConverters::toBoolean);
}
@@ -107,6 +108,65 @@ class JedisZSetCommands implements RedisZSetCommands {
return connection.invoke().just(BinaryJedis::zincrby, MultiKeyPipelineBase::zincrby, key, increment, value);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisZSetCommands#zRandMember(byte[])
*/
@Override
public byte[] zRandMember(byte[] key) {
Assert.notNull(key, "Key must not be null!");
return connection.invoke().just(BinaryJedis::zrandmember, MultiKeyPipelineBase::zrandmember, key);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisZSetCommands#zRandMember(byte[], long)
*/
@Override
public List<byte[]> zRandMember(byte[] key, long count) {
Assert.notNull(key, "Key must not be null!");
return connection.invoke().fromMany(BinaryJedis::zrandmember, MultiKeyPipelineBase::zrandmember, key, count)
.toList();
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisZSetCommands#zRandMemberWithScore(byte[])
*/
@Override
public Tuple zRandMemberWithScore(byte[] key) {
Assert.notNull(key, "Key must not be null!");
return connection.invoke()
.from(BinaryJedis::zrandmemberWithScores, MultiKeyPipelineBase::zrandmemberWithScores, key, 1L).get(it -> {
if (it.isEmpty()) {
return null;
}
return JedisConverters.toTuple(it.iterator().next());
});
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisZSetCommands#zRandMemberWithScore(byte[], long)
*/
@Override
public List<Tuple> zRandMemberWithScore(byte[] key, long count) {
Assert.notNull(key, "Key must not be null!");
return connection.invoke()
.fromMany(BinaryJedis::zrandmemberWithScores, MultiKeyPipelineBase::zrandmemberWithScores, key, count)
.toList(JedisConverters::toTuple);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisZSetCommands#zRank(byte[], byte[])

View File

@@ -160,6 +160,39 @@ class LettuceReactiveZSetCommands implements ReactiveZSetCommands {
}));
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.ReactiveZSetCommands#zRandMember(Publisher)
*/
@Override
public Flux<CommandResponse<ZRandMemberCommand, Flux<ByteBuffer>>> zRandMember(
Publisher<ZRandMemberCommand> commands) {
return connection.execute(cmd -> Flux.from(commands).map(command -> {
Assert.notNull(command.getKey(), "Key must not be null!");
return new CommandResponse<>(command, cmd.zrandmember(command.getKey(), command.getCount()));
}));
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.ReactiveZSetCommands#zRandMemberWithScore(Publisher)
*/
@Override
public Flux<CommandResponse<ZRandMemberCommand, Flux<Tuple>>> zRandMemberWithScore(
Publisher<ZRandMemberCommand> commands) {
return connection.execute(cmd -> Flux.from(commands).map(command -> {
Assert.notNull(command.getKey(), "Key must not be null!");
return new CommandResponse<>(command, cmd.zrandmemberWithScores(command.getKey(), command.getCount())
.map(this::toTuple));
}));
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.ReactiveZSetCommands#zRank(org.reactivestreams.Publisher)

View File

@@ -107,6 +107,56 @@ class LettuceZSetCommands implements RedisZSetCommands {
return connection.invoke().just(RedisSortedSetAsyncCommands::zincrby, key, increment, value);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisZSetCommands#zRandMember(byte[])
*/
@Override
public byte[] zRandMember(byte[] key) {
Assert.notNull(key, "Key must not be null!");
return connection.invoke().just(RedisSortedSetAsyncCommands::zrandmember, key);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisZSetCommands#zRandMember(byte[], long)
*/
@Override
public List<byte[]> zRandMember(byte[] key, long count) {
Assert.notNull(key, "Key must not be null!");
return connection.invoke().just(RedisSortedSetAsyncCommands::zrandmember, key, count);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisZSetCommands#zRandMemberWithScore(byte[])
*/
@Override
public Tuple zRandMemberWithScore(byte[] key) {
Assert.notNull(key, "Key must not be null!");
return connection.invoke().from(RedisSortedSetAsyncCommands::zrandmemberWithScores, key)
.get(LettuceConverters::toTuple);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisZSetCommands#zRandMemberWithScore(byte[], long)
*/
@Override
public List<Tuple> zRandMemberWithScore(byte[] key, long count) {
Assert.notNull(key, "Key must not be null!");
return connection.invoke().fromMany(RedisSortedSetAsyncCommands::zrandmemberWithScores, key, count)
.toList(LettuceConverters::toTuple);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisZSetCommands#zRank(byte[], byte[])

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.data.redis.core;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
@@ -224,7 +225,7 @@ abstract class AbstractOperations<K, V> {
}
@Nullable
Set<TypedTuple<V>> deserializeTupleValues(@Nullable Collection<Tuple> rawValues) {
Set<TypedTuple<V>> deserializeTupleValues(@Nullable Set<Tuple> rawValues) {
if (rawValues == null) {
return null;
}
@@ -235,6 +236,17 @@ abstract class AbstractOperations<K, V> {
return set;
}
List<TypedTuple<V>> deserializeTupleValues(List<Tuple> rawValues) {
if (rawValues == null) {
return null;
}
List<TypedTuple<V>> set = new ArrayList<>(rawValues.size());
for (Tuple rawValue : rawValues) {
set.add(deserializeTuple(rawValue));
}
return set;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Nullable
TypedTuple<V> deserializeTuple(@Nullable Tuple tuple) {

View File

@@ -107,6 +107,73 @@ public interface BoundZSetOperations<K, V> extends BoundKeyOperations<K> {
@Nullable
Double incrementScore(V value, double delta);
/**
* Get random element from set at the bound key.
*
* @return {@literal null} when used in pipeline / transaction.
* @since 2.6
* @see <a href="https://redis.io/commands/zrandmember">Redis Documentation: ZRANDMEMBER</a>
*/
V randomMember();
/**
* Get {@code count} distinct random elements from set at the bound key.
*
* @param count nr of members to return
* @return empty {@link Set} if {@code key} does not exist.
* @throws IllegalArgumentException if count is negative.
* @since 2.6
* @see <a href="https://redis.io/commands/zrandmember">Redis Documentation: ZRANDMEMBER</a>
*/
@Nullable
Set<V> distinctRandomMembers(long count);
/**
* Get {@code count} random elements from set at the bound key.
*
* @param count nr of members to return.
* @return empty {@link List} if {@code key} does not exist or {@literal null} when used in pipeline / transaction.
* @throws IllegalArgumentException if count is negative.
* @since 2.6
* @see <a href="https://redis.io/commands/zrandmember">Redis Documentation: ZRANDMEMBER</a>
*/
@Nullable
List<V> randomMembers(long count);
/**
* Get random element with its score from set at the bound key.
*
* @return {@literal null} when used in pipeline / transaction.
* @since 2.6
* @see <a href="https://redis.io/commands/zrandmember">Redis Documentation: ZRANDMEMBER</a>
*/
TypedTuple<V> randomMemberWithScore();
/**
* Get {@code count} distinct random elements with their score from set at the bound key.
*
* @param count nr of members to return
* @return empty {@link Set} if {@code key} does not exist.
* @throws IllegalArgumentException if count is negative.
* @since 2.6
* @see <a href="https://redis.io/commands/zrandmember">Redis Documentation: ZRANDMEMBER</a>
*/
@Nullable
Set<TypedTuple<V>> distinctRandomMembersWithScore(long count);
/**
* Get {@code count} random elements with their score from set at the bound key.
*
* @param key must not be {@literal null}.
* @param count nr of members to return.
* @return empty {@link List} if {@code key} does not exist or {@literal null} when used in pipeline / transaction.
* @throws IllegalArgumentException if count is negative.
* @since 2.6
* @see <a href="https://redis.io/commands/zrandmember">Redis Documentation: ZRANDMEMBER</a>
*/
@Nullable
List<TypedTuple<V>> randomMembersWithScore(long count);
/**
* Determine the index of element with {@code value} in a sorted set.
*

View File

@@ -99,6 +99,64 @@ class DefaultBoundZSetOperations<K, V> extends DefaultBoundKeyOperations<K> impl
return ops.incrementScore(getKey(), value, delta);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.BoundZSetOperations#randomMember()
*/
@Override
public V randomMember() {
return ops.randomMember(getKey());
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.BoundZSetOperations#distinctRandomMembers(long)
*/
@Nullable
@Override
public Set<V> distinctRandomMembers(long count) {
return ops.distinctRandomMembers(getKey(), count);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.BoundZSetOperations#randomMembers(long)
*/
@Nullable
@Override
public List<V> randomMembers(long count) {
return ops.randomMembers(getKey(), count);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.BoundZSetOperations#randomMemberWithScore()
*/
@Override
public TypedTuple<V> randomMemberWithScore() {
return ops.randomMemberWithScore(getKey());
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.BoundZSetOperations#distinctRandomMembersWithScore(long)
*/
@Nullable
@Override
public Set<TypedTuple<V>> distinctRandomMembersWithScore(long count) {
return ops.distinctRandomMembersWithScore(getKey(), count);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.BoundZSetOperations#randomMembersWithScore(long)
*/
@Nullable
@Override
public List<TypedTuple<V>> randomMembersWithScore(long count) {
return ops.randomMembersWithScore(getKey(), count);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.BoundZSetOperations#getOperations()

View File

@@ -120,6 +120,82 @@ class DefaultReactiveZSetOperations<K, V> implements ReactiveZSetOperations<K, V
return createMono(connection -> connection.zIncrBy(rawKey(key), delta, rawValue(value)));
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.ReactiveZSetOperations#randomMember(K)
*/
@Override
public Mono<V> randomMember(K key) {
Assert.notNull(key, "Key must not be null!");
return createMono(connection -> connection.zRandMember(rawKey(key))).map(this::readValue);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.ReactiveZSetOperations#distinctRandomMembers(K, long)
*/
@Override
public Flux<V> distinctRandomMembers(K key, long count) {
Assert.notNull(key, "Key must not be null!");
Assert.isTrue(count > 0, "Negative count not supported. Use randomMembers to allow duplicate elements.");
return createFlux(connection -> connection.zRandMember(rawKey(key), count)).map(this::readValue);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.ReactiveZSetOperations#randomMembers(K, long)
*/
@Override
public Flux<V> randomMembers(K key, long count) {
Assert.notNull(key, "Key must not be null!");
Assert.isTrue(count > 0, "Use a positive number for count. This method is already allowing duplicate elements.");
return createFlux(connection -> connection.zRandMember(rawKey(key), -count)).map(this::readValue);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.ReactiveZSetOperations#randomMemberWithScore(K)
*/
@Override
public Mono<TypedTuple<V>> randomMemberWithScore(K key) {
Assert.notNull(key, "Key must not be null!");
return createMono(connection -> connection.zRandMemberWithScore(rawKey(key))).map(this::readTypedTuple);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.ReactiveZSetOperations#distinctRandomMembersWithScore(K, long)
*/
@Override
public Flux<TypedTuple<V>> distinctRandomMembersWithScore(K key, long count) {
Assert.notNull(key, "Key must not be null!");
Assert.isTrue(count > 0, "Negative count not supported. Use randomMembers to allow duplicate elements.");
return createFlux(connection -> connection.zRandMemberWithScore(rawKey(key), count)).map(this::readTypedTuple);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.ReactiveZSetOperations#randomMembersWithScore(K, long)
*/
@Override
public Flux<TypedTuple<V>> randomMembersWithScore(K key, long count) {
Assert.notNull(key, "Key must not be null!");
Assert.isTrue(count > 0, "Use a positive number for count. This method is already allowing duplicate elements.");
return createFlux(connection -> connection.zRandMemberWithScore(rawKey(key), -count)).map(this::readTypedTuple);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.ReactiveZSetOperations#rank(java.lang.Object, java.lang.Object)

View File

@@ -17,6 +17,7 @@ package org.springframework.data.redis.core;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@@ -28,6 +29,7 @@ import org.springframework.data.redis.connection.RedisZSetCommands.Tuple;
import org.springframework.data.redis.connection.RedisZSetCommands.Weights;
import org.springframework.data.redis.connection.RedisZSetCommands.ZAddArgs;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Default implementation of {@link ZSetOperations}.
@@ -130,6 +132,90 @@ class DefaultZSetOperations<K, V> extends AbstractOperations<K, V> implements ZS
return execute(connection -> connection.zIncrBy(rawKey, delta, rawValue), true);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.ZSetOperations#randomMember(java.lang.Object)
*/
@Override
public V randomMember(K key) {
byte[] rawKey = rawKey(key);
return deserializeValue(execute(connection -> connection.zRandMember(rawKey), true));
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.ZSetOperations#distinctRandomMembers(java.lang.Object, long)
*/
@Override
public Set<V> distinctRandomMembers(K key, long count) {
Assert.isTrue(count > 0, "Negative count not supported. Use randomMembers to allow duplicate elements.");
byte[] rawKey = rawKey(key);
List<byte[]> result = execute(connection -> connection.zRandMember(rawKey, count), true);
return result != null ? deserializeValues(new LinkedHashSet<>(result)) : null;
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.ZSetOperations#randomMembers(java.lang.Object, long)
*/
@Override
public List<V> randomMembers(K key, long count) {
Assert.isTrue(count > 0, "Use a positive number for count. This method is already allowing duplicate elements.");
byte[] rawKey = rawKey(key);
List<byte[]> result = execute(connection -> connection.zRandMember(rawKey, count), true);
return deserializeValues(result);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.ZSetOperations#randomMemberWithScore(java.lang.Object)
*/
@Override
public TypedTuple<V> randomMemberWithScore(K key) {
byte[] rawKey = rawKey(key);
return deserializeTuple(execute(connection -> connection.zRandMemberWithScore(rawKey), true));
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.ZSetOperations#distinctRandomMembersWithScore(java.lang.Object, long)
*/
@Override
public Set<TypedTuple<V>> distinctRandomMembersWithScore(K key, long count) {
Assert.isTrue(count > 0, "Negative count not supported. Use randomMembers to allow duplicate elements.");
byte[] rawKey = rawKey(key);
List<Tuple> result = execute(connection -> connection.zRandMemberWithScore(rawKey, count), true);
return result != null ? deserializeTupleValues(new LinkedHashSet<>(result)) : null;
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.ZSetOperations#randomMembersWithScore(java.lang.Object, long)
*/
@Override
public List<TypedTuple<V>> randomMembersWithScore(K key, long count) {
Assert.isTrue(count > 0, "Use a positive number for count. This method is already allowing duplicate elements.");
byte[] rawKey = rawKey(key);
List<Tuple> result = execute(connection -> connection.zRandMemberWithScore(rawKey, count), true);
return result != null ? deserializeTupleValues(result) : null;
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.ZSetOperations#range(java.lang.Object, long, long)
@@ -459,7 +545,8 @@ class DefaultZSetOperations<K, V> extends AbstractOperations<K, V> implements ZS
public Set<TypedTuple<V>> popMin(K key, long count) {
byte[] rawKey = rawKey(key);
return deserializeTupleValues(execute(connection -> connection.zPopMin(rawKey, count), true));
Set<Tuple> result = execute(connection -> connection.zPopMin(rawKey, count), true);
return deserializeTupleValues(new LinkedHashSet<> (result));
}
/*
@@ -495,7 +582,8 @@ class DefaultZSetOperations<K, V> extends AbstractOperations<K, V> implements ZS
public Set<TypedTuple<V>> popMax(K key, long count) {
byte[] rawKey = rawKey(key);
return deserializeTupleValues(execute(connection -> connection.zPopMax(rawKey, count), true));
Set<Tuple> result =execute(connection -> connection.zPopMax(rawKey, count), true);
return deserializeTupleValues(new LinkedHashSet<>(result));
}
/*
@@ -550,7 +638,8 @@ class DefaultZSetOperations<K, V> extends AbstractOperations<K, V> implements ZS
public Set<TypedTuple<V>> differenceWithScores(K key, Collection<K> otherKeys) {
byte[][] rawKeys = rawKeys(key, otherKeys);
return deserializeTupleValues(execute(connection -> connection.zDiffWithScores(rawKeys), true));
Set<Tuple> result = execute(connection -> connection.zDiffWithScores(rawKeys), true);
return deserializeTupleValues(new LinkedHashSet<>(result));
}
/*
@@ -586,7 +675,8 @@ class DefaultZSetOperations<K, V> extends AbstractOperations<K, V> implements ZS
public Set<TypedTuple<V>> intersectWithScores(K key, Collection<K> otherKeys) {
byte[][] rawKeys = rawKeys(key, otherKeys);
return deserializeTupleValues(execute(connection -> connection.zInterWithScores(rawKeys), true));
Set<Tuple> result = execute(connection -> connection.zInterWithScores(rawKeys), true);
return deserializeTupleValues(result);
}
/*
@@ -597,8 +687,8 @@ class DefaultZSetOperations<K, V> extends AbstractOperations<K, V> implements ZS
public Set<TypedTuple<V>> intersectWithScores(K key, Collection<K> otherKeys, Aggregate aggregate, Weights weights) {
byte[][] rawKeys = rawKeys(key, otherKeys);
return deserializeTupleValues(
execute(connection -> connection.zInterWithScores(aggregate, weights, rawKeys), true));
Set<Tuple> result = execute(connection -> connection.zInterWithScores(aggregate, weights, rawKeys), true);
return deserializeTupleValues(result);
}
/*
@@ -656,7 +746,8 @@ class DefaultZSetOperations<K, V> extends AbstractOperations<K, V> implements ZS
public Set<TypedTuple<V>> unionWithScores(K key, Collection<K> otherKeys) {
byte[][] rawKeys = rawKeys(key, otherKeys);
return deserializeTupleValues(execute(connection -> connection.zUnionWithScores(rawKeys), true));
Set<Tuple> result = execute(connection -> connection.zUnionWithScores(rawKeys), true);
return deserializeTupleValues(result);
}
/*
@@ -667,8 +758,9 @@ class DefaultZSetOperations<K, V> extends AbstractOperations<K, V> implements ZS
public Set<TypedTuple<V>> unionWithScores(K key, Collection<K> otherKeys, Aggregate aggregate, Weights weights) {
byte[][] rawKeys = rawKeys(key, otherKeys);
Set<Tuple> result = execute(connection -> connection.zUnionWithScores(aggregate, weights, rawKeys), true);
return deserializeTupleValues(
execute(connection -> connection.zUnionWithScores(aggregate, weights, rawKeys), true));
result);
}
/*

View File

@@ -83,6 +83,74 @@ public interface ReactiveZSetOperations<K, V> {
*/
Mono<Double> incrementScore(K key, V value, double delta);
/**
* Get random element from set at {@code key}.
*
* @param key must not be {@literal null}.
* @return
* @since 2.6
* @see <a href="https://redis.io/commands/zrandmember">Redis Documentation: ZRANDMEMBER</a>
*/
Mono<V> randomMember(K key);
/**
* Get {@code count} distinct random elements from set at {@code key}.
*
* @param key must not be {@literal null}.
* @param count nr of members to return
* @return
* @throws IllegalArgumentException if count is negative.
* @since 2.6
* @see <a href="https://redis.io/commands/zrandmember">Redis Documentation: ZRANDMEMBER</a>
*/
Flux<V> distinctRandomMembers(K key, long count);
/**
* Get {@code count} random elements from set at {@code key}.
*
* @param key must not be {@literal null}.
* @param count nr of members to return.
* @return
* @throws IllegalArgumentException if count is negative.
* @since 2.6
* @see <a href="https://redis.io/commands/zrandmember">Redis Documentation: ZRANDMEMBER</a>
*/
Flux<V> randomMembers(K key, long count);
/**
* Get random element with its score from set at {@code key}.
*
* @param key must not be {@literal null}.
* @return
* @since 2.6
* @see <a href="https://redis.io/commands/zrandmember">Redis Documentation: ZRANDMEMBER</a>
*/
Mono<TypedTuple<V>> randomMemberWithScore(K key);
/**
* Get {@code count} distinct random elements with their score from set at {@code key}.
*
* @param key must not be {@literal null}.
* @param count nr of members to return
* @return
* @throws IllegalArgumentException if count is negative.
* @since 2.6
* @see <a href="https://redis.io/commands/zrandmember">Redis Documentation: ZRANDMEMBER</a>
*/
Flux<TypedTuple<V>> distinctRandomMembersWithScore(K key, long count);
/**
* Get {@code count} random elements with their score from set at {@code key}.
*
* @param key must not be {@literal null}.
* @param count nr of members to return.
* @return
* @throws IllegalArgumentException if count is negative.
* @since 2.6
* @see <a href="https://redis.io/commands/zrandmember">Redis Documentation: ZRANDMEMBER</a>
*/
Flux<TypedTuple<V>> randomMembersWithScore(K key, long count);
/**
* Determine the index of element with {@code value} in a sorted set.
*

View File

@@ -138,6 +138,78 @@ public interface ZSetOperations<K, V> {
@Nullable
Double incrementScore(K key, V value, double delta);
/**
* Get random element from set at {@code key}.
*
* @param key must not be {@literal null}.
* @return {@literal null} when used in pipeline / transaction.
* @since 2.6
* @see <a href="https://redis.io/commands/zrandmember">Redis Documentation: ZRANDMEMBER</a>
*/
V randomMember(K key);
/**
* Get {@code count} distinct random elements from set at {@code key}.
*
* @param key must not be {@literal null}.
* @param count nr of members to return
* @return empty {@link Set} if {@code key} does not exist.
* @throws IllegalArgumentException if count is negative.
* @since 2.6
* @see <a href="https://redis.io/commands/zrandmember">Redis Documentation: ZRANDMEMBER</a>
*/
@Nullable
Set<V> distinctRandomMembers(K key, long count);
/**
* Get {@code count} random elements from set at {@code key}.
*
* @param key must not be {@literal null}.
* @param count nr of members to return.
* @return empty {@link List} if {@code key} does not exist or {@literal null} when used in pipeline / transaction.
* @throws IllegalArgumentException if count is negative.
* @since 2.6
* @see <a href="https://redis.io/commands/zrandmember">Redis Documentation: ZRANDMEMBER</a>
*/
@Nullable
List<V> randomMembers(K key, long count);
/**
* Get random element with its score from set at {@code key}.
*
* @param key must not be {@literal null}.
* @return {@literal null} when used in pipeline / transaction.
* @since 2.6
* @see <a href="https://redis.io/commands/zrandmember">Redis Documentation: ZRANDMEMBER</a>
*/
TypedTuple<V> randomMemberWithScore(K key);
/**
* Get {@code count} distinct random elements with their score from set at {@code key}.
*
* @param key must not be {@literal null}.
* @param count nr of members to return
* @return empty {@link Set} if {@code key} does not exist.
* @throws IllegalArgumentException if count is negative.
* @since 2.6
* @see <a href="https://redis.io/commands/zrandmember">Redis Documentation: ZRANDMEMBER</a>
*/
@Nullable
Set<TypedTuple<V>> distinctRandomMembersWithScore(K key, long count);
/**
* Get {@code count} random elements with their score from set at {@code key}.
*
* @param key must not be {@literal null}.
* @param count nr of members to return.
* @return empty {@link List} if {@code key} does not exist or {@literal null} when used in pipeline / transaction.
* @throws IllegalArgumentException if count is negative.
* @since 2.6
* @see <a href="https://redis.io/commands/zrandmember">Redis Documentation: ZRANDMEMBER</a>
*/
@Nullable
List<TypedTuple<V>> randomMembersWithScore(K key, long count);
/**
* Determine the index of element with {@code value} in a sorted set.
*