diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveListCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveListCommands.java index 3b28b1f03..c90b2b9a9 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveListCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveListCommands.java @@ -38,6 +38,7 @@ import org.springframework.util.ObjectUtils; /** * @author Christoph Strobl * @author Mark Paluch + * @author Michele Mancioppi * @since 2.0 */ class LettuceReactiveListCommands implements ReactiveListCommands { @@ -116,8 +117,8 @@ class LettuceReactiveListCommands implements ReactiveListCommands { Assert.notNull(command.getKey(), "Key must not be null!"); Assert.notNull(command.getRange(), "Range must not be null!"); - Flux result = cmd.lrange(command.getKey(), command.getRange().getLowerBound().getValue().orElse(null), - command.getRange().getUpperBound().getValue().orElse(null)); + Flux result = cmd.lrange(command.getKey(), command.getRange().getLowerBound().getValue().orElse(0L), + command.getRange().getUpperBound().getValue().orElse(Long.MAX_VALUE)); return Mono.just(new CommandResponse<>(command, result)); })); } @@ -135,8 +136,8 @@ class LettuceReactiveListCommands implements ReactiveListCommands { Assert.notNull(command.getRange(), "Range must not be null!"); return cmd - .ltrim(command.getKey(), command.getRange().getLowerBound().getValue().orElse(null), - command.getRange().getUpperBound().getValue().orElse(null)) + .ltrim(command.getKey(), command.getRange().getLowerBound().getValue().orElse(0L), + command.getRange().getUpperBound().getValue().orElse(Long.MAX_VALUE)) .map(LettuceConverters::stringToBoolean).map(value -> new BooleanResponse<>(command, value)); })); } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveStringCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveStringCommands.java index 312db4ad5..973232c30 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveStringCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveStringCommands.java @@ -40,6 +40,7 @@ import org.springframework.util.Assert; * @author Christoph Strobl * @author Mark Paluch * @author Jiahe Cai + * @author Michele Mancioppi * @since 2.0 */ class LettuceReactiveStringCommands implements ReactiveStringCommands { @@ -251,8 +252,8 @@ class LettuceReactiveStringCommands implements ReactiveStringCommands { Range range = command.getRange(); - return cmd.getrange(command.getKey(), range.getLowerBound().getValue().orElse(null), - range.getUpperBound().getValue().orElse(null)).map((value) -> new ByteBufferResponse<>(command, value)); + return cmd.getrange(command.getKey(), range.getLowerBound().getValue().orElse(0L), + range.getUpperBound().getValue().orElse(Long.MAX_VALUE)).map((value) -> new ByteBufferResponse<>(command, value)); })); } @@ -323,7 +324,7 @@ class LettuceReactiveStringCommands implements ReactiveStringCommands { Range range = command.getRange(); return (!Range.unbounded().equals(range) ? cmd.bitcount(command.getKey(), - range.getLowerBound().getValue().orElse(null), range.getUpperBound().getValue().orElse(null)) + range.getLowerBound().getValue().orElse(0L), range.getUpperBound().getValue().orElse(Long.MAX_VALUE)) : cmd.bitcount(command.getKey())).map(responseValue -> new NumericResponse<>(command, responseValue)); })); } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveZSetCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveZSetCommands.java index 3f9328d02..af2bc8d45 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveZSetCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveZSetCommands.java @@ -49,6 +49,7 @@ import org.springframework.util.StringUtils; /** * @author Christoph Strobl * @author Mark Paluch + * @author Michele Mancioppi * @since 2.0 */ class LettuceReactiveZSetCommands implements ReactiveZSetCommands { @@ -189,28 +190,28 @@ class LettuceReactiveZSetCommands implements ReactiveZSetCommands { if (command.isWithScores()) { result = cmd - .zrangeWithScores(command.getKey(), command.getRange().getLowerBound().getValue().orElse(null), - command.getRange().getUpperBound().getValue().orElse(null)) + .zrangeWithScores(command.getKey(), command.getRange().getLowerBound().getValue().orElse(0L), + command.getRange().getUpperBound().getValue().orElse(Long.MAX_VALUE)) .map(sc -> (Tuple) new DefaultTuple(getBytes(sc), sc.getScore())); } else { result = cmd - .zrange(command.getKey(), command.getRange().getLowerBound().getValue().orElse(null), - command.getRange().getUpperBound().getValue().orElse(null)) + .zrange(command.getKey(), command.getRange().getLowerBound().getValue().orElse(0L), + command.getRange().getUpperBound().getValue().orElse(Long.MAX_VALUE)) .map(value -> (Tuple) new DefaultTuple(ByteUtils.getBytes(value), Double.NaN)); } } else { if (command.isWithScores()) { result = cmd - .zrevrangeWithScores(command.getKey(), command.getRange().getLowerBound().getValue().orElse(null), - command.getRange().getUpperBound().getValue().orElse(null)) + .zrevrangeWithScores(command.getKey(), command.getRange().getLowerBound().getValue().orElse(0L), + command.getRange().getUpperBound().getValue().orElse(Long.MAX_VALUE)) .map(sc -> (Tuple) new DefaultTuple(getBytes(sc), sc.getScore())); } else { result = cmd - .zrevrange(command.getKey(), command.getRange().getLowerBound().getValue().orElse(null), - command.getRange().getUpperBound().getValue().orElse(null)) + .zrevrange(command.getKey(), command.getRange().getLowerBound().getValue().orElse(0L), + command.getRange().getUpperBound().getValue().orElse(Long.MAX_VALUE)) .map(value -> (Tuple) new DefaultTuple(ByteUtils.getBytes(value), Double.NaN)); } } @@ -377,8 +378,8 @@ class LettuceReactiveZSetCommands implements ReactiveZSetCommands { Assert.notNull(command.getRange(), "Range must not be null!"); return cmd - .zremrangebyrank(command.getKey(), command.getRange().getLowerBound().getValue().orElse(null), - command.getRange().getUpperBound().getValue().orElse(null)) + .zremrangebyrank(command.getKey(), command.getRange().getLowerBound().getValue().orElse(0L), + command.getRange().getUpperBound().getValue().orElse(Long.MAX_VALUE)) .map(value -> new NumericResponse<>(command, value)); })); } @@ -544,11 +545,14 @@ class LettuceReactiveZSetCommands implements ReactiveZSetCommands { Boolean upper) { return (source) -> { - Boolean inclusive = upper ? source.getUpperBound().isInclusive() : source.getLowerBound().isInclusive(); Object value = upper ? source.getUpperBound().getValue().orElse(null) : source.getLowerBound().getValue().orElse(null); + if (value == null) { + return Boundary.unbounded(); + } + if (value instanceof Number) { return inclusive ? Boundary.including((Number) value) : Boundary.excluding((Number) value); } diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveListCommandTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveListCommandTests.java index 36789d37e..ccea4c841 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveListCommandTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveListCommandTests.java @@ -21,24 +21,28 @@ import static org.hamcrest.core.IsEqual.*; import static org.hamcrest.core.IsNot.*; import static org.junit.Assert.*; import static org.junit.Assume.assumeThat; +import static org.springframework.data.domain.Range.Bound.*; import java.nio.ByteBuffer; import java.time.Duration; import java.util.Arrays; -import org.junit.Assume; import org.junit.Test; import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.data.domain.Range; import org.springframework.data.redis.connection.ReactiveListCommands.PopResult; import org.springframework.data.redis.connection.ReactiveListCommands.PushCommand; +import org.springframework.data.redis.connection.ReactiveRedisConnection; +import org.springframework.data.redis.connection.ReactiveRedisConnection.CommandResponse; +import org.springframework.data.redis.connection.ReactiveRedisConnection.RangeCommand; import org.springframework.data.redis.connection.RedisListCommands.Position; - -import org.springframework.data.redis.test.util.LettuceRedisClientProvider; import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; /** * @author Christoph Strobl * @author Mark Paluch + * @author Michele Mancioppi */ public class LettuceReactiveListCommandTests extends LettuceReactiveCommandsTestsBase { @@ -106,6 +110,32 @@ public class LettuceReactiveListCommandTests extends LettuceReactiveCommandsTest contains(VALUE_2_BBUFFER, VALUE_3_BBUFFER)); } + @Test // DATAREDIS-852 + public void lRangeShouldReturnValuesCorrectlyWithMinUnbounded() { + + nativeCommands.rpush(KEY_1, VALUE_1, VALUE_2, VALUE_3); + + RangeCommand rangeCommand = RangeCommand.key(KEY_1_BBUFFER).within(Range.of(unbounded(), inclusive(1L))); + + StepVerifier.create(connection.listCommands().lRange(Mono.just(rangeCommand)).flatMap(CommandResponse::getOutput)) // + .expectNext(VALUE_1_BBUFFER) + .expectNext(VALUE_2_BBUFFER) + .verifyComplete(); + } + + @Test // DATAREDIS-852 + public void lRangeShouldReturnValuesCorrectlyWithMaxUnbounded() { + + nativeCommands.rpush(KEY_1, VALUE_1, VALUE_2, VALUE_3); + + RangeCommand rangeCommand = RangeCommand.key(KEY_1_BBUFFER).within(Range.of(inclusive(1L), unbounded())); + + StepVerifier.create(connection.listCommands().lRange(Mono.just(rangeCommand)).flatMap(CommandResponse::getOutput)) // + .expectNext(VALUE_2_BBUFFER) + .expectNext(VALUE_3_BBUFFER) + .verifyComplete(); + } + @Test // DATAREDIS-525 public void lTrimShouldReturnValuesCorrectly() { @@ -115,6 +145,30 @@ public class LettuceReactiveListCommandTests extends LettuceReactiveCommandsTest assertThat(nativeCommands.lrange(KEY_1, 0, -1), not(contains(VALUE_1_BBUFFER))); } + @Test // DATAREDIS-852 + public void lTrimShouldReturnValuesCorrectlyWithMinUnbounded() { + + nativeCommands.rpush(KEY_1, VALUE_1, VALUE_2, VALUE_3); + + RangeCommand rangeCommand = RangeCommand.key(KEY_1_BBUFFER).within(Range.of(unbounded(), inclusive(1L))); + + StepVerifier.create(connection.listCommands().lTrim(Mono.just(rangeCommand))) // + .expectNext(new ReactiveRedisConnection.BooleanResponse<>(rangeCommand, true)) // + .verifyComplete(); + } + + @Test // DATAREDIS-852 + public void lTrimShouldReturnValuesCorrectlyWithMaxUnbounded() { + + nativeCommands.rpush(KEY_1, VALUE_1, VALUE_2, VALUE_3); + + RangeCommand rangeCommand = RangeCommand.key(KEY_1_BBUFFER).within(Range.of(inclusive(1L), unbounded())); + + StepVerifier.create(connection.listCommands().lTrim(Mono.just(rangeCommand))) // + .expectNext(new ReactiveRedisConnection.BooleanResponse<>(rangeCommand, true)) // + .verifyComplete(); + } + @Test // DATAREDIS-525 public void lIndexShouldReturnValueCorrectly() { diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveStringCommandsTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveStringCommandsTests.java index a32c0bce9..526bcd54c 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveStringCommandsTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveStringCommandsTests.java @@ -41,11 +41,14 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import org.junit.Test; +import org.springframework.data.domain.Range; import org.springframework.data.domain.Range.Bound; +import org.springframework.data.redis.connection.ReactiveRedisConnection; import org.springframework.data.redis.connection.ReactiveRedisConnection.ByteBufferResponse; import org.springframework.data.redis.connection.ReactiveRedisConnection.CommandResponse; import org.springframework.data.redis.connection.ReactiveRedisConnection.KeyCommand; import org.springframework.data.redis.connection.ReactiveRedisConnection.MultiValueResponse; +import org.springframework.data.redis.connection.ReactiveRedisConnection.RangeCommand; import org.springframework.data.redis.connection.ReactiveStringCommands.SetCommand; import org.springframework.data.redis.connection.RedisStringCommands.BitOperation; import org.springframework.data.redis.core.types.Expiration; @@ -55,6 +58,7 @@ import org.springframework.data.redis.util.ByteUtils; /** * @author Christoph Strobl * @author Mark Paluch + * @author Michele Mancioppi */ public class LettuceReactiveStringCommandsTests extends LettuceReactiveCommandsTestsBase { @@ -295,6 +299,30 @@ public class LettuceReactiveStringCommandsTests extends LettuceReactiveCommandsT .verifyComplete(); } + @Test // DATAREDIS-525 + public void getRangeShouldReturnSubstringCorrectlyWithMinUnbound() { + + nativeCommands.set(KEY_1, VALUE_1); + + RangeCommand rangeCommand = RangeCommand.key(KEY_1_BBUFFER).within(Range.of(Bound.unbounded(), Bound.inclusive(2L))); + + StepVerifier.create(connection.stringCommands().getRange(Mono.just(rangeCommand))) // + .expectNext(new ReactiveRedisConnection.ByteBufferResponse<>(rangeCommand, ByteBuffer.wrap("val".getBytes()))) + .verifyComplete(); + } + + @Test // DATAREDIS-525 + public void getRangeShouldReturnSubstringCorrectlyWithMaxUnbound() { + + nativeCommands.set(KEY_1, VALUE_1); + + RangeCommand rangeCommand = RangeCommand.key(KEY_1_BBUFFER).within(Range.of(Bound.inclusive(0L), Bound.unbounded())); + + StepVerifier.create(connection.stringCommands().getRange(Mono.just(rangeCommand))) // + .expectNext(new ReactiveRedisConnection.ByteBufferResponse<>(rangeCommand, ByteBuffer.wrap(VALUE_1.getBytes()))) + .verifyComplete(); + } + @Test // DATAREDIS-525 public void setRangeShouldReturnNewStringLengthCorrectly() { diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveZSetCommandsTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveZSetCommandsTests.java index 35feaafea..24ab322a6 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveZSetCommandsTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveZSetCommandsTests.java @@ -35,6 +35,7 @@ import org.springframework.data.redis.core.ScanOptions; * * @author Christoph Strobl * @author Mark Paluch + * @author Michele Mancioppi */ public class LettuceReactiveZSetCommandsTests extends LettuceReactiveCommandsTestsBase { @@ -142,6 +143,32 @@ public class LettuceReactiveZSetCommandsTests extends LettuceReactiveCommandsTes .verifyComplete(); } + @Test // DATAREDIS-852 + public void zRangeByScoreShouldReturnValuesCorrectlyWithMinUnbounded() { + + nativeCommands.zadd(KEY_1, 1D, VALUE_1); + nativeCommands.zadd(KEY_1, 2D, VALUE_2); + nativeCommands.zadd(KEY_1, 3D, VALUE_3); + + StepVerifier.create(connection.zSetCommands().zRangeByScore(KEY_1_BBUFFER, Range.of(Range.Bound.unbounded(), + Range.Bound.inclusive(3D)))) // + .expectNext(VALUE_1_BBUFFER, VALUE_2_BBUFFER, VALUE_3_BBUFFER) // + .verifyComplete(); + } + + @Test // DATAREDIS-852 + public void zRangeByScoreShouldReturnValuesCorrectlyWithMaxUnbounded() { + + nativeCommands.zadd(KEY_1, 1D, VALUE_1); + nativeCommands.zadd(KEY_1, 2D, VALUE_2); + nativeCommands.zadd(KEY_1, 3D, VALUE_3); + + StepVerifier.create(connection.zSetCommands().zRangeByScore(KEY_1_BBUFFER, Range.of(Range.Bound.inclusive(0D), + Range.Bound.unbounded()))) // + .expectNext(VALUE_1_BBUFFER, VALUE_2_BBUFFER, VALUE_3_BBUFFER) // + .verifyComplete(); + } + @Test // DATAREDIS-525 public void zRangeByScoreShouldReturnValuesCorrectlyWithMinExclusion() {