Skip to content

Commit

Permalink
Java: Add Zrevrank command. (#1337)
Browse files Browse the repository at this point in the history
* Java: Add `Zrevrank` command. (#241)

* Minor documentation updates.

* Minor documentation updates.

---------

Co-authored-by: Yury-Fridlyand <yury.fridlyand@improving.com>
  • Loading branch information
SanHalacogluImproving and Yury-Fridlyand authored Apr 29, 2024
1 parent a37f6dc commit 057a432
Show file tree
Hide file tree
Showing 11 changed files with 233 additions and 6 deletions.
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 @@ -173,6 +173,7 @@ enum RequestType {
ObjectFreq = 130;
RenameNx = 131;
Touch = 132;
ZRevRank = 133;
}

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 @@ -141,6 +141,7 @@ pub enum RequestType {
ObjectFreq = 130,
RenameNx = 131,
Touch = 132,
ZRevRank = 133,
}

fn get_two_word_command(first: &str, second: &str) -> Cmd {
Expand Down Expand Up @@ -285,6 +286,7 @@ impl From<::protobuf::EnumOrUnknown<ProtobufRequestType>> for RequestType {
ProtobufRequestType::BZPopMax => RequestType::BZPopMax,
ProtobufRequestType::RenameNx => RequestType::RenameNx,
ProtobufRequestType::Touch => RequestType::Touch,
ProtobufRequestType::ZRevRank => RequestType::ZRevRank,
}
}
}
Expand Down Expand Up @@ -425,6 +427,7 @@ impl RequestType {
RequestType::BZPopMax => Some(cmd("BZPOPMAX")),
RequestType::RenameNx => Some(cmd("RENAMENX")),
RequestType::Touch => Some(cmd("TOUCH")),
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 @@ -89,6 +89,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 @@ -844,6 +845,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 @@ -104,6 +104,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 @@ -1663,7 +1664,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 @@ -1681,7 +1682,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 @@ -1697,6 +1698,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 @@ -125,6 +125,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 @@ -2601,6 +2602,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 @@ -111,6 +111,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 @@ -413,6 +414,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 @@ -1785,6 +1785,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 @@ -124,6 +124,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 @@ -244,6 +245,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

0 comments on commit 057a432

Please sign in to comment.