Skip to content

Commit

Permalink
Java: Add Zremrangebyrank command. (Sorted Set Group) (#189) (valke…
Browse files Browse the repository at this point in the history
…y-io#1263)

* Java: Add `Zremrangebyrank` command. (Sorted Set Group) (#189)

* Rebase + Spotless.

* Minor documentation update.

* Added checks for elements in IT tests.

* Minor transaction update.

* Minor UT update.
  • Loading branch information
SanHalacogluImproving authored and cyip10 committed Jun 24, 2024
1 parent 503b21a commit cbd4856
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 0 deletions.
9 changes: 9 additions & 0 deletions java/client/src/main/java/glide/api/BaseClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.ZMScore;
import static redis_request.RedisRequestOuterClass.RequestType.ZPopMax;
import static redis_request.RedisRequestOuterClass.RequestType.ZPopMin;
import static redis_request.RedisRequestOuterClass.RequestType.ZRemRangeByRank;
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 @@ -765,6 +766,14 @@ public CompletableFuture<Long> zcount(
Zcount, new String[] {key, minScore.toArgs(), maxScore.toArgs()}, this::handleLongResponse);
}

@Override
public CompletableFuture<Long> zremrangebyrank(@NonNull String key, long start, long end) {
return commandManager.submitNewCommand(
ZRemRangeByRank,
new String[] {key, Long.toString(start), Long.toString(end)},
this::handleLongResponse);
}

@Override
public CompletableFuture<String> xadd(@NonNull String key, @NonNull Map<String, String> values) {
return xadd(key, values, StreamAddOptions.builder().build());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -556,4 +556,31 @@ CompletableFuture<Map<String, Double>> zrangeWithScores(
* }</pre>
*/
CompletableFuture<Long> zcount(String key, ScoreRange minScore, ScoreRange maxScore);

/**
* Removes all elements in the sorted set stored at <code>key</code> with rank between <code>start
* </code> and <code>end</code>. Both <code>start</code> and <code>end</code> are zero-based
* indexes with <code>0</code> being the element with the lowest score. These indexes can be
* negative numbers, where they indicate offsets starting at the element with the highest score.
*
* @see <a href="https://redis.io/commands/zremrangebyrank/">redis.io</a> for more details.
* @param key The key of the sorted set.
* @param start The starting point of the range.
* @param end The end of the range.
* @return The number of elements removed.<br>
* If <code>start</code> exceeds the end of the sorted set, or if <code>start</code> is
* greater than <code>end</code>, <code>0</code> returned.<br>
* If <code>end</code> exceeds the actual end of the sorted set, the range will stop at the
* actual end of the sorted set.<br>
* If <code>key</code> does not exist <code>0</code> will be returned.
* @example
* <pre>{@code
* Long payload1 = client.zremrangebyrank("mySortedSet", 0, 4).get();
* assert payload1 == 5L; // Indicates that 5 elements, with ranks ranging from 0 to 4 (inclusive), have been removed from "mySortedSet".
*
* Long payload2 = client.zremrangebyrank("mySortedSet", 0, 4).get();
* assert payload2 == 0L; // Indicates that nothing was removed.
* }</pre>
*/
CompletableFuture<Long> zremrangebyrank(String key, long start, long end);
}
24 changes: 24 additions & 0 deletions java/client/src/main/java/glide/api/models/BaseTransaction.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.ZMScore;
import static redis_request.RedisRequestOuterClass.RequestType.ZPopMax;
import static redis_request.RedisRequestOuterClass.RequestType.ZPopMin;
import static redis_request.RedisRequestOuterClass.RequestType.ZRemRangeByRank;
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 @@ -1596,6 +1597,29 @@ public T zcount(@NonNull String key, @NonNull ScoreRange minScore, @NonNull Scor
return getThis();
}

/**
* Removes all elements in the sorted set stored at <code>key</code> with rank between <code>start
* </code> and <code>end</code>. Both <code>start</code> and <code>end</code> are zero-based
* indexes with <code>0</code> being the element with the lowest score. These indexes can be
* negative numbers, where they indicate offsets starting at the element with the highest score.
*
* @see <a href="https://redis.io/commands/zremrangebyrank/">redis.io</a> for more details.
* @param key The key of the sorted set.
* @param start The starting point of the range.
* @param end The end of the range.
* @return Command Response - The number of elements removed.<br>
* If <code>start</code> exceeds the end of the sorted set, or if <code>start</code> is
* greater than <code>end</code>, <code>0</code> returned.<br>
* If <code>end</code> exceeds the actual end of the sorted set, the range will stop at the
* actual end of the sorted set.<br>
* If <code>key</code> does not exist <code>0</code> will be returned.
*/
public T zremrangebyrank(@NonNull String key, long start, long end) {
ArgsArray commandArgs = buildArgs(key, Long.toString(start), Long.toString(end));
protobufTransaction.addCommands(buildCommand(ZRemRangeByRank, commandArgs));
return getThis();
}

/**
* Adds an entry to the specified stream stored at <code>key</code>.<br>
* If the <code>key</code> doesn't exist, the stream is created.
Expand Down
27 changes: 27 additions & 0 deletions java/client/src/test/java/glide/api/RedisClientTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.ZMScore;
import static redis_request.RedisRequestOuterClass.RequestType.ZPopMax;
import static redis_request.RedisRequestOuterClass.RequestType.ZPopMin;
import static redis_request.RedisRequestOuterClass.RequestType.ZRemRangeByRank;
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 @@ -2453,6 +2454,32 @@ public void zcount_returns_success() {
assertEquals(value, payload);
}

@SneakyThrows
@Test
public void zremrangebyrank_returns_success() {
// setup
String key = "testKey";
long start = 0;
long end = -1;
String[] arguments = new String[] {key, Long.toString(start), Long.toString(end)};
Long value = 5L;

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

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

// exercise
CompletableFuture<Long> response = service.zremrangebyrank(key, start, end);
Long payload = response.get();

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

@SneakyThrows
@Test
public void xadd_returns_success() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.ZMScore;
import static redis_request.RedisRequestOuterClass.RequestType.ZPopMax;
import static redis_request.RedisRequestOuterClass.RequestType.ZPopMin;
import static redis_request.RedisRequestOuterClass.RequestType.ZRemRangeByRank;
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 @@ -377,6 +378,9 @@ public void transaction_builds_protobuf_request(BaseTransaction<?> transaction)
transaction.zcount("key", new ScoreBoundary(5, false), InfScoreBound.POSITIVE_INFINITY);
results.add(Pair.of(Zcount, buildArgs("key", "(5.0", "+inf")));

transaction.zremrangebyrank("key", 0, -1);
results.add(Pair.of(ZRemRangeByRank, buildArgs("key", "0", "-1")));

transaction.xadd("key", Map.of("field1", "foo1"));
results.add(Pair.of(XAdd, buildArgs("key", "*", "field1", "foo1")));

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

@SneakyThrows
@ParameterizedTest
@MethodSource("getClients")
public void zremrangebyrank(BaseClient client) {
String key1 = UUID.randomUUID().toString();
String key2 = UUID.randomUUID().toString();
RangeByIndex query = new RangeByIndex(0, -1);
Map<String, Double> membersScores = Map.of("one", 1.0, "two", 2.0, "three", 3.0);
assertEquals(3, client.zadd(key1, membersScores).get());

// Incorrect range start > stop
assertEquals(0, client.zremrangebyrank(key1, 2, 1).get());
assertEquals(
Map.of("one", 1.0, "two", 2.0, "three", 3.0), client.zrangeWithScores(key1, query).get());

assertEquals(2, client.zremrangebyrank(key1, 0, 1).get());
assertEquals(Map.of("three", 3.0), client.zrangeWithScores(key1, query).get());

assertEquals(1, client.zremrangebyrank(key1, 0, 10).get());
assertTrue(client.zrangeWithScores(key1, query).get().isEmpty());

// Non Existing Key
assertEquals(0, client.zremrangebyrank(key2, 0, 10).get());

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

@SneakyThrows
@ParameterizedTest
@MethodSource("getClients")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ public static BaseTransaction<?> transactionTest(BaseTransaction<?> baseTransact
baseTransaction.zcount(key8, new ScoreBoundary(2, true), InfScoreBound.POSITIVE_INFINITY);
baseTransaction.zpopmin(key8);
baseTransaction.zpopmax(key8);
baseTransaction.zremrangebyrank(key8, 5, 10);
baseTransaction.zdiffstore(key8, new String[] {key8, key8});

baseTransaction.zadd(zSetKey2, Map.of("one", 1.0, "two", 2.0));
Expand Down Expand Up @@ -211,6 +212,7 @@ public static Object[] transactionTestResult() {
2L, // zcount(key8, new ScoreBoundary(2, true), InfScoreBound.POSITIVE_INFINITY)
Map.of("two", 2.0), // zpopmin(key8)
Map.of("three", 3.0), // zpopmax(key8)
0L, // zremrangebyrank(key8, 5, 10)
0L, // zdiffstore(key8, new String[] {key8, key8})
2L, // zadd(zSetKey2, Map.of("one", 1.0, "two", 2.0))
new String[] {"one", "two"}, // zdiff(new String[] {zSetKey2, key8})
Expand Down

0 comments on commit cbd4856

Please sign in to comment.