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 SORT and SORT_RO commands #363

Merged
merged 18 commits into from
Jun 19, 2024
Merged
Show file tree
Hide file tree
Changes from 17 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
2 changes: 2 additions & 0 deletions glide-core/src/protobuf/redis_request.proto
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,8 @@ enum RequestType {
BitFieldReadOnly = 173;
Move = 174;
SInterCard = 175;
Sort = 176;
SortReadOnly = 177;
}

message Command {
Expand Down
6 changes: 6 additions & 0 deletions glide-core/src/request_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ pub enum RequestType {
BitFieldReadOnly = 173,
Move = 174,
SInterCard = 175,
Sort = 176,
SortReadOnly = 177,
}

fn get_two_word_command(first: &str, second: &str) -> Cmd {
Expand Down Expand Up @@ -355,6 +357,8 @@ impl From<::protobuf::EnumOrUnknown<ProtobufRequestType>> for RequestType {
ProtobufRequestType::BitFieldReadOnly => RequestType::BitFieldReadOnly,
ProtobufRequestType::Move => RequestType::Move,
ProtobufRequestType::SInterCard => RequestType::SInterCard,
ProtobufRequestType::Sort => RequestType::Sort,
ProtobufRequestType::SortReadOnly => RequestType::SortReadOnly,
}
}
}
Expand Down Expand Up @@ -530,6 +534,8 @@ impl RequestType {
RequestType::BitFieldReadOnly => Some(cmd("BITFIELD_RO")),
RequestType::Move => Some(cmd("MOVE")),
RequestType::SInterCard => Some(cmd("SINTERCARD")),
RequestType::Sort => Some(cmd("SORT")),
RequestType::SortReadOnly => Some(cmd("SORT_RO")),
}
}
}
53 changes: 53 additions & 0 deletions java/client/src/main/java/glide/api/BaseClient.java
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.api;

import static glide.api.models.commands.SortOptions.STORE_COMMAND_STRING;
import static glide.api.models.commands.bitmap.BitFieldOptions.BitFieldReadOnlySubCommands;
import static glide.api.models.commands.bitmap.BitFieldOptions.BitFieldSubCommands;
import static glide.api.models.commands.bitmap.BitFieldOptions.createBitFieldArgs;
Expand Down Expand Up @@ -105,6 +106,8 @@
import static redis_request.RedisRequestOuterClass.RequestType.Set;
import static redis_request.RedisRequestOuterClass.RequestType.SetBit;
import static redis_request.RedisRequestOuterClass.RequestType.SetRange;
import static redis_request.RedisRequestOuterClass.RequestType.Sort;
import static redis_request.RedisRequestOuterClass.RequestType.SortReadOnly;
import static redis_request.RedisRequestOuterClass.RequestType.Strlen;
import static redis_request.RedisRequestOuterClass.RequestType.TTL;
import static redis_request.RedisRequestOuterClass.RequestType.Touch;
Expand Down Expand Up @@ -164,6 +167,7 @@
import glide.api.models.commands.ScoreFilter;
import glide.api.models.commands.ScriptOptions;
import glide.api.models.commands.SetOptions;
import glide.api.models.commands.SortBaseOptions;
import glide.api.models.commands.WeightAggregateOptions.Aggregate;
import glide.api.models.commands.WeightAggregateOptions.KeysOrWeightedKeys;
import glide.api.models.commands.ZAddOptions;
Expand Down Expand Up @@ -1677,4 +1681,53 @@ public CompletableFuture<Long> sintercard(@NonNull String[] keys, long limit) {
new String[] {SET_LIMIT_REDIS_API, Long.toString(limit)});
return commandManager.submitNewCommand(SInterCard, arguments, this::handleLongResponse);
}

@Override
public CompletableFuture<String[]> sort(@NonNull String key) {
return commandManager.submitNewCommand(
Sort,
new String[] {key},
response -> castArray(handleArrayResponse(response), String.class));
}

@Override
public CompletableFuture<String[]> sort(
@NonNull String key, @NonNull SortBaseOptions sortBaseOptions) {
String[] arguments = ArrayUtils.addFirst(sortBaseOptions.toArgs(), key);
return commandManager.submitNewCommand(
Sort, arguments, response -> castArray(handleArrayResponse(response), String.class));
}

@Override
public CompletableFuture<String[]> sortReadOnly(@NonNull String key) {
return commandManager.submitNewCommand(
SortReadOnly,
new String[] {key},
response -> castArray(handleArrayResponse(response), String.class));
}

@Override
public CompletableFuture<String[]> sortReadOnly(
@NonNull String key, @NonNull SortBaseOptions sortBaseOptions) {
String[] arguments = ArrayUtils.addFirst(sortBaseOptions.toArgs(), key);
return commandManager.submitNewCommand(
SortReadOnly,
arguments,
response -> castArray(handleArrayResponse(response), String.class));
}

@Override
public CompletableFuture<Long> sortStore(@NonNull String key, @NonNull String destination) {
return commandManager.submitNewCommand(
Sort, new String[] {key, STORE_COMMAND_STRING, destination}, this::handleLongResponse);
}

