diff --git a/src/main/java/org/springframework/data/redis/connection/ReactiveNumberCommands.java b/src/main/java/org/springframework/data/redis/connection/ReactiveNumberCommands.java index a72fb9ee6..a00734041 100644 --- a/src/main/java/org/springframework/data/redis/connection/ReactiveNumberCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/ReactiveNumberCommands.java @@ -117,6 +117,7 @@ public interface ReactiveNumberCommands { * @param value must not be {@literal null}. * @return * @see Redis Documentation: INCRBY + * @see Redis Documentation: INCRBYFLOAT */ default Mono incrBy(ByteBuffer key, T value) { @@ -132,6 +133,7 @@ public interface ReactiveNumberCommands { * @param commands must not be {@literal null}. * @return * @see Redis Documentation: INCRBY + * @see Redis Documentation: INCRBYFLOAT */ Flux, T>> incrBy( Publisher> commands); diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveNumberCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveNumberCommands.java index bb011b8c4..29878ffcb 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveNumberCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveNumberCommands.java @@ -75,7 +75,7 @@ class LettuceReactiveNumberCommands implements ReactiveNumberCommands { T incrBy = command.getValue(); - Mono result = null; + Mono result; if (incrBy instanceof Double || incrBy instanceof Float) { result = cmd.incrbyfloat(command.getKey(), incrBy.doubleValue()); } else { diff --git a/src/main/java/org/springframework/data/redis/core/BoundValueOperations.java b/src/main/java/org/springframework/data/redis/core/BoundValueOperations.java index 85895bd5d..207f2bf6f 100644 --- a/src/main/java/org/springframework/data/redis/core/BoundValueOperations.java +++ b/src/main/java/org/springframework/data/redis/core/BoundValueOperations.java @@ -87,12 +87,23 @@ public interface BoundValueOperations extends BoundKeyOperations { @Nullable V getAndSet(V value); + /** + * Increment an integer value stored as string value under the bound key by one. + * + * @param delta + * @return {@literal null} when used in pipeline / transaction. + * @since 2.1 + * @see Redis Documentation: INCR + */ + @Nullable + Long increment(); + /** * Increment an integer value stored as string value under the bound key by {@code delta}. * * @param delta * @return {@literal null} when used in pipeline / transaction. - * @see Redis Documentation: INCR + * @see Redis Documentation: INCRBY */ @Nullable Long increment(long delta); @@ -107,6 +118,27 @@ public interface BoundValueOperations extends BoundKeyOperations { @Nullable Double increment(double delta); + /** + * Decrement an integer value stored as string value under the bound key by one. + * + * @return {@literal null} when used in pipeline / transaction. + * @since 2.1 + * @see Redis Documentation: DECR + */ + @Nullable + Long decrement(); + + /** + * Decrement an integer value stored as string value under the bound key by {@code delta}. + * + * @param delta + * @return {@literal null} when used in pipeline / transaction. + * @since 2.1 + * @see Redis Documentation: DECRBY + */ + @Nullable + Long decrement(long delta); + /** * Append a {@code value} to the bound key. * diff --git a/src/main/java/org/springframework/data/redis/core/DefaultBoundValueOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultBoundValueOperations.java index 426decabe..31af095d3 100644 --- a/src/main/java/org/springframework/data/redis/core/DefaultBoundValueOperations.java +++ b/src/main/java/org/springframework/data/redis/core/DefaultBoundValueOperations.java @@ -22,6 +22,7 @@ import org.springframework.data.redis.connection.DataType; /** * @author Costin Leau * @author Jiahe Cai + * @author Mark Paluch */ class DefaultBoundValueOperations extends DefaultBoundKeyOperations implements BoundValueOperations { @@ -57,6 +58,15 @@ class DefaultBoundValueOperations extends DefaultBoundKeyOperations imp return ops.getAndSet(getKey(), value); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundValueOperations#increment() + */ + @Override + public Long increment() { + return ops.increment(getKey()); + } + /* * (non-Javadoc) * @see org.springframework.data.redis.core.BoundValueOperations#increment(long) @@ -75,6 +85,24 @@ class DefaultBoundValueOperations extends DefaultBoundKeyOperations imp return ops.increment(getKey(), delta); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundValueOperations#decrement() + */ + @Override + public Long decrement() { + return ops.decrement(getKey()); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundValueOperations#decrement(double) + */ + @Override + public Long decrement(long delta) { + return ops.decrement(getKey(), delta); + } + /* * (non-Javadoc) * @see org.springframework.data.redis.core.BoundValueOperations#append(java.lang.String) diff --git a/src/main/java/org/springframework/data/redis/core/DefaultReactiveValueOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultReactiveValueOperations.java index a50a247fc..f45cb615d 100644 --- a/src/main/java/org/springframework/data/redis/core/DefaultReactiveValueOperations.java +++ b/src/main/java/org/springframework/data/redis/core/DefaultReactiveValueOperations.java @@ -194,6 +194,61 @@ class DefaultReactiveValueOperations implements ReactiveValueOperations increment(K key) { + + Assert.notNull(key, "Key must not be null!"); + + return template.createMono(connection -> connection.numberCommands().incr(rawKey(key))); + } + + /* (non-Javadoc) + * @see org.springframework.data.redis.core.ReactiveValueOperations#increment(java.lang.Object, long) + */ + @Override + public Mono increment(K key, long delta) { + + Assert.notNull(key, "Key must not be null!"); + + return template.createMono(connection -> connection.numberCommands().incrBy(rawKey(key), delta)); + } + + /* (non-Javadoc) + * @see org.springframework.data.redis.core.ReactiveValueOperations#increment(java.lang.Object, double) + */ + @Override + public Mono increment(K key, double delta) { + + Assert.notNull(key, "Key must not be null!"); + + return template.createMono(connection -> connection.numberCommands().incrBy(rawKey(key), delta)); + } + + /* (non-Javadoc) + * @see org.springframework.data.redis.core.ReactiveValueOperations#decrement(java.lang.Object) + */ + @Override + public Mono decrement(K key) { + + Assert.notNull(key, "Key must not be null!"); + + return template.createMono(connection -> connection.numberCommands().decr(rawKey(key))); + } + + /* (non-Javadoc) + * @see org.springframework.data.redis.core.ReactiveValueOperations#decrement(java.lang.Object, long) + */ + @Override + public Mono decrement(K key, long delta) { + + Assert.notNull(key, "Key must not be null!"); + + return template.createMono(connection -> connection.numberCommands().decrBy(rawKey(key), delta)); + } + /* (non-Javadoc) * @see org.springframework.data.redis.core.ReactiveValueOperations#append(java.lang.Object, java.lang.String) */ @@ -273,61 +328,6 @@ class DefaultReactiveValueOperations implements ReactiveValueOperations connection.keyCommands().del(rawKey(key))).map(l -> l != 0); } - - /* (non-Javadoc) - * @see org.springframework.data.redis.core.ReactiveValueOperations#increment(java.lang.Object) - */ - @Override - public Mono increment(K key) { - - Assert.notNull(key, "Key must not be null!"); - - return incrementBy(key, 1L); - } - - /* (non-Javadoc) - * @see org.springframework.data.redis.core.ReactiveValueOperations#incrementBy(java.lang.Object, long) - */ - @Override - public Mono incrementBy(K key, long delta) { - - Assert.notNull(key, "Key must not be null!"); - - return template.createMono(connection -> connection.numberCommands().incrBy(rawKey(key), delta)); - } - - /* (non-Javadoc) - * @see org.springframework.data.redis.core.ReactiveValueOperations#incrementBy(java.lang.Object, double) - */ - @Override - public Mono incrementBy(K key, double delta) { - - Assert.notNull(key, "Key must not be null!"); - - return template.createMono(connection -> connection.numberCommands().incrBy(rawKey(key), delta)); - } - - /* (non-Javadoc) - * @see org.springframework.data.redis.core.ReactiveValueOperations#decrement(java.lang.Object) - */ - @Override - public Mono decrement(K key) { - - Assert.notNull(key, "Key must not be null!"); - - return incrementBy(key, -1L); - } - - /* (non-Javadoc) - * @see org.springframework.data.redis.core.ReactiveValueOperations#decrementBy(java.lang.Object, long) - */ - @Override - public Mono decrementBy(K key, long delta) { - - Assert.notNull(key, "Key must not be null!"); - - return incrementBy(key, -delta); - } private Mono createMono(Function> function) { diff --git a/src/main/java/org/springframework/data/redis/core/DefaultValueOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultValueOperations.java index 69b66a716..6e0912a91 100644 --- a/src/main/java/org/springframework/data/redis/core/DefaultValueOperations.java +++ b/src/main/java/org/springframework/data/redis/core/DefaultValueOperations.java @@ -74,6 +74,17 @@ class DefaultValueOperations extends AbstractOperations implements V }, true); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.ValueOperations#increment(java.lang.Object) + */ + @Override + public Long increment(K key) { + + byte[] rawKey = rawKey(key); + return execute(connection -> connection.incr(rawKey), true); + } + /* * (non-Javadoc) * @see org.springframework.data.redis.core.ValueOperations#increment(java.lang.Object, long) @@ -96,6 +107,28 @@ class DefaultValueOperations extends AbstractOperations implements V return execute(connection -> connection.incrBy(rawKey, delta), true); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.ValueOperations#decrement(java.lang.Object) + */ + @Override + public Long decrement(K key) { + + byte[] rawKey = rawKey(key); + return execute(connection -> connection.decr(rawKey), true); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.ValueOperations#increment(java.lang.Object, long) + */ + @Override + public Long decrement(K key, long delta) { + + byte[] rawKey = rawKey(key); + return execute(connection -> connection.decrBy(rawKey, delta), true); + } + /* * (non-Javadoc) * @see org.springframework.data.redis.core.ValueOperations#append(java.lang.Object, java.lang.String) diff --git a/src/main/java/org/springframework/data/redis/core/ReactiveValueOperations.java b/src/main/java/org/springframework/data/redis/core/ReactiveValueOperations.java index 416d12d3e..63a1dcf22 100644 --- a/src/main/java/org/springframework/data/redis/core/ReactiveValueOperations.java +++ b/src/main/java/org/springframework/data/redis/core/ReactiveValueOperations.java @@ -131,6 +131,54 @@ public interface ReactiveValueOperations { */ Mono> multiGet(Collection keys); + /** + * Increments the number stored at {@code key} by one. + * + * @param key must not be {@literal null}. + * @since 2.1 + * @see Redis Documentation: INCR + */ + Mono increment(K key); + + /** + * Increments the number stored at {@code key} by {@code delta}. + * + * @param key must not be {@literal null}. + * @param delta + * @since 2.1 + * @see Redis Documentation: INCRBY + */ + Mono increment(K key, long delta); + + /** + * Increment the string representing a floating point number stored at {@code key} by {@code delta}. + * + * @param key must not be {@literal null}. + * @param delta + * @since 2.1 + * @see Redis Documentation: INCRBYFLOAT + */ + Mono increment(K key, double delta); + + /** + * Decrements the number stored at {@code key} by one. + * + * @param key must not be {@literal null}. + * @since 2.1 + * @see Redis Documentation: DECR + */ + Mono decrement(K key); + + /** + * Decrements the number stored at {@code key} by {@code delta}. + * + * @param key must not be {@literal null}. + * @param delta + * @since 2.1 + * @see Redis Documentation: DECRBY + */ + Mono decrement(K key, long delta); + /** * Append a {@code value} to {@code key}. * @@ -183,7 +231,7 @@ public interface ReactiveValueOperations { * * @param key must not be {@literal null}. * @param offset - * @see Redis Documentation: GETBIT + * @see Redis Documentation: GETBIT */ Mono getBit(K key, long offset); @@ -193,44 +241,4 @@ public interface ReactiveValueOperations { * @param key must not be {@literal null}. */ Mono delete(K key); - - /** - * Increments the number stored at {@code key} by one. - * - * @param key must not be {@literal null}. - * @see Redis Documentation: INCR - */ - Mono increment(K key); - - /** - * Increments the number stored at {@code key} by {@code delta}. - * @param key must not be {@literal null}. - * @param delta - * @see Redis Documentation: INCRBY - */ - Mono incrementBy(K key, long delta); - - /** - * Increment the string representing a floating point number stored at {@code key} by {@code delta}. - * @param key must not be {@literal null}. - * @param delta - * @see Redis Documentation: INCRBYFLOAT - */ - Mono incrementBy(K key, double delta); - - /** - * Decrements the number stored at {@code key} by one. - * - * @param key must not be {@literal null}. - * @see Redis Documentation: DECR - */ - Mono decrement(K key); - - /** - * Decrements the number stored at {@code key} by {@code delta}. - * @param key must not be {@literal null}. - * @param delta - * @see Redis Documentation: DECRBY - */ - Mono decrementBy(K key, long delta); } diff --git a/src/main/java/org/springframework/data/redis/core/ValueOperations.java b/src/main/java/org/springframework/data/redis/core/ValueOperations.java index 853639931..93e83b70a 100644 --- a/src/main/java/org/springframework/data/redis/core/ValueOperations.java +++ b/src/main/java/org/springframework/data/redis/core/ValueOperations.java @@ -126,13 +126,24 @@ public interface ValueOperations { @Nullable List multiGet(Collection keys); + /** + * Increment an integer value stored as string value under {@code key} by one. + * + * @param key must not be {@literal null}. + * @return {@literal null} when used in pipeline / transaction. + * @since 2.1 + * @see Redis Documentation: INCR + */ + @Nullable + Long increment(K key); + /** * Increment an integer value stored as string value under {@code key} by {@code delta}. * * @param key must not be {@literal null}. * @param delta * @return {@literal null} when used in pipeline / transaction. - * @see Redis Documentation: INCR + * @see Redis Documentation: INCRBY */ @Nullable Long increment(K key, long delta); @@ -148,6 +159,29 @@ public interface ValueOperations { @Nullable Double increment(K key, double delta); + /** + * Decrement an integer value stored as string value under {@code key} by one. + * + * @param key must not be {@literal null}. + * @return {@literal null} when used in pipeline / transaction. + * @since 2.1 + * @see Redis Documentation: DECR + */ + @Nullable + Long decrement(K key); + + /** + * Decrement an integer value stored as string value under {@code key} by {@code delta}. + * + * @param key must not be {@literal null}. + * @param delta + * @return {@literal null} when used in pipeline / transaction. + * @since 2.1 + * @see Redis Documentation: DECRBY + */ + @Nullable + Long decrement(K key, long delta); + /** * Append a {@code value} to {@code key}. * diff --git a/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicInteger.java b/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicInteger.java index 64fb35ecd..8844a68be 100644 --- a/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicInteger.java +++ b/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicInteger.java @@ -30,7 +30,6 @@ import org.springframework.data.redis.core.SessionCallback; import org.springframework.data.redis.core.ValueOperations; import org.springframework.data.redis.serializer.GenericToStringSerializer; import org.springframework.data.redis.serializer.RedisSerializer; -import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -245,7 +244,7 @@ public class RedisAtomicInteger extends Number implements Serializable, BoundKey * @return the updated value. */ public int incrementAndGet() { - return operations.increment(key, 1).intValue(); + return operations.increment(key).intValue(); } /** @@ -254,7 +253,7 @@ public class RedisAtomicInteger extends Number implements Serializable, BoundKey * @return the updated value. */ public int decrementAndGet() { - return operations.increment(key, -1).intValue(); + return operations.decrement(key).intValue(); } /** diff --git a/src/test/java/org/springframework/data/redis/core/DefaultReactiveValueOperationsIntegrationTests.java b/src/test/java/org/springframework/data/redis/core/DefaultReactiveValueOperationsIntegrationTests.java index 6fe76c079..669d383eb 100644 --- a/src/test/java/org/springframework/data/redis/core/DefaultReactiveValueOperationsIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/core/DefaultReactiveValueOperationsIntegrationTests.java @@ -384,7 +384,7 @@ public class DefaultReactiveValueOperationsIntegrationTests { StepVerifier.create(valueOperations.size(key)).expectNext(0L).verifyComplete(); } - + @Test // DATAREDIS-784 public void increment() { @@ -400,11 +400,11 @@ public class DefaultReactiveValueOperationsIntegrationTests { K key = keyFactory.instance(); - StepVerifier.create(valueOperations.incrementBy(key, 2L)).expectNext(2L).verifyComplete(); + StepVerifier.create(valueOperations.increment(key, 2L)).expectNext(2L).verifyComplete(); - StepVerifier.create(valueOperations.incrementBy(key, -3L)).expectNext(-1L).verifyComplete(); + StepVerifier.create(valueOperations.increment(key, -3L)).expectNext(-1L).verifyComplete(); - StepVerifier.create(valueOperations.incrementBy(key, 1L)).expectNext(0L).verifyComplete(); + StepVerifier.create(valueOperations.increment(key, 1L)).expectNext(0L).verifyComplete(); } @Test // DATAREDIS-784 @@ -412,11 +412,11 @@ public class DefaultReactiveValueOperationsIntegrationTests { K key = keyFactory.instance(); - StepVerifier.create(valueOperations.incrementBy(key, 0.1)).expectNext(0.1).verifyComplete(); + StepVerifier.create(valueOperations.increment(key, 0.1)).expectNext(0.1).verifyComplete(); - StepVerifier.create(valueOperations.incrementBy(key, -0.3)).expectNext(-0.2).verifyComplete(); + StepVerifier.create(valueOperations.increment(key, -0.3)).expectNext(-0.2).verifyComplete(); - StepVerifier.create(valueOperations.incrementBy(key, 0.2)).expectNext(0.0).verifyComplete(); + StepVerifier.create(valueOperations.increment(key, 0.2)).expectNext(0.0).verifyComplete(); } @Test // DATAREDIS-784 @@ -434,10 +434,10 @@ public class DefaultReactiveValueOperationsIntegrationTests { K key = keyFactory.instance(); - StepVerifier.create(valueOperations.decrementBy(key, 2L)).expectNext(-2L).verifyComplete(); + StepVerifier.create(valueOperations.decrement(key, 2L)).expectNext(-2L).verifyComplete(); - StepVerifier.create(valueOperations.decrementBy(key, -3L)).expectNext(1L).verifyComplete(); + StepVerifier.create(valueOperations.decrement(key, -3L)).expectNext(1L).verifyComplete(); - StepVerifier.create(valueOperations.decrementBy(key, 1L)).expectNext(0L).verifyComplete(); + StepVerifier.create(valueOperations.decrement(key, 1L)).expectNext(0L).verifyComplete(); } } diff --git a/src/test/java/org/springframework/data/redis/core/DefaultValueOperationsTests.java b/src/test/java/org/springframework/data/redis/core/DefaultValueOperationsTests.java index d2d7c1e6f..5659e439c 100644 --- a/src/test/java/org/springframework/data/redis/core/DefaultValueOperationsTests.java +++ b/src/test/java/org/springframework/data/redis/core/DefaultValueOperationsTests.java @@ -49,6 +49,7 @@ import org.springframework.data.redis.RedisTestProfileValueSource; * @author David Liu * @author Thomas Darimont * @author Jiahe Cai + * @author Mark Paluch */ @RunWith(Parameterized.class) public class DefaultValueOperationsTests { @@ -94,8 +95,18 @@ public class DefaultValueOperationsTests { }); } + @Test // DATAREDIS-784 + public void testIncrement() { + K key = keyFactory.instance(); + V v1 = valueFactory.instance(); + assumeTrue(v1 instanceof Long); + valueOps.set(key, v1); + assertEquals(Long.valueOf((Long) v1 + 1), valueOps.increment(key)); + assertEquals(Long.valueOf((Long) v1 + 1), valueOps.get(key)); + } + @Test - public void testIncrementLong() throws Exception { + public void testIncrementLong() { K key = keyFactory.instance(); V v1 = valueFactory.instance(); assumeTrue(v1 instanceof Long); @@ -122,6 +133,26 @@ public class DefaultValueOperationsTests { assertEquals(Double.valueOf(twoDForm.format((Double) v1 + 1.4 - 10d)), valueOps.get(key)); } + @Test // DATAREDIS-784 + public void testDecrement() { + K key = keyFactory.instance(); + V v1 = valueFactory.instance(); + assumeTrue(v1 instanceof Long); + valueOps.set(key, v1); + assertEquals(Long.valueOf((Long) v1 - 1), valueOps.decrement(key)); + assertEquals(Long.valueOf((Long) v1 - 1), valueOps.get(key)); + } + + @Test // DATAREDIS-784 + public void testDecrementByLong() { + K key = keyFactory.instance(); + V v1 = valueFactory.instance(); + assumeTrue(v1 instanceof Long); + valueOps.set(key, v1); + assertEquals(Long.valueOf((Long) v1 - 5), valueOps.decrement(key, 5)); + assertEquals(Long.valueOf((Long) v1 - 5), valueOps.get(key)); + } + @Test public void testMultiSetIfAbsent() { Map keysAndValues = new HashMap<>();