Skip to content

Commit

Permalink
Java: add xrevrange command (#341)
Browse files Browse the repository at this point in the history
* Init commit for XREVRANGE

Signed-off-by: Andrew Carbonetto <[email protected]>

* Updates to xrevrange

Signed-off-by: Andrew Carbonetto <[email protected]>

* Add XREVRANGE to rust

Signed-off-by: Andrew Carbonetto <[email protected]>

* Revert set changes

Signed-off-by: Andrew Carbonetto <[email protected]>

* Java: Add XREVRANGE command

Signed-off-by: Andrew Carbonetto <[email protected]>

* Documentation updates for xrevrange

Signed-off-by: Andrew Carbonetto <[email protected]>

* Revert small change

Signed-off-by: Andrew Carbonetto <[email protected]>

---------

Signed-off-by: Andrew Carbonetto <[email protected]>
  • Loading branch information
acarbonetto authored Jun 6, 2024
1 parent 4c6c081 commit 935b465
Show file tree
Hide file tree
Showing 10 changed files with 310 additions and 4 deletions.
2 changes: 1 addition & 1 deletion glide-core/src/client/value_conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,7 @@ pub(crate) fn expected_type_for_cmd(cmd: &Cmd) -> Option<ExpectedReturnType> {

// TODO use enum to avoid mistakes
match command.as_slice() {
b"HGETALL" | b"CONFIG GET" | b"FT.CONFIG GET" | b"HELLO" | b"XRANGE" => {
b"HGETALL" | b"CONFIG GET" | b"FT.CONFIG GET" | b"HELLO" | b"XRANGE" | b"XREVRANGE" => {
Some(ExpectedReturnType::Map {
key_type: &None,
value_type: &None,
Expand Down
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 @@ -206,6 +206,7 @@ enum RequestType {
BitFieldReadOnly = 173;
Move = 174;
SInterCard = 175;
XRevRange = 176;
}

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 @@ -176,6 +176,7 @@ pub enum RequestType {
BitFieldReadOnly = 173,
Move = 174,
SInterCard = 175,
XRevRange = 176,
}

fn get_two_word_command(first: &str, second: &str) -> Cmd {
Expand Down Expand Up @@ -355,6 +356,7 @@ impl From<::protobuf::EnumOrUnknown<ProtobufRequestType>> for RequestType {
ProtobufRequestType::BitFieldReadOnly => RequestType::BitFieldReadOnly,
ProtobufRequestType::Move => RequestType::Move,
ProtobufRequestType::SInterCard => RequestType::SInterCard,
ProtobufRequestType::XRevRange => RequestType::XRevRange,
}
}
}
Expand Down Expand Up @@ -530,6 +532,7 @@ impl RequestType {
RequestType::BitFieldReadOnly => Some(cmd("BITFIELD_RO")),
RequestType::Move => Some(cmd("MOVE")),
RequestType::SInterCard => Some(cmd("SINTERCARD")),
RequestType::XRevRange => Some(cmd("XREVRANGE")),
}
}
}
21 changes: 21 additions & 0 deletions java/client/src/main/java/glide/api/BaseClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.XDel;
import static redis_request.RedisRequestOuterClass.RequestType.XLen;
import static redis_request.RedisRequestOuterClass.RequestType.XRange;
import static redis_request.RedisRequestOuterClass.RequestType.XRevRange;
import static redis_request.RedisRequestOuterClass.RequestType.XTrim;
import static redis_request.RedisRequestOuterClass.RequestType.ZAdd;
import static redis_request.RedisRequestOuterClass.RequestType.ZCard;
Expand Down Expand Up @@ -1277,6 +1278,26 @@ public CompletableFuture<Map<String, String[]>> xrange(
XRange, arguments, response -> castMapOfArrays(handleMapResponse(response), String.class));
}

@Override
public CompletableFuture<Map<String, String[]>> xrevrange(
@NonNull String key, @NonNull StreamRange end, @NonNull StreamRange start) {
String[] arguments = ArrayUtils.addFirst(StreamRange.toArgs(end, start), key);
return commandManager.submitNewCommand(
XRevRange,
arguments,
response -> castMapOfArrays(handleMapResponse(response), String.class));
}

@Override
public CompletableFuture<Map<String, String[]>> xrevrange(
@NonNull String key, @NonNull StreamRange end, @NonNull StreamRange start, long count) {
String[] arguments = ArrayUtils.addFirst(StreamRange.toArgs(end, start, count), key);
return commandManager.submitNewCommand(
XRevRange,
arguments,
response -> castMapOfArrays(handleMapResponse(response), String.class));
}

@Override
public CompletableFuture<Long> pttl(@NonNull String key) {
return commandManager.submitNewCommand(PTTL, new String[] {key}, this::handleLongResponse);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,8 @@ public interface StreamBaseCommands {
* <li>Use {@link InfRangeBound#MAX} to end with the maximum available ID.
* </ul>
*
* @return @return A <code>Map</code> of key to stream entry data, where entry data is an array of
* item pairings.
* @return A <code>Map</code> of key to stream entry data, where entry data is an array of item
* pairings.
* @example
* <pre>{@code
* // Retrieve all stream entries
Expand Down Expand Up @@ -181,4 +181,82 @@ public interface StreamBaseCommands {
*/
CompletableFuture<Map<String, String[]>> xrange(
String key, StreamRange start, StreamRange end, long count);

/**
* Returns stream entries matching a given range of IDs in reverse order.<br>
* Equivalent to {@link #xrange(String, StreamRange, StreamRange)} but returns the entries in
* reverse order.
*
* @param key The key of the stream.
* @param end Ending stream ID bound for range.
* <ul>
* <li>Use {@link IdBound#of} to specify a stream ID.
* <li>Use {@link IdBound#ofExclusive} to specify an exclusive bounded stream ID.
* <li>Use {@link InfRangeBound#MAX} to end with the maximum available ID.
* </ul>
*
* @param start Starting stream ID bound for range.
* <ul>
* <li>Use {@link IdBound#of} to specify a stream ID.
* <li>Use {@link IdBound#ofExclusive} to specify an exclusive bounded stream ID.
* <li>Use {@link InfRangeBound#MIN} to start with the minimum available ID.
* </ul>
*
* @return A <code>Map</code> of key to stream entry data, where entry data is an array of item
* pairings.
* @example
* <pre>{@code
* // Retrieve all stream entries
* Map<String, String[]> result = client.xrevrange("key", InfRangeBound.MAX, InfRangeBound.MIN).get();
* result.forEach((k, v) -> {
* System.out.println("Stream ID: " + k);
* for (int i = 0; i < v.length;) {
* System.out.println(v[i++] + ": " + v[i++]);
* }
* });
* // Retrieve exactly one stream entry by id
* Map<String, String[]> result = client.xrevrange("key", IdBound.of(streamId), IdBound.of(streamId)).get();
* System.out.println("Stream ID: " + streamid + " -> " + Arrays.toString(result.get(streamid)));
* }</pre>
*/
CompletableFuture<Map<String, String[]>> xrevrange(
String key, StreamRange end, StreamRange start);

/**
* Returns stream entries matching a given range of IDs in reverse order.<br>
* Equivalent to {@link #xrange(String, StreamRange, StreamRange, long)} but returns the entries
* in reverse order.
*
* @param key The key of the stream.
* @param end Ending stream ID bound for range.
* <ul>
* <li>Use {@link IdBound#of} to specify a stream ID.
* <li>Use {@link IdBound#ofExclusive} to specify an exclusive bounded stream ID.
* <li>Use {@link InfRangeBound#MAX} to end with the maximum available ID.
* </ul>
*
* @param start Starting stream ID bound for range.
* <ul>
* <li>Use {@link IdBound#of} to specify a stream ID.
* <li>Use {@link IdBound#ofExclusive} to specify an exclusive bounded stream ID.
* <li>Use {@link InfRangeBound#MIN} to start with the minimum available ID.
* </ul>
*
* @param count Maximum count of stream entries to return.
* @return A <code>Map</code> of key to stream entry data, where entry data is an array of item
* pairings.
* @example
* <pre>{@code
* // Retrieve the first 2 stream entries
* Map<String, String[]> result = client.xrange("key", InfRangeBound.MAX, InfRangeBound.MIN, 2).get();
* result.forEach((k, v) -> {
* System.out.println("Stream ID: " + k);
* for (int i = 0; i < v.length;) {
* System.out.println(v[i++] + ": " + v[i++]);
* }
* });
* }</pre>
*/
CompletableFuture<Map<String, String[]>> xrevrange(
String key, StreamRange end, StreamRange start, long count);
}
66 changes: 66 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 @@ -133,6 +133,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.XDel;
import static redis_request.RedisRequestOuterClass.RequestType.XLen;
import static redis_request.RedisRequestOuterClass.RequestType.XRange;
import static redis_request.RedisRequestOuterClass.RequestType.XRevRange;
import static redis_request.RedisRequestOuterClass.RequestType.XTrim;
import static redis_request.RedisRequestOuterClass.RequestType.ZAdd;
import static redis_request.RedisRequestOuterClass.RequestType.ZCard;
Expand Down Expand Up @@ -2797,6 +2798,71 @@ public T xrange(
return getThis();
}

/**
* Returns stream entries matching a given range of IDs in reverse order.<br>
* Equivalent to {@link #xrange(String, StreamRange, StreamRange)} but returns the entries in
* reverse order.
*
* @param key The key of the stream.
* @param end Ending stream ID bound for range.
* <ul>
* <li>Use {@link StreamRange.IdBound#of} to specify a stream ID.
* <li>Use {@link StreamRange.IdBound#ofExclusive} to specify an exclusive bounded stream
* ID.
* <li>Use {@link StreamRange.InfRangeBound#MAX} to end with the maximum available ID.
* </ul>
*
* @param start Starting stream ID bound for range.
* <ul>
* <li>Use {@link StreamRange.IdBound#of} to specify a stream ID.
* <li>Use {@link StreamRange.IdBound#ofExclusive} to specify an exclusive bounded stream
* ID.
* <li>Use {@link StreamRange.InfRangeBound#MIN} to start with the minimum available ID.
* </ul>
*
* @return Command Response - A <code>Map</code> of key to stream entry data, where entry data is
* an array of item pairings.
*/
public T xrevrange(@NonNull String key, @NonNull StreamRange end, @NonNull StreamRange start) {
ArgsArray commandArgs = buildArgs(ArrayUtils.addFirst(StreamRange.toArgs(end, start), key));
protobufTransaction.addCommands(buildCommand(XRevRange, commandArgs));
return getThis();
}

/**
* Returns stream entries matching a given range of IDs in reverse order.<br>
* Equivalent to {@link #xrange(String, StreamRange, StreamRange, long)} but returns the entries
* in reverse order.
*
* @param key The key of the stream.
* @param start Starting stream ID bound for range.
* <ul>
* <li>Use {@link StreamRange.IdBound#of} to specify a stream ID.
* <li>Use {@link StreamRange.IdBound#ofExclusive} to specify an exclusive bounded stream
* ID.
* <li>Use {@link StreamRange.InfRangeBound#MIN} to start with the minimum available ID.
* </ul>
*
* @param end Ending stream ID bound for range.
* <ul>
* <li>Use {@link StreamRange.IdBound#of} to specify a stream ID.
* <li>Use {@link StreamRange.IdBound#ofExclusive} to specify an exclusive bounded stream
* ID.
* <li>Use {@link StreamRange.InfRangeBound#MAX} to end with the maximum available ID.
* </ul>
*
* @param count Maximum count of stream entries to return.
* @return Command Response - A <code>Map</code> of key to stream entry data, where entry data is
* an array of item pairings.
*/
public T xrevrange(
@NonNull String key, @NonNull StreamRange end, @NonNull StreamRange start, long count) {
ArgsArray commandArgs =
buildArgs(ArrayUtils.addFirst(StreamRange.toArgs(end, start, count), key));
protobufTransaction.addCommands(buildCommand(XRevRange, commandArgs));
return getThis();
}

/**
* Returns the remaining time to live of <code>key</code> that has a timeout, in milliseconds.
*
Expand Down
65 changes: 65 additions & 0 deletions java/client/src/test/java/glide/api/RedisClientTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.XDel;
import static redis_request.RedisRequestOuterClass.RequestType.XLen;
import static redis_request.RedisRequestOuterClass.RequestType.XRange;
import static redis_request.RedisRequestOuterClass.RequestType.XRevRange;
import static redis_request.RedisRequestOuterClass.RequestType.XTrim;
import static redis_request.RedisRequestOuterClass.RequestType.ZAdd;
import static redis_request.RedisRequestOuterClass.RequestType.ZCard;
Expand Down Expand Up @@ -4139,6 +4140,70 @@ public void xrange_withcount_returns_success() {
assertEquals(completedResult, payload);
}

@Test
@SneakyThrows
public void xrevrange_returns_success() {
// setup
String key = "testKey";
StreamRange end = IdBound.of(9999L);
StreamRange start = IdBound.ofExclusive("696969-10");
Map<String, String[]> completedResult =
Map.of(key, new String[] {"duration", "12345", "event-id", "2", "user-id", "42"});

CompletableFuture<Map<String, String[]>> testResponse = new CompletableFuture<>();
testResponse.complete(completedResult);

// match on protobuf request
when(commandManager.<Map<String, String[]>>submitNewCommand(
eq(XRevRange), eq(new String[] {key, "9999", "(696969-10"}), any()))
.thenReturn(testResponse);

// exercise
CompletableFuture<Map<String, String[]>> response = service.xrevrange(key, end, start);
Map<String, String[]> payload = response.get();

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

@Test
@SneakyThrows
public void xrevrange_withcount_returns_success() {
// setup
String key = "testKey";
StreamRange end = InfRangeBound.MAX;
StreamRange start = InfRangeBound.MIN;
long count = 99L;
Map<String, String[]> completedResult =
Map.of(key, new String[] {"duration", "12345", "event-id", "2", "user-id", "42"});

CompletableFuture<Map<String, String[]>> testResponse = new CompletableFuture<>();
testResponse.complete(completedResult);

// match on protobuf request
when(commandManager.<Map<String, String[]>>submitNewCommand(
eq(XRevRange),
eq(
new String[] {
key,
MAXIMUM_RANGE_REDIS_API,
MINIMUM_RANGE_REDIS_API,
RANGE_COUNT_REDIS_API,
Long.toString(count)
}),
any()))
.thenReturn(testResponse);

// exercise
CompletableFuture<Map<String, String[]>> response = service.xrevrange(key, end, start, count);
Map<String, String[]> payload = response.get();

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

@SneakyThrows
@Test
public void type_returns_success() {
Expand Down
16 changes: 16 additions & 0 deletions java/client/src/test/java/glide/api/models/TransactionTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.XDel;
import static redis_request.RedisRequestOuterClass.RequestType.XLen;
import static redis_request.RedisRequestOuterClass.RequestType.XRange;
import static redis_request.RedisRequestOuterClass.RequestType.XRevRange;
import static redis_request.RedisRequestOuterClass.RequestType.XTrim;
import static redis_request.RedisRequestOuterClass.RequestType.ZAdd;
import static redis_request.RedisRequestOuterClass.RequestType.ZCard;
Expand Down Expand Up @@ -713,6 +714,21 @@ InfScoreBound.NEGATIVE_INFINITY, new ScoreBoundary(3, false), new Limit(1, 2)),
RANGE_COUNT_REDIS_API,
"99")));

transaction.xrevrange("key", InfRangeBound.MAX, InfRangeBound.MIN);
results.add(
Pair.of(XRevRange, buildArgs("key", MAXIMUM_RANGE_REDIS_API, MINIMUM_RANGE_REDIS_API)));

transaction.xrevrange("key", InfRangeBound.MAX, InfRangeBound.MIN, 99L);
results.add(
Pair.of(
XRevRange,
buildArgs(
"key",
MAXIMUM_RANGE_REDIS_API,
MINIMUM_RANGE_REDIS_API,
RANGE_COUNT_REDIS_API,
"99")));

transaction.time();
results.add(Pair.of(Time, buildArgs()));

Expand Down
Loading

0 comments on commit 935b465

Please sign in to comment.