@Override
public CompletableFuture<Long> sortStore(
@NonNull String key, @NonNull String destination, @NonNull SortBaseOptions sortBaseOptions) {
String[] storeArguments = new String[] {STORE_COMMAND_STRING, destination};
String[] arguments =
ArrayUtils.addFirst(concatenateArrays(storeArguments, sortBaseOptions.toArgs()), key);
return commandManager.submitNewCommand(Sort, arguments, this::handleLongResponse);
}
}
34 changes: 34 additions & 0 deletions java/client/src/main/java/glide/api/RedisClient.java
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.api;

import static glide.api.models.commands.SortOptions.STORE_COMMAND_STRING;
import static glide.api.models.commands.function.FunctionLoadOptions.REPLACE;
import static glide.utils.ArrayTransformUtils.castArray;
import static glide.utils.ArrayTransformUtils.concatenateArrays;
Expand All @@ -21,6 +22,8 @@
import static redis_request.RedisRequestOuterClass.RequestType.Move;
import static redis_request.RedisRequestOuterClass.RequestType.Ping;
import static redis_request.RedisRequestOuterClass.RequestType.Select;
import static redis_request.RedisRequestOuterClass.RequestType.Sort;
import static redis_request.RedisRequestOuterClass.RequestType.SortReadOnly;
import static redis_request.RedisRequestOuterClass.RequestType.Time;

import glide.api.commands.ConnectionManagementCommands;
Expand All @@ -30,13 +33,15 @@
import glide.api.models.Transaction;
import glide.api.models.commands.FlushMode;
import glide.api.models.commands.InfoOptions;
import glide.api.models.commands.SortStandaloneOptions;
import glide.api.models.configuration.RedisClientConfiguration;
import glide.managers.CommandManager;
import glide.managers.ConnectionManager;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import lombok.NonNull;
import org.apache.commons.lang3.ArrayUtils;

/**
* Async (non-blocking) client for Redis in Standalone mode. Use {@link #CreateClient} to request a
Expand Down Expand Up @@ -203,4 +208,33 @@ public CompletableFuture<Boolean> move(@NonNull String key, long dbIndex) {
return commandManager.submitNewCommand(
Move, new String[] {key, Long.toString(dbIndex)}, this::handleBooleanResponse);
}

@Override
public CompletableFuture<String[]> sort(
@NonNull String key, @NonNull SortStandaloneOptions sortStandaloneOptions) {
String[] arguments = ArrayUtils.addFirst(sortStandaloneOptions.toArgs(), key);
return commandManager.submitNewCommand(
Sort, arguments, response -> castArray(handleArrayResponse(response), String.class));
}

@Override
public CompletableFuture<String[]> sortReadOnly(
@NonNull String key, @NonNull SortStandaloneOptions sortStandaloneOptions) {
String[] arguments = ArrayUtils.addFirst(sortStandaloneOptions.toArgs(), key);
return commandManager.submitNewCommand(
SortReadOnly,
arguments,
response -> castArray(handleArrayResponse(response), String.class));
}

@Override
public CompletableFuture<Long> sortStore(
@NonNull String key,
@NonNull String destination,
@NonNull SortStandaloneOptions sortStandaloneOptions) {
String[] storeArguments = new String[] {STORE_COMMAND_STRING, destination};
String[] arguments =
ArrayUtils.addFirst(concatenateArrays(storeArguments, sortStandaloneOptions.toArgs()), key);
return commandManager.submitNewCommand(Sort, arguments, this::handleLongResponse);
}
}
148 changes: 148 additions & 0 deletions java/client/src/main/java/glide/api/commands/GenericBaseCommands.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import glide.api.models.Script;
import glide.api.models.commands.ExpireOptions;
import glide.api.models.commands.ScriptOptions;
import glide.api.models.commands.SortBaseOptions;
import glide.api.models.configuration.ReadFrom;
import java.util.concurrent.CompletableFuture;

/**
Expand Down Expand Up @@ -542,4 +544,150 @@ CompletableFuture<Boolean> pexpireAt(
* }</pre>
*/
CompletableFuture<Long> touch(String[] keys);

/**
* Sorts the elements in the list, set, or sorted set at <code>key</code> and returns the result.
* The <code>sort</code> command can be used to sort elements based on different criteria and
* apply transformations on sorted elements.<br>
* To store the result into a new key, see {@link #sortStore(String, String)}.
*
* @param key The key of the list, set, or sorted set to be sorted.
* @return A list of sorted elements.
* @example
* <pre>{@code
* client.lpush("mylist", new String[] {"3", "1", "2"}).get();
* assertArrayEquals(new String[] {"1", "2", "3"}, client.sort("mylist").get()); // List is sorted in ascending order
* }</pre>
*/
CompletableFuture<String[]> sort(String key);

