DATAREDIS-852 - Polishing.
Refactor lower/upper bound retrieval into LettuceConverters for a consistent lower/upper boundary return value. Use minus one (-1) as the upper bound index to always retrieve the last element if the upper boundary is not bounded. Original pull request: #353.
This commit is contained in:
@@ -113,6 +113,9 @@ abstract public class LettuceConverters extends Converters {
|
||||
public static final byte[] POSITIVE_INFINITY_BYTES;
|
||||
public static final byte[] NEGATIVE_INFINITY_BYTES;
|
||||
|
||||
private static final long INDEXED_RANGE_START = 0;
|
||||
private static final long INDEXED_RANGE_END = -1;
|
||||
|
||||
static {
|
||||
|
||||
DATE_TO_LONG = source -> source != null ? source.getTime() : null;
|
||||
@@ -962,6 +965,54 @@ abstract public class LettuceConverters extends Converters {
|
||||
return TRANSACTION_RESULT_UNWRAPPER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@link Optional} lower bound from {@link Range}.
|
||||
*
|
||||
* @param range
|
||||
* @param <T>
|
||||
* @return
|
||||
* @since 2.0.9
|
||||
*/
|
||||
static <T extends Comparable<T>> Optional<T> getLowerBound(org.springframework.data.domain.Range<T> range) {
|
||||
return range.getLowerBound().getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@link Optional} upper bound from {@link Range}.
|
||||
*
|
||||
* @param range
|
||||
* @param <T>
|
||||
* @return
|
||||
* @since 2.0.9
|
||||
*/
|
||||
static <T extends Comparable<T>> Optional<T> getUpperBound(org.springframework.data.domain.Range<T> range) {
|
||||
return range.getUpperBound().getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the lower bound index from {@link Range} or {@literal 0} (zero) if the lower range is not bounded to point
|
||||
* to the first element. To be used with index-based commands such as {@code LRANGE}, {@code GETRANGE}.
|
||||
*
|
||||
* @param range
|
||||
* @return the lower index bound value or {@literal 0} for the first element if not bounded.
|
||||
* @since 2.0.9
|
||||
*/
|
||||
static long getLowerBoundIndex(org.springframework.data.domain.Range<Long> range) {
|
||||
return getLowerBound(range).orElse(INDEXED_RANGE_START);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the upper bound index from {@link Range} or {@literal -1} (minus one) if the upper range is not bounded to
|
||||
* point to the last element. To be used with index-based commands such as {@code LRANGE}, {@code GETRANGE}.
|
||||
*
|
||||
* @param range
|
||||
* @return the upper index bound value or {@literal -1} for the last element if not bounded.
|
||||
* @since 2.0.9
|
||||
*/
|
||||
static long getUpperBoundIndex(org.springframework.data.domain.Range<Long> range) {
|
||||
return getUpperBound(range).orElse(INDEXED_RANGE_END);
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 1.8
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.util.Arrays;
|
||||
|
||||
import org.reactivestreams.Publisher;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.domain.Range;
|
||||
import org.springframework.data.redis.connection.ReactiveListCommands;
|
||||
import org.springframework.data.redis.connection.ReactiveRedisConnection.BooleanResponse;
|
||||
import org.springframework.data.redis.connection.ReactiveRedisConnection.ByteBufferResponse;
|
||||
@@ -74,7 +75,7 @@ class LettuceReactiveListCommands implements ReactiveListCommands {
|
||||
String.format("%s PUSHX only allows one value!", command.getDirection()));
|
||||
}
|
||||
|
||||
Mono<Long> pushResult = null;
|
||||
Mono<Long> pushResult;
|
||||
|
||||
if (ObjectUtils.nullSafeEquals(Direction.RIGHT, command.getDirection())) {
|
||||
pushResult = command.getUpsert()
|
||||
@@ -117,8 +118,12 @@ class LettuceReactiveListCommands implements ReactiveListCommands {
|
||||
Assert.notNull(command.getKey(), "Key must not be null!");
|
||||
Assert.notNull(command.getRange(), "Range must not be null!");
|
||||
|
||||
Flux<ByteBuffer> result = cmd.lrange(command.getKey(), command.getRange().getLowerBound().getValue().orElse(0L),
|
||||
command.getRange().getUpperBound().getValue().orElse(Long.MAX_VALUE));
|
||||
Range<Long> range = command.getRange();
|
||||
|
||||
Flux<ByteBuffer> result = cmd.lrange(command.getKey(), //
|
||||
LettuceConverters.getLowerBoundIndex(range), //
|
||||
LettuceConverters.getUpperBoundIndex(range));
|
||||
|
||||
return Mono.just(new CommandResponse<>(command, result));
|
||||
}));
|
||||
}
|
||||
@@ -135,9 +140,13 @@ class LettuceReactiveListCommands implements ReactiveListCommands {
|
||||
Assert.notNull(command.getKey(), "Key must not be null!");
|
||||
Assert.notNull(command.getRange(), "Range must not be null!");
|
||||
|
||||
return cmd
|
||||
.ltrim(command.getKey(), command.getRange().getLowerBound().getValue().orElse(0L),
|
||||
command.getRange().getUpperBound().getValue().orElse(Long.MAX_VALUE))
|
||||
Range<Long> range = command.getRange();
|
||||
|
||||
Mono<String> result = cmd.ltrim(command.getKey(), //
|
||||
LettuceConverters.getLowerBoundIndex(range), //
|
||||
LettuceConverters.getUpperBoundIndex(range));
|
||||
|
||||
return result
|
||||
.map(LettuceConverters::stringToBoolean).map(value -> new BooleanResponse<>(command, value));
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -45,7 +45,8 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
class LettuceReactiveStringCommands implements ReactiveStringCommands {
|
||||
|
||||
private final static ByteBuffer EMPTY_BYTE_BUFFER = ByteBuffer.wrap(new byte[0]);
|
||||
private static final ByteBuffer EMPTY_BYTE_BUFFER = ByteBuffer.wrap(new byte[0]);
|
||||
|
||||
private final LettuceReactiveRedisConnection connection;
|
||||
|
||||
/**
|
||||
@@ -115,7 +116,7 @@ class LettuceReactiveStringCommands implements ReactiveStringCommands {
|
||||
Assert.notNull(command.getValue(), "Value must not be null!");
|
||||
|
||||
if (command.getExpiration().isPresent() || command.getOption().isPresent()) {
|
||||
throw new IllegalArgumentException("Command must not define exipiration nor option for GETSET.");
|
||||
throw new IllegalArgumentException("Command must not define expiration nor option for GETSET.");
|
||||
}
|
||||
|
||||
return cmd.getset(command.getKey(), command.getValue()).map((value) -> new ByteBufferResponse<>(command, value))
|
||||
@@ -252,8 +253,11 @@ class LettuceReactiveStringCommands implements ReactiveStringCommands {
|
||||
|
||||
Range<Long> range = command.getRange();
|
||||
|
||||
return cmd.getrange(command.getKey(), range.getLowerBound().getValue().orElse(0L),
|
||||
range.getUpperBound().getValue().orElse(Long.MAX_VALUE)).map((value) -> new ByteBufferResponse<>(command, value));
|
||||
Mono<ByteBuffer> result = cmd.getrange(command.getKey(), //
|
||||
LettuceConverters.getLowerBoundIndex(range), //
|
||||
LettuceConverters.getUpperBoundIndex(range));
|
||||
|
||||
return result.map((value) -> new ByteBufferResponse<>(command, value));
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -324,7 +328,8 @@ class LettuceReactiveStringCommands implements ReactiveStringCommands {
|
||||
Range<Long> range = command.getRange();
|
||||
|
||||
return (!Range.unbounded().equals(range) ? cmd.bitcount(command.getKey(),
|
||||
range.getLowerBound().getValue().orElse(0L), range.getUpperBound().getValue().orElse(Long.MAX_VALUE))
|
||||
LettuceConverters.getLowerBoundIndex(range), //
|
||||
LettuceConverters.getUpperBoundIndex(range)) //
|
||||
: cmd.bitcount(command.getKey())).map(responseValue -> new NumericResponse<>(command, responseValue));
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -186,33 +186,31 @@ class LettuceReactiveZSetCommands implements ReactiveZSetCommands {
|
||||
|
||||
Flux<Tuple> result;
|
||||
|
||||
long start = LettuceConverters.getLowerBoundIndex(command.getRange());
|
||||
long stop = LettuceConverters.getUpperBoundIndex(command.getRange());
|
||||
|
||||
if (ObjectUtils.nullSafeEquals(command.getDirection(), Direction.ASC)) {
|
||||
if (command.isWithScores()) {
|
||||
|
||||
result = cmd
|
||||
.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()));
|
||||
.zrangeWithScores(command.getKey(), start, stop).map(sc -> new DefaultTuple(getBytes(sc), sc.getScore()));
|
||||
} else {
|
||||
|
||||
result = cmd
|
||||
.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));
|
||||
.zrange(command.getKey(), start, stop)
|
||||
.map(value -> new DefaultTuple(ByteUtils.getBytes(value), Double.NaN));
|
||||
}
|
||||
} else {
|
||||
if (command.isWithScores()) {
|
||||
|
||||
result = cmd
|
||||
.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()));
|
||||
.zrevrangeWithScores(command.getKey(), start, stop)
|
||||
.map(sc -> new DefaultTuple(getBytes(sc), sc.getScore()));
|
||||
} else {
|
||||
|
||||
result = cmd
|
||||
.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));
|
||||
.zrevrange(command.getKey(), start, stop)
|
||||
.map(value -> new DefaultTuple(ByteUtils.getBytes(value), Double.NaN));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,21 +243,21 @@ class LettuceReactiveZSetCommands implements ReactiveZSetCommands {
|
||||
|
||||
if (!isLimited) {
|
||||
result = cmd.zrangebyscoreWithScores(command.getKey(), range)
|
||||
.map(sc -> (Tuple) new DefaultTuple(ByteUtils.getBytes(sc.getValue()), sc.getScore()));
|
||||
.map(sc -> new DefaultTuple(ByteUtils.getBytes(sc.getValue()), sc.getScore()));
|
||||
} else {
|
||||
result = cmd
|
||||
.zrangebyscoreWithScores(command.getKey(), range, LettuceConverters.toLimit(command.getLimit().get()))
|
||||
.map(sc -> (Tuple) new DefaultTuple(ByteUtils.getBytes(sc.getValue()), sc.getScore()));
|
||||
.map(sc -> new DefaultTuple(ByteUtils.getBytes(sc.getValue()), sc.getScore()));
|
||||
}
|
||||
} else {
|
||||
|
||||
if (!isLimited) {
|
||||
result = cmd.zrangebyscore(command.getKey(), range)
|
||||
.map(value -> (Tuple) new DefaultTuple(ByteUtils.getBytes(value), Double.NaN));
|
||||
.map(value -> new DefaultTuple(ByteUtils.getBytes(value), Double.NaN));
|
||||
} else {
|
||||
|
||||
result = cmd.zrangebyscore(command.getKey(), range, LettuceConverters.toLimit(command.getLimit().get()))
|
||||
.map(value -> (Tuple) new DefaultTuple(ByteUtils.getBytes(value), Double.NaN));
|
||||
.map(value -> new DefaultTuple(ByteUtils.getBytes(value), Double.NaN));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -270,23 +268,23 @@ class LettuceReactiveZSetCommands implements ReactiveZSetCommands {
|
||||
|
||||
if (!isLimited) {
|
||||
result = cmd.zrevrangebyscoreWithScores(command.getKey(), range)
|
||||
.map(sc -> (Tuple) new DefaultTuple(ByteUtils.getBytes(sc.getValue()), sc.getScore()));
|
||||
.map(sc -> new DefaultTuple(ByteUtils.getBytes(sc.getValue()), sc.getScore()));
|
||||
} else {
|
||||
|
||||
result = cmd
|
||||
.zrevrangebyscoreWithScores(command.getKey(), range,
|
||||
LettuceConverters.toLimit(command.getLimit().get()))
|
||||
.map(sc -> (Tuple) new DefaultTuple(ByteUtils.getBytes(sc.getValue()), sc.getScore()));
|
||||
.map(sc -> new DefaultTuple(ByteUtils.getBytes(sc.getValue()), sc.getScore()));
|
||||
}
|
||||
} else {
|
||||
|
||||
if (!isLimited) {
|
||||
result = cmd.zrevrangebyscore(command.getKey(), range)
|
||||
.map(value -> (Tuple) new DefaultTuple(ByteUtils.getBytes(value), Double.NaN));
|
||||
.map(value -> new DefaultTuple(ByteUtils.getBytes(value), Double.NaN));
|
||||
} else {
|
||||
|
||||
result = cmd.zrevrangebyscore(command.getKey(), range, LettuceConverters.toLimit(command.getLimit().get()))
|
||||
.map(value -> (Tuple) new DefaultTuple(ByteUtils.getBytes(value), Double.NaN));
|
||||
.map(value -> new DefaultTuple(ByteUtils.getBytes(value), Double.NaN));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -377,9 +375,11 @@ class LettuceReactiveZSetCommands implements ReactiveZSetCommands {
|
||||
Assert.notNull(command.getKey(), "Key must not be null!");
|
||||
Assert.notNull(command.getRange(), "Range must not be null!");
|
||||
|
||||
return cmd
|
||||
.zremrangebyrank(command.getKey(), command.getRange().getLowerBound().getValue().orElse(0L),
|
||||
command.getRange().getUpperBound().getValue().orElse(Long.MAX_VALUE))
|
||||
Mono<Long> result = cmd.zremrangebyrank(command.getKey(), //
|
||||
LettuceConverters.getLowerBoundIndex(command.getRange()), //
|
||||
LettuceConverters.getUpperBoundIndex(command.getRange()));
|
||||
|
||||
return result
|
||||
.map(value -> new NumericResponse<>(command, value));
|
||||
}));
|
||||
}
|
||||
@@ -546,8 +546,8 @@ class LettuceReactiveZSetCommands implements ReactiveZSetCommands {
|
||||
|
||||
return (source) -> {
|
||||
Boolean inclusive = upper ? source.getUpperBound().isInclusive() : source.getLowerBound().isInclusive();
|
||||
Object value = upper ? source.getUpperBound().getValue().orElse(null)
|
||||
: source.getLowerBound().getValue().orElse(null);
|
||||
Object value = upper ? LettuceConverters.getUpperBound(source).orElse(null)
|
||||
: LettuceConverters.getLowerBound(source).orElse(null);
|
||||
|
||||
if (value == null) {
|
||||
return Boundary.unbounded();
|
||||
|
||||
Reference in New Issue
Block a user