Support ZADD params for Reactive-/RedisConnection and add addIfAbsent methods.

Closes: #1794
Original pull request: #1988.
This commit is contained in:
Christoph Strobl
2021-02-23 14:15:03 +01:00
committed by Mark Paluch
parent 102ee017aa
commit 4d77392c9d
21 changed files with 666 additions and 91 deletions

View File

@@ -1322,20 +1322,20 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisZSetCommands#zAdd(byte[], double, byte[])
* @see org.springframework.data.redis.connection.RedisZSetCommands#zAdd(byte[], double, byte[], org.springframework.data.redis.connection.RedisZSetCommands.ZAddArgs)
*/
@Override
public Boolean zAdd(byte[] key, double score, byte[] value) {
return convertAndReturn(delegate.zAdd(key, score, value), Converters.identityConverter());
public Boolean zAdd(byte[] key, double score, byte[] value, ZAddArgs args) {
return convertAndReturn(delegate.zAdd(key, score, value, args), Converters.identityConverter());
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisZSetCommands#zAdd(byte[], java.util.Set)
* @see org.springframework.data.redis.connection.RedisZSetCommands#zAdd(byte[], java.util.Set, org.springframework.data.redis.connection.RedisZSetCommands.ZAddArgs)
*/
@Override
public Long zAdd(byte[] key, Set<Tuple> tuples) {
return convertAndReturn(delegate.zAdd(key, tuples), Converters.identityConverter());
public Long zAdd(byte[] key, Set<Tuple> tuples, ZAddArgs args) {
return convertAndReturn(delegate.zAdd(key, tuples, args), Converters.identityConverter());
}
/*
@@ -2686,20 +2686,20 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.StringRedisConnection#zAdd(java.lang.String, double, java.lang.String)
* @see org.springframework.data.redis.connection.StringRedisConnection#zAdd(java.lang.String, double, java.lang.String, org.springframework.data.redis.connection.RedisZSetCommands.ZAddArgs)
*/
@Override
public Boolean zAdd(String key, double score, String value) {
return zAdd(serialize(key), score, serialize(value));
public Boolean zAdd(String key, double score, String value, ZAddArgs args) {
return zAdd(serialize(key), score, serialize(value), args);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.StringRedisConnection#zAdd(java.lang.String, java.util.Set)
* @see org.springframework.data.redis.connection.StringRedisConnection#zAdd(java.lang.String, java.util.Set, org.springframework.data.redis.connection.RedisZSetCommands.ZAddArgs)
*/
@Override
public Long zAdd(String key, Set<StringTuple> tuples) {
return zAdd(serialize(key), stringTupleToTuple.convert(tuples));
public Long zAdd(String key, Set<StringTuple> tuples, ZAddArgs args) {
return zAdd(serialize(key), stringTupleToTuple.convert(tuples), args);
}
/*

View File

@@ -873,15 +873,15 @@ public interface DefaultedRedisConnection extends RedisConnection {
/** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */
@Override
@Deprecated
default Boolean zAdd(byte[] key, double score, byte[] value) {
return zSetCommands().zAdd(key, score, value);
default Boolean zAdd(byte[] key, double score, byte[] value, ZAddArgs args) {
return zSetCommands().zAdd(key, score, value, args);
}
/** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */
@Override
@Deprecated
default Long zAdd(byte[] key, Set<Tuple> tuples) {
return zSetCommands().zAdd(key, tuples);
default Long zAdd(byte[] key, Set<Tuple> tuples, ZAddArgs args) {
return zSetCommands().zAdd(key, tuples, args);
}
/** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */

View File

@@ -63,9 +63,11 @@ public interface ReactiveZSetCommands {
private final boolean upsert;
private final boolean returnTotalChanged;
private final boolean incr;
private final boolean gt;
private final boolean lt;
private ZAddCommand(@Nullable ByteBuffer key, List<Tuple> tuples, boolean upsert, boolean returnTotalChanged,
boolean incr) {
boolean incr, boolean gt, boolean lt) {
super(key);
@@ -73,6 +75,8 @@ public interface ReactiveZSetCommands {
this.upsert = upsert;
this.returnTotalChanged = returnTotalChanged;
this.incr = incr;
this.gt = gt;
this.lt = lt;
}
/**
@@ -98,7 +102,7 @@ public interface ReactiveZSetCommands {
Assert.notNull(tuples, "Tuples must not be null!");
return new ZAddCommand(null, new ArrayList<>(tuples), false, false, false);
return new ZAddCommand(null, new ArrayList<>(tuples), false, false, false, false, false);
}
/**
@@ -111,7 +115,7 @@ public interface ReactiveZSetCommands {
Assert.notNull(key, "Key must not be null!");
return new ZAddCommand(key, tuples, upsert, returnTotalChanged, incr);
return new ZAddCommand(key, tuples, upsert, returnTotalChanged, incr, gt, lt);
}
/**
@@ -121,7 +125,7 @@ public interface ReactiveZSetCommands {
* @return a new {@link ZAddCommand} with {@literal xx} applied.
*/
public ZAddCommand xx() {
return new ZAddCommand(getKey(), tuples, false, returnTotalChanged, incr);
return new ZAddCommand(getKey(), tuples, false, returnTotalChanged, incr, gt, lt);
}
/**
@@ -131,7 +135,7 @@ public interface ReactiveZSetCommands {
* @return a new {@link ZAddCommand} with {@literal nx} applied.
*/
public ZAddCommand nx() {
return new ZAddCommand(getKey(), tuples, true, returnTotalChanged, incr);
return new ZAddCommand(getKey(), tuples, true, returnTotalChanged, incr, gt, lt);
}
/**
@@ -141,7 +145,7 @@ public interface ReactiveZSetCommands {
* @return a new {@link ZAddCommand} with {@literal ch} applied.
*/
public ZAddCommand ch() {
return new ZAddCommand(getKey(), tuples, upsert, true, incr);
return new ZAddCommand(getKey(), tuples, upsert, true, incr, gt, lt);
}
/**
@@ -151,7 +155,29 @@ public interface ReactiveZSetCommands {
* @return a new {@link ZAddCommand} with {@literal incr} applied.
*/
public ZAddCommand incr() {
return new ZAddCommand(getKey(), tuples, upsert, upsert, true);
return new ZAddCommand(getKey(), tuples, upsert, upsert, true, gt, lt);
}
/**
* Applies {@literal GT} mode. Constructs a new command
* instance with all previously configured properties.
*
* @return a new {@link ZAddCommand} with {@literal incr} applied.
* @since 2.5
*/
public ZAddCommand gt() {
return new ZAddCommand(getKey(), tuples, upsert, upsert, incr, true, lt);
}
/**
* Applies {@literal LT} mode. Constructs a new command
* instance with all previously configured properties.
*
* @return a new {@link ZAddCommand} with {@literal incr} applied.
* @since 2.5
*/
public ZAddCommand lt() {
return new ZAddCommand(getKey(), tuples, upsert, upsert, incr, gt, true);
}
/**
@@ -175,6 +201,23 @@ public interface ReactiveZSetCommands {
return incr;
}
/**
*
* @return {@literal true} if {@literal GT} is set.
* @since 2.5
*/
public boolean isGt() {
return gt;
}
/**
* @return {@literal true} if {@literal LT} is set.
* @since 2.5
*/
public boolean isLt() {
return lt;
}
/**
* @return
*/

View File

@@ -17,6 +17,7 @@ package org.springframework.data.redis.connection;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.function.DoubleUnaryOperator;
@@ -396,6 +397,171 @@ public interface RedisZSetCommands {
}
}
/**
* {@code ZADD} specific arguments. <br />
* Looking of the {@code INCR} flag? Use the {@code ZINCRBY} operation instead.
*
* @since 2.3
* @see <a href="https://redis.io/commands/zadd">Redis Documentation: ZADD</a>
*/
class ZAddArgs {
private static final ZAddArgs NONE = new ZAddArgs(Collections.emptySet());
private final Set<Flag> flags;
private ZAddArgs(Set<Flag> flags) {
this.flags = flags;
}
/**
* @return immutable {@link ZAddArgs}.
*/
public static ZAddArgs none() {
return NONE;
}
/**
* @return new instance of {@link ZAddArgs} without any flags set.
*/
public static ZAddArgs empty() {
return new ZAddArgs(new LinkedHashSet<>(5));
}
/**
* @return new instance of {@link ZAddArgs} without {@link Flag#NX} set.
*/
public static ZAddArgs ifNotExists() {
return empty().nx();
}
/**
* @return new instance of {@link ZAddArgs} without {@link Flag#NX} set.
*/
public static ZAddArgs ifExists() {
return empty().xx();
}
/**
* Only update elements that already exist.
*
* @return this.
*/
public ZAddArgs nx() {
flags.add(Flag.NX);
return this;
}
/**
* Don't update already existing elements.
*
* @return this.
*/
public ZAddArgs xx() {
flags.add(Flag.XX);
return this;
}
/**
* Only update existing elements if the new score is less than the current score.
*
* @return this.
*/
public ZAddArgs lt() {
flags.add(Flag.LT);
return this;
}
/**
* Only update existing elements if the new score is greater than the current score.
*
* @return this.
*/
public ZAddArgs gt() {
flags.add(Flag.GT);
return this;
}
/**
* Only update elements that already exist.
*
* @return this.
*/
public ZAddArgs ch() {
flags.add(Flag.CH);
return this;
}
/**
* Only update elements that already exist.
*
* @return this.
*/
public boolean contains(Flag flag) {
return flags.contains(flag);
}
/**
* @return {@literal true} if no flags set.
*/
public boolean isEmpty() {
return !flags.isEmpty();
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ZAddArgs zAddArgs = (ZAddArgs) o;
return ObjectUtils.nullSafeEquals(flags, zAddArgs.flags);
}
@Override
public int hashCode() {
return ObjectUtils.nullSafeHashCode(flags);
}
public enum Flag {
/**
* Only update elements that already exist.
*/
XX,
/**
* Don't update already existing elements.
*/
NX,
/**
* Only update existing elements if the new score is greater than the current score.
*/
GT,
/**
* Only update existing elements if the new score is less than the current score.
*/
LT,
/**
* Modify the return value from the number of new elements added, to the total number of elements changed.
*/
CH
}
}
/**
* Add {@code value} to a sorted set at {@code key}, or update its {@code score} if it already exists.
*
@@ -406,7 +572,24 @@ public interface RedisZSetCommands {
* @see <a href="https://redis.io/commands/zadd">Redis Documentation: ZADD</a>
*/
@Nullable
Boolean zAdd(byte[] key, double score, byte[] value);
default Boolean zAdd(byte[] key, double score, byte[] value) {
return zAdd(key, score, value, ZAddArgs.none());
}
/**
* Add {@code value} to a sorted set at {@code key}, or update its {@code score} depending on the given
* {@link ZAddArgs args}.
*
* @param key must not be {@literal null}.
* @param score the score.
* @param value the value.
* @param args must not be {@literal null} use {@link ZAddArgs#none()} instead.
* @return {@literal null} when used in pipeline / transaction.
* @since 2.5
* @see <a href="https://redis.io/commands/zadd">Redis Documentation: ZADD</a>
*/
@Nullable
Boolean zAdd(byte[] key, double score, byte[] value, ZAddArgs args);
/**
* Add {@code tuples} to a sorted set at {@code key}, or update its {@code score} if it already exists.
@@ -417,7 +600,22 @@ public interface RedisZSetCommands {
* @see <a href="https://redis.io/commands/zadd">Redis Documentation: ZADD</a>
*/
@Nullable
Long zAdd(byte[] key, Set<Tuple> tuples);
default Long zAdd(byte[] key, Set<Tuple> tuples) {
return zAdd(key, tuples, ZAddArgs.none());
}
/**
* Add {@code tuples} to a sorted set at {@code key}, or update its {@code score} depending on the given
* {@link ZAddArgs args}.
*
* @param key must not be {@literal null}.
* @param tuples must not be {@literal null}.
* @param args must not be {@literal null} use {@link ZAddArgs#none()} instead.
* @return {@literal null} when used in pipeline / transaction.
* @since 2.5
* @see <a href="https://redis.io/commands/zadd">Redis Documentation: ZADD</a>
*/
Long zAdd(byte[] key, Set<Tuple> tuples, ZAddArgs args);
/**
* Remove {@code values} from sorted set. Return number of removed elements.

View File

@@ -1102,7 +1102,24 @@ public interface StringRedisConnection extends RedisConnection {
* @see <a href="https://redis.io/commands/zadd">Redis Documentation: ZADD</a>
* @see RedisZSetCommands#zAdd(byte[], double, byte[])
*/
Boolean zAdd(String key, double score, String value);
default Boolean zAdd(String key, double score, String value) {
return zAdd(key, score, value, ZAddArgs.none());
}
/**
* Add the {@code value} to a sorted set at {@code key}, or update its {@code score} depending on the given
* {@link ZAddArgs args}.
*
* @param key must not be {@literal null}.
* @param score must not be {@literal null}.
* @param value must not be {@literal null}.
* @param args must not be {@literal null} use {@link ZAddArgs#none()} instead.
* @return {@literal null} when used in pipeline / transaction.
* @since 2.5
* @see <a href="https://redis.io/commands/zadd">Redis Documentation: ZADD</a>
* @see RedisZSetCommands#zAdd(byte[], double, byte[], ZAddArgs)
*/
Boolean zAdd(String key, double score, String value, ZAddArgs args);
/**
* Add {@code tuples} to a sorted set at {@code key}, or update its {@code score} if it already exists.
@@ -1113,7 +1130,24 @@ public interface StringRedisConnection extends RedisConnection {
* @see <a href="https://redis.io/commands/zadd">Redis Documentation: ZADD</a>
* @see RedisZSetCommands#zAdd(byte[], Set)
*/
Long zAdd(String key, Set<StringTuple> tuples);
default Long zAdd(String key, Set<StringTuple> tuples) {
return zAdd(key, tuples, ZAddArgs.none());
}
/**
* Add {@code tuples} to a sorted set at {@code key}, or update its {@code score} depending on the given
* {@link ZAddArgs args}.
*
* @param key must not be {@literal null}.
* @param tuples must not be {@literal null}.
* @param args must not be {@literal null} use {@link ZAddArgs#none()} instead.
* @return {@literal null} when used in pipeline / transaction.
* @since 2.5
* @see <a href="https://redis.io/commands/zadd">Redis Documentation: ZADD</a>
* @see RedisZSetCommands#zAdd(byte[], Set, ZAddArgs)
*/
@Nullable
Long zAdd(String key, Set<StringTuple> tuples, ZAddArgs args);
/**
* Remove {@code values} from sorted set. Return number of removed elements.

View File

@@ -54,13 +54,13 @@ class JedisClusterZSetCommands implements RedisZSetCommands {
* @see org.springframework.data.redis.connection.RedisZSetCommands#zAdd(byte[], double, byte[])
*/
@Override
public Boolean zAdd(byte[] key, double score, byte[] value) {
public Boolean zAdd(byte[] key, double score, byte[] value, ZAddArgs args) {
Assert.notNull(key, "Key must not be null!");
Assert.notNull(value, "Value must not be null!");
try {
return JedisConverters.toBoolean(connection.getCluster().zadd(key, score, value));
return JedisConverters.toBoolean(connection.getCluster().zadd(key, score, value, JedisConverters.toZAddParams(args)));
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
@@ -68,16 +68,16 @@ class JedisClusterZSetCommands implements RedisZSetCommands {
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisZSetCommands#zAdd(byte[], java.util.Set)
* @see org.springframework.data.redis.connection.RedisZSetCommands#zAdd(byte[], java.util.Set, org.springframework.data.redis.connection.RedisZSetCommands.ZAddArgs)
*/
@Override
public Long zAdd(byte[] key, Set<Tuple> tuples) {
public Long zAdd(byte[] key, Set<Tuple> tuples, ZAddArgs args) {
Assert.notNull(key, "Key must not be null!");
Assert.notNull(tuples, "Tuples must not be null!");
try {
return connection.getCluster().zadd(key, JedisConverters.toTupleMap(tuples));
return connection.getCluster().zadd(key, JedisConverters.toTupleMap(tuples), JedisConverters.toZAddParams(args));
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}

View File

@@ -24,6 +24,7 @@ import redis.clients.jedis.ScanParams;
import redis.clients.jedis.SortingParams;
import redis.clients.jedis.params.GeoRadiusParam;
import redis.clients.jedis.params.SetParams;
import redis.clients.jedis.params.ZAddParams;
import redis.clients.jedis.util.SafeEncoder;
import java.nio.ByteBuffer;
@@ -61,6 +62,7 @@ import org.springframework.data.redis.connection.RedisStringCommands.BitOperatio
import org.springframework.data.redis.connection.RedisStringCommands.SetOption;
import org.springframework.data.redis.connection.RedisZSetCommands.Range.Boundary;
import org.springframework.data.redis.connection.RedisZSetCommands.Tuple;
import org.springframework.data.redis.connection.RedisZSetCommands.ZAddArgs;
import org.springframework.data.redis.connection.SortParameters;
import org.springframework.data.redis.connection.SortParameters.Order;
import org.springframework.data.redis.connection.SortParameters.Range;
@@ -652,6 +654,42 @@ public abstract class JedisConverters extends Converters {
return ObjectUtils.caseInsensitiveValueOf(GeoUnit.values(), metricToUse.getAbbreviation());
}
/**
* Convert {@link ZAddArgs} to {@link ZAddParams}.
*
* @param source must not be {@literal null}.
* @return new instance of {@link ZAddParams}.
* @since 2.5
*/
static ZAddParams toZAddParams(ZAddArgs source) {
if (!source.isEmpty()) {
return new ZAddParams();
}
ZAddParams target = new ZAddParams() {
{
if (source.contains(ZAddArgs.Flag.GT)) {
addParam("gt");
}
if (source.contains(ZAddArgs.Flag.LT)) {
addParam("lt");
}
}
};
if (source.contains(ZAddArgs.Flag.XX)) {
target.xx();
}
if (source.contains(ZAddArgs.Flag.NX)) {
target.nx();
}
if (source.contains(ZAddArgs.Flag.CH)) {
target.ch();
}
return target;
}
/**
* Convert {@link GeoRadiusCommandArgs} into {@link GeoRadiusParam}.

View File

@@ -21,12 +21,14 @@ import redis.clients.jedis.MultiKeyPipelineBase;
import redis.clients.jedis.ScanParams;
import redis.clients.jedis.ScanResult;
import redis.clients.jedis.ZParams;
import redis.clients.jedis.params.ZAddParams;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashSet;
import java.util.Set;
import org.springframework.data.redis.connection.RedisZSetCommands;
import org.springframework.data.redis.connection.RedisZSetCommands.ZAddArgs.Flag;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.KeyBoundCursor;
import org.springframework.data.redis.core.ScanIteration;
@@ -53,27 +55,27 @@ class JedisZSetCommands implements RedisZSetCommands {
* @see org.springframework.data.redis.connection.RedisZSetCommands#zAdd(byte[], double, byte[])
*/
@Override
public Boolean zAdd(byte[] key, double score, byte[] value) {
public Boolean zAdd(byte[] key, double score, byte[] value, ZAddArgs args) {
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)
return connection.invoke().from(BinaryJedis::zadd, MultiKeyPipelineBase::zadd, key, score, value, JedisConverters.toZAddParams(args))
.get(JedisConverters::toBoolean);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisZSetCommands#zAdd(byte[], java.util.Set)
* @see org.springframework.data.redis.connection.RedisZSetCommands#zAdd(byte[], java.util.Set, org.springframework.data.redis.connection.RedisZSetCommands.ZAddArgs)
*/
@Override
public Long zAdd(byte[] key, Set<Tuple> tuples) {
public Long zAdd(byte[] key, Set<Tuple> tuples, ZAddArgs args) {
Assert.notNull(key, "Key must not be null!");
Assert.notNull(tuples, "Tuples must not be null!");
return connection.invoke().just(BinaryJedis::zadd, MultiKeyPipelineBase::zadd, key,
JedisConverters.toTupleMap(tuples));
JedisConverters.toTupleMap(tuples), JedisConverters.toZAddParams(args));
}
/*

View File

@@ -102,6 +102,12 @@ class LettuceReactiveZSetCommands implements ReactiveZSetCommands {
} else {
args = ZAddArgs.Builder.xx();
}
if(command.isGt()) {
args = args == null ? ZAddArgs.Builder.gt() : args.gt();
}
if(command.isLt()) {
args = args == null ? ZAddArgs.Builder.lt() : args.lt();
}
}
ScoredValue<ByteBuffer>[] values = (ScoredValue<ByteBuffer>[]) command.getTuples().stream()

View File

@@ -26,6 +26,7 @@ import java.util.List;
import java.util.Set;
import org.springframework.data.redis.connection.RedisZSetCommands;
import org.springframework.data.redis.connection.RedisZSetCommands.ZAddArgs.Flag;
import org.springframework.data.redis.connection.convert.Converters;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.KeyBoundCursor;
@@ -50,29 +51,29 @@ class LettuceZSetCommands implements RedisZSetCommands {
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisZSetCommands#zAdd(byte[], double, byte[])
* @see org.springframework.data.redis.connection.RedisZSetCommands#zAdd(byte[], double, byte[], org.springframework.data.redis.connection.RedisZSetCommands.ZAddArgs)
*/
@Override
public Boolean zAdd(byte[] key, double score, byte[] value) {
public Boolean zAdd(byte[] key, double score, byte[] value, ZAddArgs args) {
Assert.notNull(key, "Key must not be null!");
Assert.notNull(value, "Value must not be null!");
return connection.invoke().from(RedisSortedSetAsyncCommands::zadd, key, score, value)
return connection.invoke().from(RedisSortedSetAsyncCommands::zadd, key, LettuceZSetCommands.toZAddArgs(args), score, value)
.get(LettuceConverters.longToBoolean());
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisZSetCommands#zAdd(byte[], java.util.Set)
* @see org.springframework.data.redis.connection.RedisZSetCommands#zAdd(byte[], java.util.Set, org.springframework.data.redis.connection.RedisZSetCommands.ZAddArgs)
*/
@Override
public Long zAdd(byte[] key, Set<Tuple> tuples) {
public Long zAdd(byte[] key, Set<Tuple> tuples, ZAddArgs args) {
Assert.notNull(key, "Key must not be null!");
Assert.notNull(tuples, "Tuples must not be null!");
return connection.invoke().just(RedisSortedSetAsyncCommands::zadd, key,
return connection.invoke().just(RedisSortedSetAsyncCommands::zadd, key, LettuceZSetCommands.toZAddArgs(args),
LettuceConverters.toObjects(tuples).toArray());
}
@@ -568,4 +569,37 @@ class LettuceZSetCommands implements RedisZSetCommands {
return args;
}
/**
* Convert {@link ZAddArgs} to {@link io.lettuce.core.ZAddArgs}.
*
* @param source must not be {@literal null}.
* @return never {@literal null}.
* @since 2.5
*/
private static io.lettuce.core.ZAddArgs toZAddArgs(ZAddArgs source) {
io.lettuce.core.ZAddArgs target = new io.lettuce.core.ZAddArgs();
if(!source.isEmpty()) {
return target;
}
if(source.contains(Flag.XX)) {
target.xx();
}
if(source.contains(Flag.NX)) {
target.nx();
}
if(source.contains(Flag.GT)) {
target.gt();
}
if(source.contains(Flag.LT)) {
target.lt();
}
if(source.contains(Flag.CH)) {
target.ch();
}
return target;
}
}

View File

@@ -48,6 +48,18 @@ public interface BoundZSetOperations<K, V> extends BoundKeyOperations<K> {
@Nullable
Boolean add(V value, double score);
/**
* Add {@code value} to a sorted set at {@code key} if it does not already exists.
*
* @param score the score.
* @param value the value.
* @return {@literal null} when used in pipeline / transaction.
* @since 2.5
* @see <a href="https://redis.io/commands/zadd">Redis Documentation: ZADD NX</a>
*/
@Nullable
Boolean addIfAbsent(V value, double score);
/**
* Add {@code tuples} to a sorted set at the bound key, or update its {@code score} if it already exists.
*
@@ -58,6 +70,17 @@ public interface BoundZSetOperations<K, V> extends BoundKeyOperations<K> {
@Nullable
Long add(Set<TypedTuple<V>> tuples);
/**
* Add {@code tuples} to a sorted set at {@code key} if it does not already exists.
*
* @param tuples must not be {@literal null}.
* @return {@literal null} when used in pipeline / transaction.
* @since 2.5
* @see <a href="https://redis.io/commands/zadd">Redis Documentation: ZADD NX</a>
*/
@Nullable
Long addIfAbsent(Set<TypedTuple<V>> tuples);
/**
* Remove {@code values} from sorted set. Return number of removed elements.
*

View File

@@ -60,6 +60,15 @@ class DefaultBoundZSetOperations<K, V> extends DefaultBoundKeyOperations<K> impl
return ops.add(getKey(), value, score);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.BoundZSetOperations#addIfAbsent(java.lang.Object, double)
*/
@Override
public Boolean addIfAbsent(V value, double score) {
return ops.addIfAbsent(getKey(), value, score);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.BoundZSetOperations#add(java.util.Set)
@@ -69,6 +78,15 @@ class DefaultBoundZSetOperations<K, V> extends DefaultBoundKeyOperations<K> impl
return ops.add(getKey(), tuples);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.BoundZSetOperations#addIfAbsent(java.util.Set)
*/
@Override
public Long addIfAbsent(Set<TypedTuple<V>> tuples) {
return ops.addIfAbsent(getKey(), tuples);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.BoundZSetOperations#incrementScore(java.lang.Object, double)

View File

@@ -24,6 +24,8 @@ import org.springframework.data.redis.connection.RedisZSetCommands.Limit;
import org.springframework.data.redis.connection.RedisZSetCommands.Range;
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;
/**
* Default implementation of {@link ZSetOperations}.
@@ -48,10 +50,31 @@ class DefaultZSetOperations<K, V> extends AbstractOperations<K, V> implements ZS
*/
@Override
public Boolean add(K key, V value, double score) {
return add(key, value, score, ZAddArgs.none());
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.ZSetOperations#addIfAbsent(java.lang.Object, java.lang.Object, double)
*/
@Override
public Boolean addIfAbsent(K key, V value, double score) {
return add(key, value, score, ZAddArgs.ifNotExists());
}
/**
* @param key must not be {@literal null}.
* @param value must not be {@literal null}.
* @param args never {@literal null}.
* @return can be {@literal null}.
* @since 2.5
*/
@Nullable
protected Boolean add(K key, V value, double score, ZAddArgs args) {
byte[] rawKey = rawKey(key);
byte[] rawValue = rawValue(value);
return execute(connection -> connection.zAdd(rawKey, score, rawValue), true);
return execute(connection -> connection.zAdd(rawKey, score, rawValue, args), true);
}
/*
@@ -60,10 +83,31 @@ class DefaultZSetOperations<K, V> extends AbstractOperations<K, V> implements ZS
*/
@Override
public Long add(K key, Set<TypedTuple<V>> tuples) {
return add(key, tuples, ZAddArgs.none());
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.ZSetOperations#addIfAbsent(java.lang.Object, java.util.Set)
*/
@Override
public Long addIfAbsent(K key, Set<TypedTuple<V>> tuples) {
return add(key, tuples, ZAddArgs.ifNotExists());
}
/**
* @param key must not be {@literal null}.
* @param tuples must not be {@literal null}.
* @param args never {@literal null}.
* @return can be {@literal null}.
* @since 2.5
*/
@Nullable
protected Long add(K key, Set<TypedTuple<V>> tuples, ZAddArgs args) {
byte[] rawKey = rawKey(key);
Set<Tuple> rawValues = rawTupleValues(tuples);
return execute(connection -> connection.zAdd(rawKey, rawValues), true);
return execute(connection -> connection.zAdd(rawKey, rawValues, args), true);
}
/*

View File

@@ -47,6 +47,19 @@ public interface ZSetOperations<K, V> {
@Nullable
Double getScore();
/**
* Create a new {@link TypedTuple}.
*
* @param value must not be {@literal null}.
* @param score can be {@literal null}.
* @param <V>
* @return new instance of {@link TypedTuple}.
* @since 2.5
*/
static <V> TypedTuple<V> of(V value, @Nullable Double score) {
return new DefaultTypedTuple<>(value, score);
}
}
/**
@@ -61,6 +74,19 @@ public interface ZSetOperations<K, V> {
@Nullable
Boolean add(K key, V value, double score);
/**
* Add {@code value} to a sorted set at {@code key} if it does not already exists.
*
* @param key must not be {@literal null}.
* @param score the score.
* @param value the value.
* @return {@literal null} when used in pipeline / transaction.
* @since 2.5
* @see <a href="https://redis.io/commands/zadd">Redis Documentation: ZADD NX</a>
*/
@Nullable
Boolean addIfAbsent(K key, V value, double score);
/**
* Add {@code tuples} to a sorted set at {@code key}, or update its {@code score} if it already exists.
*
@@ -72,6 +98,18 @@ public interface ZSetOperations<K, V> {
@Nullable
Long add(K key, Set<TypedTuple<V>> tuples);
/**
* Add {@code tuples} to a sorted set at {@code key} if it does not already exists.
*
* @param key must not be {@literal null}.
* @param tuples must not be {@literal null}.
* @return {@literal null} when used in pipeline / transaction.
* @since 2.5
* @see <a href="https://redis.io/commands/zadd">Redis Documentation: ZADD NX</a>
*/
@Nullable
Long addIfAbsent(K key, Set<TypedTuple<V>> tuples);
/**
* Remove {@code values} from sorted set. Return number of removed elements.
*

View File

@@ -288,6 +288,18 @@ public class DefaultRedisZSet<E> extends AbstractRedisCollection<E> implements R
return result;
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.support.collections.RedisZSet#addIfAbsent(java.lang.Object, double)
*/
@Override
public boolean addIfAbsent(E e, double score) {
Boolean result = boundZSetOps.addIfAbsent(e, score);
checkResult(result);
return result;
}
/*
* (non-Javadoc)
* @see java.util.AbstractCollection#clear()

View File

@@ -144,6 +144,27 @@ public interface RedisZSet<E> extends RedisCollection<E>, Set<E> {
*/
boolean add(E e);
/**
* Adds an element to the set using the {@link #getDefaultScore() default score} if the element does not already exists.
*
* @param e element to add
* @return true if a new element was added, false otherwise (only the score has been updated)
* @since 2.5
*/
default boolean addIfAbsent(E e) {
return addIfAbsent(e, getDefaultScore());
}
/**
* Adds an element to the set with the given score if the element does not already exists.
*
* @param e element to add
* @param score element score
* @return true if a new element was added, false otherwise (only the score has been updated)
* @since 2.5
*/
boolean addIfAbsent(E e, double score);
/**
* Count number of elements within sorted set with value between {@code Range#min} and {@code Range#max} applying
* lexicographical ordering.