diff --git a/src/main/java/com/lambdaworks/redis/RedisAsyncConnectionImpl.java b/src/main/java/com/lambdaworks/redis/RedisAsyncConnectionImpl.java index 9e42057d28..d2b9fb029e 100644 --- a/src/main/java/com/lambdaworks/redis/RedisAsyncConnectionImpl.java +++ b/src/main/java/com/lambdaworks/redis/RedisAsyncConnectionImpl.java @@ -974,12 +974,27 @@ public RedisFuture unwatch() { @Override public RedisFuture zadd(K key, double score, V member) { - return dispatch(commandBuilder.zadd(key, score, member)); + return dispatch(commandBuilder.zadd(key, null, score, member)); } @Override public RedisFuture zadd(K key, Object... scoresAndValues) { - return dispatch(commandBuilder.zadd(key, scoresAndValues)); + return dispatch(commandBuilder.zadd(key, null, scoresAndValues)); + } + + @Override + public RedisFuture zadd(K key, ZAddArgs zAddArgs, double score, V member) { + return dispatch(commandBuilder.zadd(key, zAddArgs, score, member)); + } + + @Override + public RedisFuture zadd(K key, ZAddArgs zAddArgs, Object... scoresAndValues) { + return dispatch(commandBuilder.zadd(key, zAddArgs, scoresAndValues)); + } + + @Override + public RedisFuture zaddincr(K key, double score, V member) { + return dispatch(commandBuilder.zaddincr(key, score, member)); } @Override @@ -1579,8 +1594,7 @@ protected RedisCommand dispatch(CommandType type, CommandOutput RedisCommand dispatch(CommandType type, CommandOutput output, - CommandArgs args) { + protected RedisCommand dispatch(CommandType type, CommandOutput output, CommandArgs args) { Command cmd = new Command(type, output, args, multi != null); return dispatch(cmd); } diff --git a/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java b/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java index e8f74a3db7..bd87bce501 100644 --- a/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java +++ b/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java @@ -943,17 +943,38 @@ public Command unwatch() { return createCommand(UNWATCH, new StatusOutput(codec)); } - public Command zadd(K key, double score, V member) { - CommandArgs args = new CommandArgs(codec).addKey(key).add(score).addValue(member); + public Command zadd(K key, ZAddArgs zAddArgs, double score, V member) { + CommandArgs args = new CommandArgs(codec).addKey(key); + + if (zAddArgs != null) { + zAddArgs.build(args); + } + args.add(score).addValue(member); + return createCommand(ZADD, new IntegerOutput(codec), args); } + public Command zaddincr(K key, double score, V member) { + CommandArgs args = new CommandArgs(codec).addKey(key); + args.add(INCR); + args.add(score).addValue(member); + + return createCommand(ZADD, new DoubleOutput(codec), args); + } + @SuppressWarnings("unchecked") - public Command zadd(K key, Object... scoresAndValues) { + public Command zadd(K key, ZAddArgs zAddArgs, Object... scoresAndValues) { assertNotEmpty(scoresAndValues, "scoresAndValues " + MUST_NOT_BE_EMPTY); assertNoNullElements(scoresAndValues, "scoresAndValues " + MUST_NOT_CONTAIN_NULL_ELEMENTS); + assertTrue(scoresAndValues.length % 2 == 0, "scoresAndValues.length must be a multiple of 2 and contain a " + + "sequence of score1, value1, score2, value2, scoreN,valueN"); CommandArgs args = new CommandArgs(codec).addKey(key); + + if (zAddArgs != null) { + zAddArgs.build(args); + } + for (int i = 0; i < scoresAndValues.length; i += 2) { args.add((Double) scoresAndValues[i]); args.addValue((V) scoresAndValues[i + 1]); @@ -1686,4 +1707,17 @@ public static void assertNoNullElements(Object[] array, String message) { } } + /** + * Assert that {@code value} is {@literal true}. + * + * @param value the value to check + * @param message the exception message to use if the assertion fails + * @throws IllegalArgumentException if the object array contains a {@code null} element + */ + public static void assertTrue(boolean value, String message) { + if (!value) { + throw new IllegalArgumentException(message); + } + } + } diff --git a/src/main/java/com/lambdaworks/redis/RedisSortedSetsAsyncConnection.java b/src/main/java/com/lambdaworks/redis/RedisSortedSetsAsyncConnection.java index 92eb0ebff1..e3ffc41f46 100644 --- a/src/main/java/com/lambdaworks/redis/RedisSortedSetsAsyncConnection.java +++ b/src/main/java/com/lambdaworks/redis/RedisSortedSetsAsyncConnection.java @@ -40,6 +40,47 @@ public interface RedisSortedSetsAsyncConnection { */ RedisFuture zadd(K key, Object... scoresAndValues); + /** + * Add one or more members to a sorted set, or update its score if it already exists. + * + * @param key the key + * @param zAddArgs arguments for zadd + * @param score the score + * @param member the member + * + * @return RedisFuture<Long> integer-reply specifically: + * + * The number of elements added to the sorted sets, not including elements already existing for which the score was + * updated. + */ + RedisFuture zadd(K key, ZAddArgs zAddArgs, double score, V member); + + /** + * Add one or more members to a sorted set, or update its score if it already exists. + * + * @param key the key + * @param zAddArgs arguments for zadd + * @param scoresAndValues the scoresAndValue tuples (score,value,score,value,...) + * @return RedisFuture<Long> integer-reply specifically: + * + * The number of elements added to the sorted sets, not including elements already existing for which the score was + * updated. + */ + RedisFuture zadd(K key, ZAddArgs zAddArgs, Object... scoresAndValues); + + /** + * ZADD acts like ZINCRBY + * + * @param key the key + * @param score the score + * @param member the member + * + * @return RedisFuture<Long> integer-reply specifically: + * + * The total number of elements changed + */ + RedisFuture zaddincr(K key, double score, V member); + /** * Get the number of members in a sorted set. * diff --git a/src/main/java/com/lambdaworks/redis/RedisSortedSetsConnection.java b/src/main/java/com/lambdaworks/redis/RedisSortedSetsConnection.java index 0b70a3f416..1099890c1c 100644 --- a/src/main/java/com/lambdaworks/redis/RedisSortedSetsConnection.java +++ b/src/main/java/com/lambdaworks/redis/RedisSortedSetsConnection.java @@ -40,6 +40,47 @@ public interface RedisSortedSetsConnection { */ Long zadd(K key, Object... scoresAndValues); + /** + * Add one or more members to a sorted set, or update its score if it already exists. + * + * @param key the key + * @param zAddArgs arguments for zadd + * @param score the score + * @param member the member + * + * @return Long integer-reply specifically: + * + * The number of elements added to the sorted sets, not including elements already existing for which the score was + * updated. + */ + Long zadd(K key, ZAddArgs zAddArgs, double score, V member); + + /** + * Add one or more members to a sorted set, or update its score if it already exists. + * + * @param key the key + * @param zAddArgs arguments for zadd + * @param scoresAndValues the scoresAndValue tuples (score,value,score,value,...) + * @return Long integer-reply specifically: + * + * The number of elements added to the sorted sets, not including elements already existing for which the score was + * updated. + */ + Long zadd(K key, ZAddArgs zAddArgs, Object... scoresAndValues); + + /** + * ZADD acts like ZINCRBY + * + * @param key the key + * @param score the score + * @param member the member + * + * @return Long integer-reply specifically: + * + * The total number of elements changed + */ + Double zaddincr(K key, double score, V member); + /** * Get the number of members in a sorted set. * diff --git a/src/main/java/com/lambdaworks/redis/ZAddArgs.java b/src/main/java/com/lambdaworks/redis/ZAddArgs.java new file mode 100644 index 0000000000..41732ae4ba --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/ZAddArgs.java @@ -0,0 +1,65 @@ +package com.lambdaworks.redis; + +import com.lambdaworks.redis.protocol.CommandArgs; + +/** + * Argument list builder for the improved redis ZADD command starting from Redis + * 3.0.2. Static import the methods from {@link Builder} and call the methods: {@code xx()} or {@code nx()} . + * + * @author Mark Paluch + */ +public class ZAddArgs { + private boolean nx = false; + private boolean xx = false; + private boolean ch = false; + + public static class Builder { + /** + * Utility constructor. + */ + private Builder() { + + } + + public static ZAddArgs nx() { + return new ZAddArgs().nx(); + } + + public static ZAddArgs xx() { + return new ZAddArgs().xx(); + } + + public static ZAddArgs ch() { + return new ZAddArgs().ch(); + } + } + + private ZAddArgs nx() { + this.nx = true; + return this; + } + + private ZAddArgs ch() { + this.ch = true; + return this; + } + + private ZAddArgs xx() { + this.xx = true; + return this; + } + + public void build(CommandArgs args) { + if (nx) { + args.add("NX"); + } + + if (xx) { + args.add("XX"); + } + + if (ch) { + args.add("CH"); + } + } +} diff --git a/src/test/java/com/lambdaworks/redis/SortedSetCommandTest.java b/src/test/java/com/lambdaworks/redis/SortedSetCommandTest.java index f912a1ee37..29b19cdd0e 100644 --- a/src/test/java/com/lambdaworks/redis/SortedSetCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/SortedSetCommandTest.java @@ -29,6 +29,46 @@ public void zadd() throws Exception { assertEquals(list("a", "b", "c"), redis.zrange(key, 0, -1)); } + @Test + public void zaddnx() throws Exception { + assertEquals(1, (long) redis.zadd(key, 1.0, "a")); + assertEquals(0, (long) redis.zadd(key, ZAddArgs.Builder.nx(), 2.0, "a")); + + assertEquals(1, (long) redis.zadd(key, ZAddArgs.Builder.nx(), 2.0, "b")); + + assertEquals(svlist(sv(1.0, "a"), sv(2.0, "b")), redis.zrangeWithScores(key, 0, -1)); + } + + @Test + public void zaddxx() throws Exception { + assertEquals(1, (long) redis.zadd(key, 1.0, "a")); + assertEquals(0, (long) redis.zadd(key, ZAddArgs.Builder.xx(), 2.0, "a")); + + assertEquals(0, (long) redis.zadd(key, ZAddArgs.Builder.xx(), 2.0, "b")); + + assertEquals(svlist(sv(2.0, "a")), redis.zrangeWithScores(key, 0, -1)); + } + + @Test + public void zaddch() throws Exception { + assertEquals(1, (long) redis.zadd(key, 1.0, "a")); + assertEquals(1, (long) redis.zadd(key, ZAddArgs.Builder.ch(), 2.0, "a")); + + assertEquals(1, (long) redis.zadd(key, ZAddArgs.Builder.ch(), 2.0, "b")); + + assertEquals(svlist(sv(2.0, "a"), sv(2.0, "b")), redis.zrangeWithScores(key, 0, -1)); + } + + @Test + public void zaddincr() throws Exception { + assertEquals(1, redis.zadd(key, 1.0, "a").longValue()); + assertEquals(3, redis.zaddincr(key, 2.0, "a").longValue()); + + assertEquals(2, redis.zaddincr(key, 2.0, "b").longValue()); + + assertEquals(svlist(sv(2.0, "b"), sv(3.0, "a")), redis.zrangeWithScores(key, 0, -1)); + } + @Test public void zcard() throws Exception { assertEquals(0, (long) redis.zcard(key));