/**
* Sorts the elements in the list, set, or sorted set at <code>key</code> and returns the result.
* The <code>sort</code> command can be used to sort elements based on different criteria and
* apply transformations on sorted elements.<br>
* To store the result into a new key, see {@link #sortStore(String, String, SortBaseOptions)}.
*
* @param key The key of the list, set, or sorted set to be sorted.
* @param sortBaseOptions The {@link SortBaseOptions}.
* @return A <code>Array</code> of sorted elements.
* @example
* <pre>{@code
* client.lpush("mylist", new String[] {"3", "1", "2", "a"}).get();
* String[] payload = client.sort(
* "mylist",
* SortBaseOptions.builder()
* .alpha(true)
* .orderBy(DESC)
* .limit(new SortOptions.Limit(0L, 3L))
* .build())
* .get();
* assertArrayEquals(new String[] {"a", "3", "2"}, payload); // List is sorted in descending order lexicographically starting
* }</pre>
*/
CompletableFuture<String[]> sort(String key, SortBaseOptions sortBaseOptions);

/**
* Sorts the elements in the list, set, or sorted set at <code>key</code> and returns the result.
* <br>
* The <code>sortReadOnly</code> command can be used to sort elements based on different criteria
* and apply transformations on sorted elements.<br>
* This command is routed depending on the client's {@link ReadFrom} strategy.
*
* @since Redis 7.0 and above.
* @param key The key of the list, set, or sorted set to be sorted.
* @return A <code>Array</code> of sorted elements.
* @example
* <pre>{@code
* client.lpush("mylist", new String[] {"3", "1", "2"}).get();
* assertArrayEquals(new String[] {"1", "2", "3"}, client.sortReadOnly("mylist").get()); // List is sorted in ascending order
* }</pre>
*/
CompletableFuture<String[]> sortReadOnly(String key);

/**
* Sorts the elements in the list, set, or sorted set at <code>key</code> and returns the result.
* <br>
* The <code>sortReadOnly</code> command can be used to sort elements based on different criteria
* and apply transformations on sorted elements.<br>
* This command is routed depending on the client's {@link ReadFrom} strategy.
*
* @since Redis 7.0 and above.
* @param key The key of the list, set, or sorted set to be sorted.
* @param sortBaseOptions The {@link SortBaseOptions}.
* @return A <code>Array</code> of sorted elements.
* @example
* <pre>{@code
* client.lpush("mylist", new String[] {"3", "1", "2", "a"}).get();
* String[] payload = client.sortReadOnly(
* "mylist",
* SortBaseOptions.builder()
* .alpha(true)
* .orderBy(DESC)
* .limit(new SortOptions.Limit(0L, 3L))
* .build())
* .get();
* assertArrayEquals(new String[] {"a", "3", "2"}, payload); // List is sorted in descending order lexicographically starting
* }</pre>
*/
CompletableFuture<String[]> sortReadOnly(String key, SortBaseOptions sortBaseOptions);

/**
* Sorts the elements in the list, set, or sorted set at <code>key</code> and stores the result in
* <code>destination</code>. The <code>sort</code> command can be used to sort elements based on
* different criteria, apply transformations on sorted elements, and store the result in a new
* key.<br>
* To get the sort result without storing it into a key, see {@link #sort(String)} and {@link
* #sortReadOnly(String)}.
*
* @apiNote When in cluster mode, <code>key</code> and <code>destination</code> must map to the
* same hash slot.
* @param key The key of the list, set, or sorted set to be sorted.
* @param destination The key where the sorted result will be stored.
* @return The number of elements in the sorted key stored at <code>destination</code>.
* @example
* <pre>{@code
* client.lpush("mylist", new String[] {"3", "1", "2"}).get();
* assert client.sortStore("mylist", "destination").get() == 3;
* assertArrayEquals(
* new String[] {"1", "2", "3"},
* client.lrange("destination", 0, -1).get()); // Sorted list is stored in `destination`
* }</pre>
*/
CompletableFuture<Long> sortStore(String key, String destination);

/**
* Sorts the elements in the list, set, or sorted set at <code>key</code> and stores the result in
* <code>destination</code>. The <code>sort</code> command can be used to sort elements based on
* different criteria, apply transformations on sorted elements, and store the result in a new
* key.<br>
* To get the sort result without storing it into a key, see {@link #sort(String,
* SortBaseOptions)} and {@link #sortReadOnly(String, SortBaseOptions)}.
*
* @apiNote When in cluster mode, <code>key</code> and <code>destination</code> must map to the
* same hash slot.
* @param key The key of the list, set, or sorted set to be sorted.
* @param destination The key where the sorted result will be stored.
* @param sortBaseOptions The {@link SortBaseOptions}.
* @return The number of elements in the sorted key stored at <code>destination</code>.
* @example
* <pre>{@code
* client.lpush("mylist", new String[] {"3", "1", "2", "a"}).get();
* Long payload = client
* .sortStore(
* "mylist",
* "destination",
* SortBaseOptions.builder()
* .alpha(true)
* .orderBy(DESC)
* .limit(new SortOptions.Limit(0L, 3L))
* .build())
* .get();
* assertEquals(3, payload);
* assertArrayEquals(
* new String[] {"a", "3", "2"},
* client.lrange("destination", 0, -1).get()); // Sorted list is stored in "destination"
* }</pre>
*/
CompletableFuture<Long> sortStore(
String key, String destination, SortBaseOptions sortBaseOptions);
}
Loading
Loading