Skip to content

Commit

Permalink
Java: Add Zremrangebyscore command. (Sorted Set Group) (valkey-io#1269
Browse files Browse the repository at this point in the history
)

* Java: Add `Zremrangebyscore` command. (Sorted Set Group) (#211)

* Added checks for elements in IT tests.

* Minor ordering fix.

* Rebase + Spotless.
  • Loading branch information
SanHalacogluImproving authored Apr 12, 2024
1 parent 32ea9d6 commit 2847b21
Show file tree
Hide file tree
Showing 8 changed files with 144 additions and 2 deletions.
10 changes: 10 additions & 0 deletions java/client/src/main/java/glide/api/BaseClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.ZPopMin;
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.ZScore;
import static redis_request.RedisRequestOuterClass.RequestType.Zadd;
import static redis_request.RedisRequestOuterClass.RequestType.Zcard;
Expand Down Expand Up @@ -785,6 +786,15 @@ public CompletableFuture<Long> zremrangebylex(
this::handleLongResponse);
}

@Override
public CompletableFuture<Long> zremrangebyscore(
@NonNull String key, @NonNull ScoreRange minScore, @NonNull ScoreRange maxScore) {
return commandManager.submitNewCommand(
ZRemRangeByScore,
new String[] {key, minScore.toArgs(), maxScore.toArgs()},
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 @@ -613,4 +613,31 @@ CompletableFuture<Map<String, Double>> zrangeWithScores(
* }</pre>
*/
CompletableFuture<Long> zremrangebylex(String key, LexRange minLex, LexRange maxLex);

/**
* Removes all elements in the sorted set stored at <code>key</code> with a score between <code>
* minScore</code> and <code>maxScore</code>.
*
* @see <a href="https://redis.io/commands/zremrangebyscore/">redis.io</a> for more details.
* @param key The key of the sorted set.
* @param minScore The minimum score to remove from. Can be an implementation of {@link
* InfScoreBound} representing positive/negative infinity, or {@link ScoreBoundary}
* representing a specific score and inclusivity.
* @param maxScore The maximum score to remove to. Can be an implementation of {@link
* InfScoreBound} representing positive/negative infinity, or {@link ScoreBoundary}
* representing a specific score and inclusivity.
* @return The number of members removed.<br>
* If <code>key</code> does not exist, it is treated as an empty sorted set, and the command
* returns <code>0</code>.<br>
* If <code>minScore</code> is greater than <code>maxScore</code>, <code>0</code> is returned.
* @example
* <pre>{@code
* Long payload1 = client.zremrangebyscore("mySortedSet", new ScoreBoundary(1, false), new ScoreBoundary(5)).get();
* assert payload1 == 4L; // Indicates that 4 members, with scores ranging from 1 (exclusive) to 5 (inclusive), have been removed from "mySortedSet".
*
* Long payload2 = client.zremrangebyscore("mySortedSet", InfScoreBound.NEGATIVE_INFINITY , new ScoreBoundary(-42)).get();
* assert payload2 == 0L; // Indicates that no elements were removed.
* }</pre>
*/
CompletableFuture<Long> zremrangebyscore(String key, ScoreRange minScore, ScoreRange maxScore);
}
25 changes: 25 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 @@ -81,6 +81,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.ZPopMin;
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.ZScore;
import static redis_request.RedisRequestOuterClass.RequestType.Zadd;
import static redis_request.RedisRequestOuterClass.RequestType.Zcard;
Expand Down Expand Up @@ -1647,6 +1648,30 @@ public T zremrangebylex(@NonNull String key, @NonNull LexRange minLex, @NonNull
return getThis();
}

/**
* Removes all elements in the sorted set stored at <code>key</code> with a score between <code>
* minScore</code> and <code>maxScore</code>.
*
* @see <a href="https://redis.io/commands/zremrangebyscore/">redis.io</a> for more details.
* @param key The key of the sorted set.
* @param minScore The minimum score to remove from. Can be an implementation of {@link
* InfScoreBound} representing positive/negative infinity, or {@link ScoreBoundary}
* representing a specific score and inclusivity.
* @param maxScore The maximum score to remove to. Can be an implementation of {@link
* InfScoreBound} representing positive/negative infinity, or {@link ScoreBoundary}
* representing a specific score and inclusivity.
* @return Command Response - The number of members removed.<br>
* If <code>key</code> does not exist, it is treated as an empty sorted set, and the command
* returns <code>0</code>.<br>
* If <code>minScore</code> is greater than <code>maxScore</code>, <code>0</code> is returned.
*/
public T zremrangebyscore(
@NonNull String key, @NonNull ScoreRange minScore, @NonNull ScoreRange maxScore) {
ArgsArray commandArgs = buildArgs(key, minScore.toArgs(), maxScore.toArgs());
protobufTransaction.addCommands(buildCommand(ZRemRangeByScore, 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
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@
/**
* Arguments for {@link SortedSetBaseCommands#zcount}, {@link
* SortedSetBaseCommands#zremrangebyrank}, {@link SortedSetBaseCommands#zremrangebylex(String,
* LexRange, LexRange)}, {@link SortedSetBaseCommands#zrange}, and {@link
* SortedSetBaseCommands#zrangeWithScores}
* LexRange, LexRange)}, {@link SortedSetBaseCommands#zremrangebyscore}, {@link
* SortedSetBaseCommands#zrange}, and {@link SortedSetBaseCommands#zrangeWithScores}
*
* @see <a href="https://redis.io/commands/zcount/">redis.io</a>
* @see <a href="https://redis.io/commands/zremrangebyrank/">redis.io</a>
* @see <a href="https://redis.io/commands/zremrangebylex/">redis.io</a>
* @see <a href="https://redis.io/commands/zremrangebyscore/">redis.io</a>
* @see <a href="https://redis.io/commands/zrange/">redis.io</a>
*/
public class RangeOptions {
Expand Down
26 changes: 26 additions & 0 deletions java/client/src/test/java/glide/api/RedisClientTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.ZPopMin;
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.ZScore;
import static redis_request.RedisRequestOuterClass.RequestType.Zadd;
import static redis_request.RedisRequestOuterClass.RequestType.Zcard;
Expand Down Expand Up @@ -2506,6 +2507,31 @@ public void zremrangebylex_returns_success() {
assertEquals(value, payload);
}

@SneakyThrows
@Test
public void zremrangebyscore_returns_success() {
// setup
String key = "testKey";
String[] arguments = new String[] {key, "-inf", "10.0"};
Long value = 3L;

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

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

// exercise
CompletableFuture<Long> response =
service.zremrangebyscore(key, InfScoreBound.NEGATIVE_INFINITY, new ScoreBoundary(10, true));
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 @@ -86,6 +86,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.ZPopMin;
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.ZScore;
import static redis_request.RedisRequestOuterClass.RequestType.Zadd;
import static redis_request.RedisRequestOuterClass.RequestType.Zcard;
Expand All @@ -95,6 +96,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.Zrem;

import glide.api.models.commands.InfoOptions;
import glide.api.models.commands.RangeOptions;
import glide.api.models.commands.RangeOptions.InfLexBound;
import glide.api.models.commands.RangeOptions.InfScoreBound;
import glide.api.models.commands.RangeOptions.LexBoundary;
Expand Down Expand Up @@ -387,6 +389,10 @@ public void transaction_builds_protobuf_request(BaseTransaction<?> transaction)
transaction.zremrangebylex("key", new LexBoundary("a", false), InfLexBound.POSITIVE_INFINITY);
results.add(Pair.of(ZRemRangeByLex, buildArgs("key", "(a", "+")));

transaction.zremrangebyscore(
"key", new ScoreBoundary(5, false), RangeOptions.InfScoreBound.POSITIVE_INFINITY);
results.add(Pair.of(ZRemRangeByScore, buildArgs("key", "(5.0", "+inf")));

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

Expand Down
45 changes: 45 additions & 0 deletions java/integTest/src/test/java/glide/SharedCommandTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import glide.api.models.Script;
import glide.api.models.commands.ExpireOptions;
import glide.api.models.commands.RangeOptions.InfLexBound;
import glide.api.models.commands.RangeOptions.InfScoreBound;
import glide.api.models.commands.RangeOptions.LexBoundary;
import glide.api.models.commands.RangeOptions.Limit;
import glide.api.models.commands.RangeOptions.RangeByIndex;
Expand Down Expand Up @@ -1565,6 +1566,50 @@ public void zremrangebylex(BaseClient client) {
assertTrue(executionException.getCause() instanceof RequestException);
}

@SneakyThrows
@ParameterizedTest
@MethodSource("getClients")
public void zremrangebyscore(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, "four", 4.0);
assertEquals(4, client.zadd(key1, membersScores).get());

// MinScore > MaxScore
assertEquals(
0,
client.zremrangebyscore(key1, new ScoreBoundary(1), InfScoreBound.NEGATIVE_INFINITY).get());
assertEquals(
Map.of("one", 1.0, "two", 2.0, "three", 3.0, "four", 4.0),
client.zrangeWithScores(key1, query).get());

assertEquals(
2, client.zremrangebyscore(key1, new ScoreBoundary(1, false), new ScoreBoundary(3)).get());
assertEquals(Map.of("one", 1.0, "four", 4.0), client.zrangeWithScores(key1, query).get());

assertEquals(
1,
client.zremrangebyscore(key1, new ScoreBoundary(4), InfScoreBound.POSITIVE_INFINITY).get());
assertEquals(Map.of("one", 1.0), client.zrangeWithScores(key1, query).get());

// Non Existing Key
assertEquals(
0,
client
.zremrangebyscore(
key2, InfScoreBound.NEGATIVE_INFINITY, InfScoreBound.POSITIVE_INFINITY)
.get());

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

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

baseTransaction.zadd(zSetKey2, Map.of("one", 1.0, "two", 2.0));
Expand Down Expand Up @@ -217,6 +218,7 @@ public static Object[] transactionTestResult() {
Map.of("three", 3.0), // zpopmax(key8)
0L, // zremrangebyrank(key8, 5, 10)
0L, // zremrangebylex(key8, new LexBoundary("j"), InfLexBound.POSITIVE_INFINITY)
0L, // zremrangebyscore(key8, new ScoreBoundary(5), InfScoreBound.POSITIVE_INFINITY)
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 2847b21

Please sign in to comment.