Add support for ZREMRANGEBYLEX.

We now support ZREMRANGEBYLEX for Synchronous, Reactive, ZSetOperations and RedisZSet.

Also provide a Kotlin coroutines variant via the extension for ReactiveZSetOperations.

Closes #1816.
Original pull request: #1968.
This commit is contained in:
Christoph Strobl
2021-02-15 09:52:27 +01:00
committed by Mark Paluch
parent 04707ecc27
commit 507a882e93
25 changed files with 516 additions and 0 deletions

View File

@@ -1909,6 +1909,25 @@ public abstract class AbstractConnectionIntegrationTests {
verifyResults(Arrays.asList(new Object[] { true, true, 2L, new LinkedHashSet<String>(0) }));
}
@Test // GH-1816
void testZRemRangeByLex() {
actual.add(connection.zAdd("myset", 0, "aaaa"));
actual.add(connection.zAdd("myset", 0, "b"));
actual.add(connection.zAdd("myset", 0, "c"));
actual.add(connection.zAdd("myset", 0, "d"));
actual.add(connection.zAdd("myset", 0, "e"));
actual.add(connection.zAdd("myset", 0, "foo"));
actual.add(connection.zAdd("myset", 0, "zap"));
actual.add(connection.zAdd("myset", 0, "zip"));
actual.add(connection.zAdd("myset", 0, "ALPHA"));
actual.add(connection.zAdd("myset", 0, "alpha"));
actual.add(connection.zRemRangeByLex("myset", Range.range().gte("alpha").lte("omega")));
actual.add(connection.zRange("myset", 0L, -1L));
verifyResults(Arrays.asList(new Object[] { true, true, true,true, true, true,true, true, true,true, 6L, new LinkedHashSet<String>(Arrays.asList("ALPHA", "aaaa", "zap", "zip")) }));
}
@Test
void testZRemRangeByScore() {
actual.add(connection.zAdd("myset", 2, "Bob"));

View File

@@ -948,6 +948,11 @@ class RedisConnectionUnitTests {
return delegate.zRemRangeByScore(key, range);
}
@Override
public Long zRemRangeByLex(byte[] key, Range range) {
return delegate.zRemRangeByLex(key, range);
}
@Override
public Set<byte[]> zRangeByScore(byte[] key, Range range) {
return delegate.zRangeByScore(key, range);

View File

@@ -412,6 +412,26 @@ public class LettuceReactiveZSetCommandsIntegrationTests extends LettuceReactive
assertThat(connection.zSetCommands().zRemRangeByRank(KEY_1_BBUFFER, ONE_TO_TWO).block()).isEqualTo(2L);
}
@ParameterizedRedisTest // GH-1816
void zRemRangeByLexRemovesValuesCorrectly() {
nativeCommands.zadd(KEY_1, 0D, "aaaa");
nativeCommands.zadd(KEY_1, 0D, "b");
nativeCommands.zadd(KEY_1, 0D, "c");
nativeCommands.zadd(KEY_1, 0D, "d");
nativeCommands.zadd(KEY_1, 0D, "e");
nativeCommands.zadd(KEY_1, 0D, "foo");
nativeCommands.zadd(KEY_1, 0D, "zap");
nativeCommands.zadd(KEY_1, 0D, "zip");
nativeCommands.zadd(KEY_1, 0D, "ALPHA");
nativeCommands.zadd(KEY_1, 0D, "alpha");
connection.zSetCommands().zRemRangeByLex(KEY_1_BBUFFER, Range.closed("alpha", "omega")) //
.as(StepVerifier::create) //
.expectNext(6L) //
.verifyComplete();
}
@ParameterizedRedisTest // DATAREDIS-525
void zRemRangeByScoreShouldRemoveValuesCorrectly() {

View File

@@ -0,0 +1,76 @@
/*
* Copyright 2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.redis.core;
import org.mockito.Mockito;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.RedisSerializer;
/**
* @author Christoph Strobl
*/
public class ConnectionMockingRedisTemplate<K, V> extends RedisTemplate<K, V> {
private RedisConnection connectionMock;
private ConnectionMockingRedisTemplate() {
connectionMock = Mockito.mock(RedisConnection.class);
RedisConnectionFactory connectionFactory = Mockito.mock(RedisConnectionFactory.class);
Mockito.when(connectionFactory.getConnection()).thenReturn(connectionMock);
setConnectionFactory(connectionFactory);
}
static <K, V> ConnectionMockingRedisTemplate<K, V> template() {
return builder().build();
}
static MockTemplateBuilder builder() {
return new MockTemplateBuilder();
}
public RedisConnection verify() {
return Mockito.verify(connectionMock);
}
public byte[] serializeKey(K key) {
return ((RedisSerializer<K>) getKeySerializer()).serialize(key);
}
public RedisConnection never() {
return Mockito.verify(connectionMock, Mockito.never());
}
public RedisConnection doReturn(Object o) {
return Mockito.doReturn(o).when(connectionMock);
}
public static class MockTemplateBuilder {
private ConnectionMockingRedisTemplate template = new ConnectionMockingRedisTemplate();
public <K, V> ConnectionMockingRedisTemplate<K, V> build() {
template.afterPropertiesSet();
return template;
}
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.redis.core;
import static org.mockito.ArgumentMatchers.*;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.data.redis.connection.RedisZSetCommands.Range;
/**
* @author Christoph Strobl
*/
class DefaultBoundZSetOperationsUnitTests {
DefaultBoundZSetOperations zSetOperations;
ConnectionMockingRedisTemplate template;
@BeforeEach
void beforeEach() {
template = ConnectionMockingRedisTemplate.template();
zSetOperations = new DefaultBoundZSetOperations<>("key", template);
}
@Test // GH-1816
void delegatesRemoveRangeByLex() {
Range range = Range.range().gte("alpha").lte("omega");
zSetOperations.removeRangeByLex(range);
template.verify().zRemRangeByLex(eq(template.serializeKey("key")), eq(range));
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.redis.core;
import static org.mockito.ArgumentMatchers.*;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.data.redis.connection.RedisZSetCommands.Range;
/**
* @author Christoph Strobl
*/
class DefaultZSetOperationsUnitTests {
DefaultZSetOperations zSetOperations;
ConnectionMockingRedisTemplate template;
@BeforeEach
void beforeEach() {
template = ConnectionMockingRedisTemplate.template();
zSetOperations = new DefaultZSetOperations<>(template);
}
@Test // GH-1816
void delegatesRemoveRangeByLex() {
Range range = Range.range().gte("alpha").lte("omega");
zSetOperations.removeRangeByLex("key", range);
template.verify().zRemRangeByLex(eq(template.serializeKey("key")), eq(range));
}
}