Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Java: Add Zrevrank command. #1337

Merged
merged 4 commits into from
Apr 29, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions glide-core/src/protobuf/redis_request.proto
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ enum RequestType {
GeoPos = 128;
BZPopMax = 129;
ObjectFreq = 130;
ZRevRank = 131;
}

message Command {
Expand Down
3 changes: 3 additions & 0 deletions glide-core/src/request_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ pub enum RequestType {
GeoPos = 128,
BZPopMax = 129,
ObjectFreq = 130,
ZRevRank = 131,
}

fn get_two_word_command(first: &str, second: &str) -> Cmd {
Expand Down Expand Up @@ -281,6 +282,7 @@ impl From<::protobuf::EnumOrUnknown<ProtobufRequestType>> for RequestType {
ProtobufRequestType::LOLWUT => RequestType::LOLWUT,
ProtobufRequestType::GeoPos => RequestType::GeoPos,
ProtobufRequestType::BZPopMax => RequestType::BZPopMax,
ProtobufRequestType::ZRevRank => RequestType::ZRevRank,
}
}
}
Expand Down Expand Up @@ -419,6 +421,7 @@ impl RequestType {
RequestType::LOLWUT => Some(cmd("LOLWUT")),
RequestType::GeoPos => Some(cmd("GEOPOS")),
RequestType::BZPopMax => Some(cmd("BZPOPMAX")),
RequestType::ZRevRank => Some(cmd("ZREVRANK")),
}
}
}
16 changes: 16 additions & 0 deletions java/client/src/main/java/glide/api/BaseClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.ZRemRangeByLex;
import static redis_request.RedisRequestOuterClass.RequestType.ZRemRangeByRank;
import static redis_request.RedisRequestOuterClass.RequestType.ZRemRangeByScore;
import static redis_request.RedisRequestOuterClass.RequestType.ZRevRank;
import static redis_request.RedisRequestOuterClass.RequestType.ZScore;
import static redis_request.RedisRequestOuterClass.RequestType.Zadd;
import static redis_request.RedisRequestOuterClass.RequestType.Zcard;
Expand Down Expand Up @@ -827,6 +828,21 @@ public CompletableFuture<Object[]> zrankWithScore(@NonNull String key, @NonNull
Zrank, new String[] {key, member, WITH_SCORE_REDIS_API}, this::handleArrayOrNullResponse);
}

@Override
public CompletableFuture<Long> zrevrank(@NonNull String key, @NonNull String member) {
return commandManager.submitNewCommand(
ZRevRank, new String[] {key, member}, this::handleLongOrNullResponse);
}

@Override
public CompletableFuture<Object[]> zrevrankWithScore(
@NonNull String key, @NonNull String member) {
return commandManager.submitNewCommand(
ZRevRank,
new String[] {key, member, WITH_SCORE_REDIS_API},
this::handleArrayOrNullResponse);
}

