Consider exclusive Range for Jedis Stream range/pending commands.
We now consider Bound.exclusive(…) for XRANGE, XREVRANGE and XPENDING commands through Jedis. Closes: #2044 Original Pull Request: #2108
This commit is contained in:
committed by
Christoph Strobl
parent
bdd6cee61c
commit
085aca9f60
@@ -63,21 +63,20 @@ class StreamConverters {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static String getLowerValue(Range<String> range) {
|
static String getLowerValue(Range<String> range) {
|
||||||
|
return getValue(range.getLowerBound(), "-");
|
||||||
if (range.getLowerBound().equals(Range.Bound.unbounded())) {
|
|
||||||
return "-";
|
|
||||||
}
|
|
||||||
|
|
||||||
return range.getLowerBound().getValue().orElse("-");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static String getUpperValue(Range<String> range) {
|
static String getUpperValue(Range<String> range) {
|
||||||
|
return getValue(range.getUpperBound(), "+");
|
||||||
|
}
|
||||||
|
|
||||||
if (range.getUpperBound().equals(Range.Bound.unbounded())) {
|
private static String getValue(Range.Bound<String> bound, String fallbackValue) {
|
||||||
return "+";
|
|
||||||
|
if (bound.equals(Range.Bound.unbounded())) {
|
||||||
|
return fallbackValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
return range.getUpperBound().getValue().orElse("+");
|
return bound.getValue().map(it -> bound.isInclusive() ? it : "(" + it).orElse(fallbackValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
static List<Object> mapToList(Map<String, Object> map) {
|
static List<Object> mapToList(Map<String, Object> map) {
|
||||||
|
|||||||
@@ -3620,7 +3620,7 @@ public abstract class AbstractConnectionIntegrationTests {
|
|||||||
actual.add(connection.xReadGroupAsString(Consumer.from("my-group", "my-consumer"),
|
actual.add(connection.xReadGroupAsString(Consumer.from("my-group", "my-consumer"),
|
||||||
StreamOffset.create(KEY_1, ReadOffset.lastConsumed())));
|
StreamOffset.create(KEY_1, ReadOffset.lastConsumed())));
|
||||||
|
|
||||||
actual.add(connection.xPending(KEY_1, "my-group", org.springframework.data.domain.Range.open("-", "+"), 10L));
|
actual.add(connection.xPending(KEY_1, "my-group", org.springframework.data.domain.Range.unbounded(), 10L));
|
||||||
|
|
||||||
List<Object> results = getResults();
|
List<Object> results = getResults();
|
||||||
assertThat(results).hasSize(4);
|
assertThat(results).hasSize(4);
|
||||||
@@ -3665,7 +3665,7 @@ public abstract class AbstractConnectionIntegrationTests {
|
|||||||
StreamOffset.create(KEY_1, ReadOffset.lastConsumed())));
|
StreamOffset.create(KEY_1, ReadOffset.lastConsumed())));
|
||||||
|
|
||||||
actual.add(connection.xPending(KEY_1, "my-group", "my-consumer",
|
actual.add(connection.xPending(KEY_1, "my-group", "my-consumer",
|
||||||
org.springframework.data.domain.Range.open("-", "+"), 10L));
|
org.springframework.data.domain.Range.unbounded(), 10L));
|
||||||
|
|
||||||
List<Object> results = getResults();
|
List<Object> results = getResults();
|
||||||
assertThat(results).hasSize(4);
|
assertThat(results).hasSize(4);
|
||||||
@@ -3688,7 +3688,7 @@ public abstract class AbstractConnectionIntegrationTests {
|
|||||||
StreamOffset.create(KEY_1, ReadOffset.lastConsumed())));
|
StreamOffset.create(KEY_1, ReadOffset.lastConsumed())));
|
||||||
|
|
||||||
actual.add(connection.xPending(KEY_1, "my-group", "my-consumer-2",
|
actual.add(connection.xPending(KEY_1, "my-group", "my-consumer-2",
|
||||||
org.springframework.data.domain.Range.open("-", "+"), 10L));
|
org.springframework.data.domain.Range.unbounded(), 10L));
|
||||||
|
|
||||||
List<Object> results = getResults();
|
List<Object> results = getResults();
|
||||||
assertThat(results).hasSize(4);
|
assertThat(results).hasSize(4);
|
||||||
@@ -3704,7 +3704,7 @@ public abstract class AbstractConnectionIntegrationTests {
|
|||||||
actual.add(connection.xAdd(KEY_1, Collections.singletonMap(KEY_2, VALUE_2)));
|
actual.add(connection.xAdd(KEY_1, Collections.singletonMap(KEY_2, VALUE_2)));
|
||||||
actual.add(connection.xGroupCreate(KEY_1, ReadOffset.from("0"), "my-group"));
|
actual.add(connection.xGroupCreate(KEY_1, ReadOffset.from("0"), "my-group"));
|
||||||
|
|
||||||
actual.add(connection.xPending(KEY_1, "my-group", org.springframework.data.domain.Range.open("-", "+"), 10L));
|
actual.add(connection.xPending(KEY_1, "my-group", org.springframework.data.domain.Range.unbounded(), 10L));
|
||||||
|
|
||||||
List<Object> results = getResults();
|
List<Object> results = getResults();
|
||||||
assertThat(results).hasSize(3);
|
assertThat(results).hasSize(3);
|
||||||
|
|||||||
@@ -34,18 +34,10 @@ import org.springframework.data.redis.connection.RedisZSetCommands.Limit;
|
|||||||
import org.springframework.data.redis.connection.jedis.extension.JedisConnectionFactoryExtension;
|
import org.springframework.data.redis.connection.jedis.extension.JedisConnectionFactoryExtension;
|
||||||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||||
import org.springframework.data.redis.connection.lettuce.extension.LettuceConnectionFactoryExtension;
|
import org.springframework.data.redis.connection.lettuce.extension.LettuceConnectionFactoryExtension;
|
||||||
import org.springframework.data.redis.connection.stream.Consumer;
|
import org.springframework.data.redis.connection.stream.*;
|
||||||
import org.springframework.data.redis.connection.stream.MapRecord;
|
|
||||||
import org.springframework.data.redis.connection.stream.ObjectRecord;
|
|
||||||
import org.springframework.data.redis.connection.stream.PendingMessages;
|
|
||||||
import org.springframework.data.redis.connection.stream.PendingMessagesSummary;
|
|
||||||
import org.springframework.data.redis.connection.stream.ReadOffset;
|
|
||||||
import org.springframework.data.redis.connection.stream.RecordId;
|
|
||||||
import org.springframework.data.redis.connection.stream.StreamOffset;
|
|
||||||
import org.springframework.data.redis.connection.stream.StreamReadOptions;
|
|
||||||
import org.springframework.data.redis.connection.stream.StreamRecords;
|
|
||||||
import org.springframework.data.redis.test.condition.EnabledOnCommand;
|
import org.springframework.data.redis.test.condition.EnabledOnCommand;
|
||||||
import org.springframework.data.redis.test.condition.EnabledOnRedisDriver;
|
import org.springframework.data.redis.test.condition.EnabledOnRedisDriver;
|
||||||
|
import org.springframework.data.redis.test.condition.EnabledOnRedisVersion;
|
||||||
import org.springframework.data.redis.test.condition.RedisDetector;
|
import org.springframework.data.redis.test.condition.RedisDetector;
|
||||||
import org.springframework.data.redis.test.extension.RedisCluster;
|
import org.springframework.data.redis.test.extension.RedisCluster;
|
||||||
import org.springframework.data.redis.test.extension.RedisStanalone;
|
import org.springframework.data.redis.test.extension.RedisStanalone;
|
||||||
@@ -198,6 +190,28 @@ public class DefaultStreamOperationsIntegrationTests<K, HK, HV> {
|
|||||||
assertThat(message.getId()).isEqualTo(messageId1);
|
assertThat(message.getId()).isEqualTo(messageId1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ParameterizedRedisTest // GH-2044
|
||||||
|
@EnabledOnRedisVersion("6.2")
|
||||||
|
void exclusiveRangeShouldReportMessages() {
|
||||||
|
|
||||||
|
K key = keyFactory.instance();
|
||||||
|
HK hashKey = hashKeyFactory.instance();
|
||||||
|
HV value = hashValueFactory.instance();
|
||||||
|
|
||||||
|
RecordId messageId1 = streamOps.add(key, Collections.singletonMap(hashKey, value));
|
||||||
|
RecordId messageId2 = streamOps.add(key, Collections.singletonMap(hashKey, value));
|
||||||
|
|
||||||
|
List<MapRecord<K, HK, HV>> messages = streamOps.range(key,
|
||||||
|
Range.from(Bound.exclusive(messageId1.getValue())).to(Bound.inclusive(messageId2.getValue())));
|
||||||
|
|
||||||
|
assertThat(messages).hasSize(1).extracting(Record::getId).contains(messageId2);
|
||||||
|
|
||||||
|
messages = streamOps.range(key,
|
||||||
|
Range.from(Bound.inclusive(messageId1.getValue())).to(Bound.exclusive(messageId2.getValue())));
|
||||||
|
|
||||||
|
assertThat(messages).hasSize(1).extracting(Record::getId).contains(messageId1);
|
||||||
|
}
|
||||||
|
|
||||||
@ParameterizedRedisTest // DATAREDIS-864
|
@ParameterizedRedisTest // DATAREDIS-864
|
||||||
void reverseRangeShouldReportMessages() {
|
void reverseRangeShouldReportMessages() {
|
||||||
|
|
||||||
@@ -213,6 +227,29 @@ public class DefaultStreamOperationsIntegrationTests<K, HK, HV> {
|
|||||||
assertThat(messages).hasSize(2).extracting("id").containsSequence(messageId2, messageId1);
|
assertThat(messages).hasSize(2).extracting("id").containsSequence(messageId2, messageId1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ParameterizedRedisTest // GH-2044
|
||||||
|
@EnabledOnRedisVersion("6.2")
|
||||||
|
void exclusiveReverseRangeShouldReportMessages() {
|
||||||
|
|
||||||
|
K key = keyFactory.instance();
|
||||||
|
HK hashKey = hashKeyFactory.instance();
|
||||||
|
HV value = hashValueFactory.instance();
|
||||||
|
|
||||||
|
RecordId messageId1 = streamOps.add(key, Collections.singletonMap(hashKey, value));
|
||||||
|
RecordId messageId2 = streamOps.add(key, Collections.singletonMap(hashKey, value));
|
||||||
|
RecordId messageId3 = streamOps.add(key, Collections.singletonMap(hashKey, value));
|
||||||
|
|
||||||
|
List<MapRecord<K, HK, HV>> messages = streamOps.reverseRange(key,
|
||||||
|
Range.from(Bound.exclusive(messageId1.getValue())).to(Bound.inclusive(messageId3.getValue())));
|
||||||
|
|
||||||
|
assertThat(messages).hasSize(2).extracting(Record::getId).containsSequence(messageId3, messageId2);
|
||||||
|
|
||||||
|
messages = streamOps.reverseRange(key,
|
||||||
|
Range.from(Bound.inclusive(messageId1.getValue())).to(Bound.exclusive(messageId3.getValue())));
|
||||||
|
|
||||||
|
assertThat(messages).hasSize(2).extracting(Record::getId).containsSequence(messageId2, messageId1);
|
||||||
|
}
|
||||||
|
|
||||||
@ParameterizedRedisTest // DATAREDIS-864
|
@ParameterizedRedisTest // DATAREDIS-864
|
||||||
void reverseRangeShouldConvertSimpleMessages() {
|
void reverseRangeShouldConvertSimpleMessages() {
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user