Support LPOS command via Jedis.

This commit introduces support for the LPOS command when using the Jedis Redis driver.

Closes #1957.
Original pull request: #1962.
This commit is contained in:
Christoph Strobl
2021-02-10 13:43:12 +01:00
committed by Mark Paluch
parent 7e7197b087
commit 19eb0930cd
4 changed files with 98 additions and 15 deletions

View File

@@ -15,12 +15,13 @@
*/
package org.springframework.data.redis.connection.jedis;
import redis.clients.jedis.params.LPosParams;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.redis.connection.ClusterSlotHashUtil;
import org.springframework.data.redis.connection.RedisListCommands;
import org.springframework.data.redis.connection.jedis.JedisClusterConnection.JedisMultiKeyClusterCommandCallback;
@@ -68,7 +69,22 @@ class JedisClusterListCommands implements RedisListCommands {
Assert.notNull(key, "Key must not be null!");
Assert.notNull(element, "Element must not be null!");
throw new InvalidDataAccessApiUsageException("LPOS is not supported by jedis.");
LPosParams params = new LPosParams();
if (rank != null) {
params.rank(rank);
}
try {
if (count != null) {
return connection.getCluster().lpos(key, element, params, count);
}
Long value = connection.getCluster().lpos(key, element, params);
return value != null ? Collections.singletonList(value) : Collections.emptyList();
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
/*

View File

@@ -19,12 +19,14 @@ import redis.clients.jedis.BinaryJedis;
import redis.clients.jedis.MultiKeyPipelineBase;
import redis.clients.jedis.Protocol;
import java.util.Collections;
import java.util.List;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.redis.connection.RedisListCommands;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import redis.clients.jedis.params.LPosParams;
/**
* @author Christoph Strobl
@@ -61,7 +63,16 @@ class JedisListCommands implements RedisListCommands {
Assert.notNull(key, "Key must not be null!");
Assert.notNull(element, "Element must not be null!");
throw new InvalidDataAccessApiUsageException("LPOS is not supported by jedis.");
LPosParams params = new LPosParams();
if(rank != null) {
params.rank(rank);
}
if(count != null) {
return connection.invoke().just(BinaryJedis::lpos, MultiKeyPipelineBase::lpos, key, element, params, count);
}
return connection.invoke().from(BinaryJedis::lpos, MultiKeyPipelineBase::lpos, key, element, params).get(Collections::singletonList);
}
/*

View File

@@ -1404,9 +1404,8 @@ public abstract class AbstractConnectionIntegrationTests {
verifyResults(Arrays.asList(2L, Arrays.asList("baz", "bar")));
}
@Test // DATAREDIS-1196
@Test // DATAREDIS-1196, GH-1957
@EnabledOnCommand("LPOS")
@EnabledOnRedisDriver({ RedisDriver.LETTUCE })
void lPos() {
actual.add(connection.rPush("mylist", "a", "b", "c", "1", "2", "3", "c", "c"));
@@ -1415,9 +1414,8 @@ public abstract class AbstractConnectionIntegrationTests {
assertThat((List<Long>) getResults().get(1)).containsOnly(2L);
}
@Test // DATAREDIS-1196
@Test // DATAREDIS-1196, GH-1957
@EnabledOnCommand("LPOS")
@EnabledOnRedisDriver({ RedisDriver.LETTUCE })
void lPosRank() {
actual.add(connection.rPush("mylist", "a", "b", "c", "1", "2", "3", "c", "c"));
@@ -1426,9 +1424,8 @@ public abstract class AbstractConnectionIntegrationTests {
assertThat((List<Long>) getResults().get(1)).containsExactly(6L);
}
@Test // DATAREDIS-1196
@Test // DATAREDIS-1196, GH-1957
@EnabledOnCommand("LPOS")
@EnabledOnRedisDriver({ RedisDriver.LETTUCE })
void lPosNegativeRank() {
actual.add(connection.rPush("mylist", "a", "b", "c", "1", "2", "3", "c", "c"));
@@ -1437,9 +1434,8 @@ public abstract class AbstractConnectionIntegrationTests {
assertThat((List<Long>) getResults().get(1)).containsExactly(7L);
}
@Test // DATAREDIS-1196
@Test // DATAREDIS-1196, GH-1957
@EnabledOnCommand("LPOS")
@EnabledOnRedisDriver({ RedisDriver.LETTUCE })
void lPosCount() {
actual.add(connection.rPush("mylist", "a", "b", "c", "1", "2", "3", "c", "c"));
@@ -1448,9 +1444,8 @@ public abstract class AbstractConnectionIntegrationTests {
assertThat((List<Long>) getResults().get(1)).containsExactly(2L, 6L);
}
@Test // DATAREDIS-1196
@Test // DATAREDIS-1196, GH-1957
@EnabledOnCommand("LPOS")
@EnabledOnRedisDriver({ RedisDriver.LETTUCE })
void lPosRankCount() {
actual.add(connection.rPush("mylist", "a", "b", "c", "1", "2", "3", "c", "c"));
@@ -1459,9 +1454,8 @@ public abstract class AbstractConnectionIntegrationTests {
assertThat((List<Long>) getResults().get(1)).containsExactly(7L, 6L);
}
@Test // DATAREDIS-1196
@Test // DATAREDIS-1196, GH-1957
@EnabledOnCommand("LPOS")
@EnabledOnRedisDriver({ RedisDriver.LETTUCE })
void lPosCountZero() {
actual.add(connection.rPush("mylist", "a", "b", "c", "1", "2", "3", "c", "c"));

View File

@@ -25,6 +25,7 @@ import static org.springframework.data.redis.connection.RedisGeoCommands.Distanc
import static org.springframework.data.redis.connection.RedisGeoCommands.GeoRadiusCommandArgs.*;
import static org.springframework.data.redis.core.ScanOptions.*;
import org.springframework.data.redis.test.condition.EnabledOnCommand;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
@@ -32,6 +33,7 @@ import redis.clients.jedis.JedisPool;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.*;
import java.util.concurrent.TimeUnit;
@@ -2472,4 +2474,64 @@ public class JedisClusterConnectionTests implements ClusterConnectionTests {
Long result = clusterConnection.scriptingCommands().evalSha(digest, ReturnType.VALUE, 1, keyAndArgs);
assertThat(result).isEqualTo(1L);
}
@Test // GH-1957
@EnabledOnCommand("LPOS")
void lPos() {
nativeConnection.rpush(KEY_1, "a", "b", "c", "1", "2", "3", "c", "c");
List<Long> result = clusterConnection.listCommands().lPos(KEY_1_BYTES, "c".getBytes(StandardCharsets.UTF_8), null, null);
assertThat(result).containsOnly(2L);
}
@Test // GH-1957
@EnabledOnCommand("LPOS")
void lPosRank() {
nativeConnection.rpush(KEY_1, "a", "b", "c", "1", "2", "3", "c", "c");
List<Long> result = clusterConnection.listCommands().lPos(KEY_1_BYTES, "c".getBytes(StandardCharsets.UTF_8), 2, null);
assertThat(result).containsExactly(6L);
}
@Test // GH-1957
@EnabledOnCommand("LPOS")
void lPosNegativeRank() {
nativeConnection.rpush(KEY_1, "a", "b", "c", "1", "2", "3", "c", "c");
List<Long> result = clusterConnection.listCommands().lPos(KEY_1_BYTES, "c".getBytes(StandardCharsets.UTF_8), -1, null);
assertThat(result).containsExactly(7L);
}
@Test // GH-1957
@EnabledOnCommand("LPOS")
void lPosCount() {
nativeConnection.rpush(KEY_1, "a", "b", "c", "1", "2", "3", "c", "c");
List<Long> result = clusterConnection.listCommands().lPos(KEY_1_BYTES, "c".getBytes(StandardCharsets.UTF_8), null, 2);
assertThat(result).containsExactly(2L, 6L);
}
@Test // GH-1957
@EnabledOnCommand("LPOS")
void lPosRankCount() {
nativeConnection.rpush(KEY_1, "a", "b", "c", "1", "2", "3", "c", "c");
List<Long> result = clusterConnection.listCommands().lPos(KEY_1_BYTES, "c".getBytes(StandardCharsets.UTF_8), -1, 2);
assertThat(result).containsExactly(7L, 6L);
}
@Test // GH-1957
@EnabledOnCommand("LPOS")
void lPosCountZero() {
nativeConnection.rpush(KEY_1, "a", "b", "c", "1", "2", "3", "c", "c");
List<Long> result = clusterConnection.listCommands().lPos(KEY_1_BYTES, "c".getBytes(StandardCharsets.UTF_8), null, 0);
assertThat(result).containsExactly(2L, 6L, 7L);
}
}