@Override
public CompletableFuture<Double[]> zmscore(@NonNull String key, @NonNull String[] members) {
String[] arguments = ArrayUtils.addFirst(members, key);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,7 @@ CompletableFuture<Long> zrangestore(

/**
* Returns the rank of <code>member</code> in the sorted set stored at <code>key</code>, with
* scores ordered from low to high.<br>
* scores ordered from low to high, starting from <code>0</code>.<br>
* To get the rank of <code>member</code> with its score, see {@link #zrankWithScore}.
*
* @see <a href="https://redis.io/commands/zrank/">redis.io</a> for more details.
Expand All @@ -529,7 +529,7 @@ CompletableFuture<Long> zrangestore(

/**
* Returns the rank of <code>member</code> in the sorted set stored at <code>key</code> with its
* score, where scores are ordered from the lowest to highest.
* score, where scores are ordered from the lowest to highest, starting from <code>0</code>.<br>
*
* @see <a href="https://redis.io/commands/zrank/">redis.io</a> for more details.
* @param key The key of the sorted set.
Expand All @@ -541,14 +541,60 @@ CompletableFuture<Long> zrangestore(
* @example
* <pre>{@code
* Object[] result1 = client.zrankWithScore("mySortedSet", "member2").get();
* assert ((Long)result1[0]) == 1L && ((Double)result1[1]) == 6.0; // Indicates that "member2" with score 6.0 has the second-lowest score in the sorted set "mySortedSet".
* assert ((Long) result1[0]) == 1L && ((Double) result1[1]) == 6.0; // Indicates that "member2" with score 6.0 has the second-lowest score in the sorted set "mySortedSet".
*
* Object[] result2 = client.zrankWithScore("mySortedSet", "nonExistingMember").get();
* assert num2 == null; // Indicates that "nonExistingMember" is not present in the sorted set "mySortedSet".
* assert result2 == null; // Indicates that "nonExistingMember" is not present in the sorted set "mySortedSet".
* }</pre>
*/
CompletableFuture<Object[]> zrankWithScore(String key, String member);

/**
* Returns the rank of <code>member</code> in the sorted set stored at <code>key</code>, where
* scores are ordered from the highest to lowest, starting from <code>0</code>.<br>
* To get the rank of <code>member</code> with its score, see {@link #zrevrankWithScore}.
*
* @see <a href="https://redis.io/commands/zrevrank/">redis.io</a> for more details.
* @param key The key of the sorted set.
* @param member The member whose rank is to be retrieved.
* @return The rank of <code>member</code> in the sorted set, where ranks are ordered from high to
* low based on scores.<br>
* If <code>key</code> doesn't exist, or if <code>member</code> is not present in the set,
* <code>null</code> will be returned.
* @example
* <pre>{@code
* Long num1 = client.zrevrank("mySortedSet", "member2").get();
* assert num1 == 1L; // Indicates that "member2" has the second-highest score in the sorted set "mySortedSet".
*
* Long num2 = client.zrevrank("mySortedSet", "nonExistingMember").get();
* assert num2 == null; // Indicates that "nonExistingMember" is not present in the sorted set "mySortedSet".
* }</pre>
*/
CompletableFuture<Long> zrevrank(String key, String member);

/**
* Returns the rank of <code>member</code> in the sorted set stored at <code>key</code> with its
* score, where scores are ordered from the highest to lowest, starting from <code>0</code>.
*
* @see <a href="https://redis.io/commands/zrevrank/">redis.io</a> for more details.
* @param key The key of the sorted set.
* @param member The member whose rank is to be retrieved.
* @return An array containing the rank (as <code>Long</code>) and score (as <code>Double</code>)
* of <code>member</code> in the sorted set, where ranks are ordered from high to low based on
* scores.<br>
* If <code>key</code> doesn't exist, or if <code>member</code> is not present in the set,
* <code>null</code> will be returned.
* @example
* <pre>{@code
* Object[] result1 = client.zrevrankWithScore("mySortedSet", "member2").get();
* assert ((Long) result1[0]) == 1L && ((Double) result1[1]) == 6.0; // Indicates that "member2" with score 6.0 has the second-highest score in the sorted set "mySortedSet".
*
* Object[] result2 = client.zrevrankWithScore("mySortedSet", "nonExistingMember").get();
* assert result2 == null; // Indicates that "nonExistingMember" is not present in the sorted set "mySortedSet".
* }</pre>
*/
CompletableFuture<Object[]> zrevrankWithScore(String key, String member);

/**
* Returns the scores associated with the specified <code>members</code> in the sorted set stored
* at <code>key</code>.
Expand Down
43 changes: 41 additions & 2 deletions java/client/src/main/java/glide/api/models/BaseTransaction.java
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.ZRemRangeByLex;
import static redis_request.RedisRequestOuterClass.RequestType.ZRemRangeByRank;
import static redis_request.RedisRequestOuterClass.RequestType.ZRemRangeByScore;
import static redis_request.RedisRequestOuterClass.RequestType.ZRevRank;
import static redis_request.RedisRequestOuterClass.RequestType.ZScore;
import static redis_request.RedisRequestOuterClass.RequestType.Zadd;
import static redis_request.RedisRequestOuterClass.RequestType.Zcard;
Expand Down Expand Up @@ -1647,7 +1648,7 @@ public T zscore(@NonNull String key, @NonNull String member) {

/**
* Returns the rank of <code>member</code> in the sorted set stored at <code>key</code>, with
* scores ordered from low to high.<br>
* scores ordered from low to high, starting from <code>0</code>.<br>
* To get the rank of <code>member</code> with its score, see {@link #zrankWithScore}.
*
* @see <a href="https://redis.io/commands/zrank/">redis.io</a> for more details.
Expand All @@ -1665,7 +1666,7 @@ public T zrank(@NonNull String key, @NonNull String member) {

/**
* Returns the rank of <code>member</code> in the sorted set stored at <code>key</code> with its
* score, where scores are ordered from the lowest to highest.
* score, where scores are ordered from the lowest to highest, starting from <code>0</code>.<br>
*
* @see <a href="https://redis.io/commands/zrank/">redis.io</a> for more details.
* @param key The key of the sorted set.
Expand All @@ -1681,6 +1682,44 @@ public T zrankWithScore(@NonNull String key, @NonNull String member) {
return getThis();
}

/**
* Returns the rank of <code>member</code> in the sorted set stored at <code>key</code>, where
* scores are ordered from the highest to lowest, starting from <code>0</code>.<br>
* To get the rank of <code>member</code> with its score, see {@link #zrevrankWithScore}.
*
* @see <a href="https://redis.io/commands/zrevrank/">redis.io</a> for more details.
* @param key The key of the sorted set.
* @param member The member whose rank is to be retrieved.
* @return Command Response - The rank of <code>member</code> in the sorted set, where ranks are
* ordered from high to low based on scores.<br>
* If <code>key</code> doesn't exist, or if <code>member</code> is not present in the set,
* <code>null</code> will be returned.
*/
public T zrevrank(@NonNull String key, @NonNull String member) {
ArgsArray commandArgs = buildArgs(key, member);
protobufTransaction.addCommands(buildCommand(ZRevRank, commandArgs));
return getThis();
}

/**
* Returns the rank of <code>member</code> in the sorted set stored at <code>key</code> with its
* score, where scores are ordered from the highest to lowest, starting from <code>0</code>.
*
* @see <a href="https://redis.io/commands/zrevrank/">redis.io</a> for more details.
* @param key The key of the sorted set.
* @param member The member whose rank is to be retrieved.
* @return Command Response - An array containing the rank (as <code>Long</code>) and score (as
* <code>Double</code>) of <code>member</code> in the sorted set, where ranks are ordered from
* high to low based on scores.<br>
* If <code>key</code> doesn't exist, or if <code>member</code> is not present in the set,
* <code>null</code> will be returned.
*/
public T zrevrankWithScore(@NonNull String key, @NonNull String member) {
ArgsArray commandArgs = buildArgs(key, member, WITH_SCORE_REDIS_API);
protobufTransaction.addCommands(buildCommand(ZRevRank, commandArgs));
return getThis();
}

/**
* Returns the scores associated with the specified <code>members</code> in the sorted set stored
* at <code>key</code>.
Expand Down
51 changes: 51 additions & 0 deletions java/client/src/test/java/glide/api/RedisClientTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.ZRemRangeByLex;
import static redis_request.RedisRequestOuterClass.RequestType.ZRemRangeByRank;
import static redis_request.RedisRequestOuterClass.RequestType.ZRemRangeByScore;
import static redis_request.RedisRequestOuterClass.RequestType.ZRevRank;
import static redis_request.RedisRequestOuterClass.RequestType.ZScore;
import static redis_request.RedisRequestOuterClass.RequestType.Zadd;
import static redis_request.RedisRequestOuterClass.RequestType.Zcard;
Expand Down Expand Up @@ -2574,6 +2575,56 @@ public void zrankWithScore_returns_success() {
assertEquals(value, payload);
}

@SneakyThrows
@Test
public void zrevrank_returns_success() {
// setup
String key = "testKey";
String member = "testMember";
String[] arguments = new String[] {key, member};
Long value = 3L;

CompletableFuture<Long> testResponse = new CompletableFuture<>();
testResponse.complete(value);

// match on protobuf request
when(commandManager.<Long>submitNewCommand(eq(ZRevRank), eq(arguments), any()))
.thenReturn(testResponse);

// exercise
CompletableFuture<Long> response = service.zrevrank(key, member);
Long payload = response.get();

// verify
assertEquals(testResponse, response);
assertEquals(value, payload);
}

@SneakyThrows
@Test
public void zrevrankWithScore_returns_success() {
// setup
String key = "testKey";
String member = "testMember";
String[] arguments = new String[] {key, member, WITH_SCORE_REDIS_API};
Object[] value = new Object[] {1, 6.0};

CompletableFuture<Object[]> testResponse = new CompletableFuture<>();
testResponse.complete(value);

// match on protobuf request
when(commandManager.<Object[]>submitNewCommand(eq(ZRevRank), eq(arguments), any()))
.thenReturn(testResponse);

// exercise
CompletableFuture<Object[]> response = service.zrevrankWithScore(key, member);
Object[] payload = response.get();

// verify
assertEquals(testResponse, response);
assertEquals(value, payload);
}

@SneakyThrows
@Test
public void zmscore_returns_success() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.ZRemRangeByLex;
import static redis_request.RedisRequestOuterClass.RequestType.ZRemRangeByRank;
import static redis_request.RedisRequestOuterClass.RequestType.ZRemRangeByScore;
import static redis_request.RedisRequestOuterClass.RequestType.ZRevRank;
import static redis_request.RedisRequestOuterClass.RequestType.ZScore;
import static redis_request.RedisRequestOuterClass.RequestType.Zadd;
import static redis_request.RedisRequestOuterClass.RequestType.Zcard;
Expand Down Expand Up @@ -407,6 +408,12 @@ public void transaction_builds_protobuf_request(BaseTransaction<?> transaction)
transaction.zrankWithScore("key", "member");
results.add(Pair.of(Zrank, buildArgs("key", "member", WITH_SCORE_REDIS_API)));

transaction.zrevrank("key", "member");
results.add(Pair.of(ZRevRank, buildArgs("key", "member")));

transaction.zrevrankWithScore("key", "member");
results.add(Pair.of(ZRevRank, buildArgs("key", "member", WITH_SCORE_REDIS_API)));

transaction.zmscore("key", new String[] {"member1", "member2"});
results.add(Pair.of(ZMScore, buildArgs("key", "member1", "member2")));

Expand Down
24 changes: 24 additions & 0 deletions java/integTest/src/test/java/glide/SharedCommandTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -1728,6 +1728,30 @@ public void zrank(BaseClient client) {
assertTrue(executionException.getCause() instanceof RequestException);
}

@SneakyThrows
@ParameterizedTest(autoCloseArguments = false)
@MethodSource("getClients")
public void zrevrank(BaseClient client) {
String key = UUID.randomUUID().toString();
Map<String, Double> membersScores = Map.of("one", 1.5, "two", 2.0, "three", 3.0);
assertEquals(3, client.zadd(key, membersScores).get());
assertEquals(0, client.zrevrank(key, "three").get());

if (REDIS_VERSION.isGreaterThanOrEqualTo("7.2.0")) {
assertArrayEquals(new Object[] {2L, 1.5}, client.zrevrankWithScore(key, "one").get());
assertNull(client.zrevrankWithScore(key, "nonExistingMember").get());
assertNull(client.zrevrankWithScore("nonExistingKey", "nonExistingMember").get());
}
assertNull(client.zrevrank(key, "nonExistingMember").get());
assertNull(client.zrevrank("nonExistingKey", "nonExistingMember").get());

// Key exists, but it is not a set
assertEquals(OK, client.set(key, "value").get());
ExecutionException executionException =
assertThrows(ExecutionException.class, () -> client.zrevrank(key, "one").get());
assertTrue(executionException.getCause() instanceof RequestException);
}

@SneakyThrows
@ParameterizedTest(autoCloseArguments = false)
@MethodSource("getClients")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ public static BaseTransaction<?> transactionTest(BaseTransaction<?> baseTransact

baseTransaction.zadd(key8, Map.of("one", 1.0, "two", 2.0, "three", 3.0));
baseTransaction.zrank(key8, "one");
baseTransaction.zrevrank(key8, "one");
baseTransaction.zaddIncr(key8, "one", 3);
baseTransaction.zrem(key8, new String[] {"one"});
baseTransaction.zcard(key8);
Expand Down Expand Up @@ -237,6 +238,7 @@ public static Object[] transactionTestResult() {
true, // smove(key7, setKey2, "baz")
3L,
0L, // zrank(key8, "one")
2L, // zrevrank(key8, "one")
4.0,
1L,
2L,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/** Copyright GLIDE-for-Redis Project Contributors - SPDX Identifier: Apache-2.0 */
package glide.cluster;

import static glide.TestConfiguration.REDIS_VERSION;
import static glide.TransactionTestUtilities.transactionTest;
import static glide.TransactionTestUtilities.transactionTestResult;
import static glide.api.BaseClient.OK;
Expand All @@ -9,6 +10,7 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assumptions.assumeTrue;

import glide.TestConfiguration;
import glide.api.RedisClusterClient;
Expand All @@ -17,6 +19,8 @@
import glide.api.models.configuration.RedisClusterClientConfiguration;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Map;
import java.util.UUID;
import lombok.SneakyThrows;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
Expand Down Expand Up @@ -140,4 +144,20 @@ public void lastsave() {
// assertEquals(OK, response[0]);
// assertTrue((long) response[1] >= 0L);
// }

@Test
@SneakyThrows
public void zrank_zrevrank_withscores() {
assumeTrue(REDIS_VERSION.isGreaterThanOrEqualTo("7.2.0"));
String zSetKey1 = "{key}:zsetKey1-" + UUID.randomUUID();
ClusterTransaction transaction = new ClusterTransaction();
transaction.zadd(zSetKey1, Map.of("one", 1.0, "two", 2.0, "three", 3.0));
transaction.zrankWithScore(zSetKey1, "one");
transaction.zrevrankWithScore(zSetKey1, "one");

Object[] result = clusterClient.exec(transaction).get();
assertEquals(3L, result[0]);
assertArrayEquals(new Object[] {0L, 1.0}, (Object[]) result[1]);
assertArrayEquals(new Object[] {2L, 1.0}, (Object[]) result[2]);
}
}
Loading
Loading