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 xrevrange command #1534

Merged
Merged
Show file tree
Hide file tree
Changes from 4 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
24 changes: 23 additions & 1 deletion glide-core/src/client/value_conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -683,12 +683,16 @@ 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" => {
Some(ExpectedReturnType::Map {
key_type: &None,
value_type: &None,
})
}
b"XRANGE" | b"XREVRANGE" => Some(ExpectedReturnType::Map {
key_type: &Some(ExpectedReturnType::BulkString),
value_type: &Some(ExpectedReturnType::ArrayOfPairs),
}),
b"XREAD" => Some(ExpectedReturnType::Map {
key_type: &Some(ExpectedReturnType::BulkString),
value_type: &Some(ExpectedReturnType::Map {
Expand Down Expand Up @@ -988,6 +992,24 @@ mod tests {
assert!(converted_4.is_err());
}

#[test]
fn convert_xrange_xrevrange() {
assert!(matches!(
expected_type_for_cmd(redis::cmd("XRANGE").arg("key").arg("start").arg("end")),
Some(ExpectedReturnType::Map {
key_type: &Some(ExpectedReturnType::BulkString),
value_type: &Some(ExpectedReturnType::ArrayOfPairs),
})
));
assert!(matches!(
expected_type_for_cmd(redis::cmd("XREVRANGE").arg("key").arg("end").arg("start")),
Some(ExpectedReturnType::Map {
key_type: &Some(ExpectedReturnType::BulkString),
value_type: &Some(ExpectedReturnType::ArrayOfPairs),
})
));
}

#[test]
fn convert_xread() {
assert!(matches!(
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 @@ -210,6 +210,7 @@ enum RequestType {
BitFieldReadOnly = 173;
Move = 174;
SInterCard = 175;
XRevRange = 176;
Copy = 178;
}

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

Expand Down Expand Up @@ -365,6 +366,7 @@ impl From<::protobuf::EnumOrUnknown<ProtobufRequestType>> for RequestType {
ProtobufRequestType::SInterCard => RequestType::SInterCard,
ProtobufRequestType::Copy => RequestType::Copy,
ProtobufRequestType::Sort => RequestType::Sort,
ProtobufRequestType::XRevRange => RequestType::XRevRange,
}
}
}
Expand Down Expand Up @@ -545,6 +547,7 @@ impl RequestType {
RequestType::SInterCard => Some(cmd("SINTERCARD")),
RequestType::Copy => Some(cmd("COPY")),
RequestType::Sort => Some(cmd("SORT")),
RequestType::XRevRange => Some(cmd("XREVRANGE")),
}
}
}
29 changes: 25 additions & 4 deletions java/client/src/main/java/glide/api/BaseClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.XLen;
import static redis_request.RedisRequestOuterClass.RequestType.XRange;
import static redis_request.RedisRequestOuterClass.RequestType.XRead;
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 @@ -1322,19 +1323,39 @@ public CompletableFuture<Long> xdel(@NonNull String key, @NonNull String[] ids)
}

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

@Override
public CompletableFuture<Map<String, String[]>> xrange(
public CompletableFuture<Map<String, String[][]>> xrange(
@NonNull String key, @NonNull StreamRange start, @NonNull StreamRange end, long count) {
String[] arguments = ArrayUtils.addFirst(StreamRange.toArgs(start, end, count), key);
return commandManager.submitNewCommand(
XRange, arguments, response -> castMapOfArrays(handleMapResponse(response), String.class));
XRange, arguments, response -> castMapOf2DArray(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 -> castMapOf2DArray(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 -> castMapOf2DArray(handleMapResponse(response), String.class));
}

@Override
Expand Down
100 changes: 87 additions & 13 deletions java/client/src/main/java/glide/api/commands/StreamBaseCommands.java
Original file line number Diff line number Diff line change
Expand Up @@ -184,24 +184,23 @@ CompletableFuture<Map<String, Map<String, String[][]>>> xread(
* <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 pairings with format <code>[[field, entry], [field, entry], ...]<code>
* @example
* <pre>{@code
* // Retrieve all stream entries
* Map<String, String[]> result = client.xrange("key", InfRangeBound.MIN, InfRangeBound.MAX).get();
* Map<String, String[][]> result = client.xrange("key", InfRangeBound.MIN, InfRangeBound.MAX).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++]);
* for (int i = 0; i < v.length; i++) {
* System.out.println(v[i][0] + ": " + v[i][1]);
* }
* });
* // Retrieve exactly one stream entry by id
* Map<String, String[]> result = client.xrange("key", IdBound.of(streamId), IdBound.of(streamId)).get();
* Map<String, String[][]> result = client.xrange("key", IdBound.of(streamId), IdBound.of(streamId)).get();
* System.out.println("Stream ID: " + streamid + " -> " + Arrays.toString(result.get(streamid)));
* }</pre>
*/
CompletableFuture<Map<String, String[]>> xrange(String key, StreamRange start, StreamRange end);
CompletableFuture<Map<String, String[][]>> xrange(String key, StreamRange start, StreamRange end);

/**
* Returns stream entries matching a given range of IDs.
Expand All @@ -222,20 +221,95 @@ CompletableFuture<Map<String, Map<String, String[][]>>> xread(
* </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.
* @return A <code>Map</code> of key to stream entry data, where entry data is an array of pairings with format <code>[[field, entry], [field, entry], ...]<code>
* @example
* <pre>{@code
* // Retrieve the first 2 stream entries
* Map<String, String[]> result = client.xrange("key", InfRangeBound.MIN, InfRangeBound.MAX, 2).get();
* Map<String, String[][]> result = client.xrange("key", InfRangeBound.MIN, InfRangeBound.MAX, 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++]);
* for (int i = 0; i < v.length; i++) {
* System.out.println(v[i][0] + ": " + v[i][1]);
* }
* });
* }</pre>
*/
CompletableFuture<Map<String, String[]>> xrange(
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 pairings with format <code>[[field, entry], [field, entry], ...]<code>
* @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; i++) {
* System.out.println(v[i][0] + ": " + v[i][1]);
* }
* });
* // 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 pairings with format <code>[[field, entry], [field, entry], ...]<code>
acarbonetto marked this conversation as resolved.
Show resolved Hide resolved
* @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; i++) {
* System.out.println(v[i][0] + ": " + v[i][1]);
* }
* });
* }</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 @@ -143,6 +143,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.XLen;
import static redis_request.RedisRequestOuterClass.RequestType.XRange;
import static redis_request.RedisRequestOuterClass.RequestType.XRead;
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 @@ -2783,6 +2784,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
acarbonetto marked this conversation as resolved.
Show resolved Hide resolved
* 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
Loading
Loading