Skip to content

Commit

Permalink
Java: Adding command COPY (valkey-io#1532)
Browse files Browse the repository at this point in the history
Java: Adding command COPY (#340)

* Java: Adding command COPY
  • Loading branch information
tjzhang-BQ authored and yipin-chen committed Jun 7, 2024
1 parent 1fa7178 commit 1eaef18
Show file tree
Hide file tree
Showing 17 changed files with 464 additions and 13 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 @@ -698,7 +698,7 @@ pub(crate) fn expected_type_for_cmd(cmd: &Cmd) -> Option<ExpectedReturnType> {
}),
b"INCRBYFLOAT" | b"HINCRBYFLOAT" | b"ZINCRBY" => Some(ExpectedReturnType::Double),
b"HEXISTS" | b"HSETNX" | b"EXPIRE" | b"EXPIREAT" | b"PEXPIRE" | b"PEXPIREAT"
| b"SISMEMBER" | b"PERSIST" | b"SMOVE" | b"RENAMENX" | b"MOVE" => {
| b"SISMEMBER" | b"PERSIST" | b"SMOVE" | b"RENAMENX" | b"MOVE" | b"COPY" => {
Some(ExpectedReturnType::Boolean)
}
b"SMISMEMBER" => Some(ExpectedReturnType::ArrayOfBools),
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;
Copy = 178;
}

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

fn get_two_word_command(first: &str, second: &str) -> Cmd {
Expand Down Expand Up @@ -362,6 +363,7 @@ impl From<::protobuf::EnumOrUnknown<ProtobufRequestType>> for RequestType {
ProtobufRequestType::BitFieldReadOnly => RequestType::BitFieldReadOnly,
ProtobufRequestType::Move => RequestType::Move,
ProtobufRequestType::SInterCard => RequestType::SInterCard,
ProtobufRequestType::Copy => RequestType::Copy,
ProtobufRequestType::Sort => RequestType::Sort,
}
}
Expand Down Expand Up @@ -541,6 +543,7 @@ impl RequestType {
RequestType::BitFieldReadOnly => Some(cmd("BITFIELD_RO")),
RequestType::Move => Some(cmd("MOVE")),
RequestType::SInterCard => Some(cmd("SINTERCARD")),
RequestType::Copy => Some(cmd("COPY")),
RequestType::Sort => Some(cmd("SORT")),
}
}
Expand Down
17 changes: 17 additions & 0 deletions java/client/src/main/java/glide/api/BaseClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.BitFieldReadOnly;
import static redis_request.RedisRequestOuterClass.RequestType.BitOp;
import static redis_request.RedisRequestOuterClass.RequestType.BitPos;
import static redis_request.RedisRequestOuterClass.RequestType.Copy;
import static redis_request.RedisRequestOuterClass.RequestType.Decr;
import static redis_request.RedisRequestOuterClass.RequestType.DecrBy;
import static redis_request.RedisRequestOuterClass.RequestType.Del;
Expand Down Expand Up @@ -1733,4 +1734,20 @@ 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<Boolean> copy(
@NonNull String source, @NonNull String destination, boolean replace) {
String[] arguments = new String[] {source, destination};
if (replace) {
arguments = ArrayUtils.add(arguments, REPLACE_REDIS_API);
}
return commandManager.submitNewCommand(Copy, arguments, this::handleBooleanResponse);
}

@Override
public CompletableFuture<Boolean> copy(@NonNull String source, @NonNull String destination) {
String[] arguments = new String[] {source, destination};
return commandManager.submitNewCommand(Copy, arguments, this::handleBooleanResponse);
}
}
21 changes: 21 additions & 0 deletions java/client/src/main/java/glide/api/RedisClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.ConfigResetStat;
import static redis_request.RedisRequestOuterClass.RequestType.ConfigRewrite;
import static redis_request.RedisRequestOuterClass.RequestType.ConfigSet;
import static redis_request.RedisRequestOuterClass.RequestType.Copy;
import static redis_request.RedisRequestOuterClass.RequestType.CustomCommand;
import static redis_request.RedisRequestOuterClass.RequestType.DBSize;
import static redis_request.RedisRequestOuterClass.RequestType.Echo;
Expand Down Expand Up @@ -43,6 +44,7 @@
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 @@ -251,4 +253,23 @@ public CompletableFuture<String> functionDelete(@NonNull String libName) {
return commandManager.submitNewCommand(
FunctionDelete, new String[] {libName}, this::handleStringResponse);
}

@Override
public CompletableFuture<Boolean> copy(
@NonNull String source, @NonNull String destination, long destinationDB) {
String[] arguments =
new String[] {source, destination, DB_REDIS_API, Long.toString(destinationDB)};
return commandManager.submitNewCommand(Copy, arguments, this::handleBooleanResponse);
}

@Override
public CompletableFuture<Boolean> copy(
@NonNull String source, @NonNull String destination, long destinationDB, boolean replace) {
String[] arguments =
new String[] {source, destination, DB_REDIS_API, Long.toString(destinationDB)};
if (replace) {
arguments = ArrayUtils.add(arguments, REPLACE_REDIS_API);
}
return commandManager.submitNewCommand(Copy, arguments, this::handleBooleanResponse);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
* @see <a href="https://redis.io/commands/?group=generic">Generic Commands</a>
*/
public interface GenericBaseCommands {
/** Redis API keyword used to replace the destination key. */
String REPLACE_REDIS_API = "REPLACE";

/**
* Removes the specified <code>keys</code> from the database. A key is ignored if it does not
Expand Down Expand Up @@ -542,4 +544,50 @@ CompletableFuture<Boolean> pexpireAt(
* }</pre>
*/
CompletableFuture<Long> touch(String[] keys);

/**
* Copies the value stored at the <code>source</code> to the <code>destination</code> key if the
* <code>destination</code> key does not yet exist.
*
* @apiNote When in cluster mode, both <code>source</code> and <code>destination</code> must map
* to the same hash slot.
* @since Redis 6.2.0 and above.
* @see <a href="https://redis.io/commands/copy/">redis.io</a> for details.
* @param source The key to the source value.
* @param destination The key where the value should be copied to.
* @return <code>true</code> if <code>source</code> was copied, <code>false</code> if <code>source
* </code> was not copied.
* @example
* <pre>{@code
* client.set("test1", "one").get();
* client.set("test2", "two").get();
* assert !client.copy("test1", "test2").get();
* assert client.copy("test1", "test2").get();
* }</pre>
*/
CompletableFuture<Boolean> copy(String source, String destination);

/**
* Copies the value stored at the <code>source</code> to the <code>destination</code> key. When
* <code>replace</code> is true, removes the <code>destination</code> key first if it already
* exists, otherwise performs no action.
*
* @apiNote When in cluster mode, both <code>source</code> and <code>destination</code> must map
* to the same hash slot.
* @since Redis 6.2.0 and above.
* @see <a href="https://redis.io/commands/copy/">redis.io</a> for details.
* @param source The key to the source value.
* @param destination The key where the value should be copied to.
* @param replace If the destination key should be removed before copying the value to it.
* @return <code>true</code> if <code>source</code> was copied, <code>false</code> if <code>source
* </code> was not copied.
* @example
* <pre>{@code
* client.set("test1", "one").get();
* client.set("test2", "two").get();
* assert !client.copy("test1", "test2", false).get();
* assert client.copy("test1", "test2", true).get();
* }</pre>
*/
CompletableFuture<Boolean> copy(String source, String destination, boolean replace);
}
44 changes: 44 additions & 0 deletions java/client/src/main/java/glide/api/commands/GenericCommands.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
* @see <a href="https://redis.io/commands/?group=generic">Generic Commands</a>
*/
public interface GenericCommands {
/** Redis API keyword used to denote the destination db index. */
String DB_REDIS_API = "DB";

/**
* Executes a single command, without checking inputs. Every part of the command, including
Expand Down Expand Up @@ -72,4 +74,46 @@ public interface GenericCommands {
* }</pre>
*/
CompletableFuture<Boolean> move(String key, long dbIndex);

/**
* Copies the value stored at the <code>source</code> to the <code>destination</code> key on
* <code>destinationDB</code>. When <code>replace</code> is true, removes the <code>destination
* </code> key first if it already exists, otherwise performs no action.
*
* @since Redis 6.2.0 and above.
* @see <a href="https://redis.io/commands/copy/">redis.io</a> for details.
* @param source The key to the source value.
* @param destination The key where the value should be copied to.
* @param destinationDB The alternative logical database index for the destination key.
* @param replace If the destination key should be removed before copying the value to it.
* @return <code>true</code> if <code>source</code> was copied, <code>false</code> if <code>source
* </code> was not copied.
* @example
* <pre>{@code
* client.set("test1", "one").get();
* assert client.copy("test1", "test2", 1, false).get();
* }</pre>
*/
CompletableFuture<Boolean> copy(
String source, String destination, long destinationDB, boolean replace);

/**
* Copies the value stored at the <code>source</code> to the <code>destination</code> key on
* <code>destinationDB</code>. When <code>replace</code> is true, removes the <code>destination
* </code> key first if it already exists, otherwise performs no action.
*
* @since Redis 6.2.0 and above.
* @see <a href="https://redis.io/commands/copy/">redis.io</a> for details.
* @param source The key to the source value.
* @param destination The key where the value should be copied to.
* @param destinationDB The alternative logical database index for the destination key.
* @return <code>true</code> if <code>source</code> was copied, <code>false</code> if <code>source
* </code> was not copied.
* @example
* <pre>{@code
* client.set("test1", "one").get();
* assert client.copy("test1", "test2", 1).get();
* }</pre>
*/
CompletableFuture<Boolean> copy(String source, String destination, long destinationDB);
}
40 changes: 40 additions & 0 deletions java/client/src/main/java/glide/api/models/BaseTransaction.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.models;

import static glide.api.commands.GenericBaseCommands.REPLACE_REDIS_API;
import static glide.api.commands.HashBaseCommands.WITH_VALUES_REDIS_API;
import static glide.api.commands.ListBaseCommands.COUNT_FOR_LIST_REDIS_API;
import static glide.api.commands.ServerManagementCommands.VERSION_REDIS_API;
Expand Down Expand Up @@ -37,6 +38,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.ConfigResetStat;
import static redis_request.RedisRequestOuterClass.RequestType.ConfigRewrite;
import static redis_request.RedisRequestOuterClass.RequestType.ConfigSet;
import static redis_request.RedisRequestOuterClass.RequestType.Copy;
import static redis_request.RedisRequestOuterClass.RequestType.CustomCommand;
import static redis_request.RedisRequestOuterClass.RequestType.DBSize;
import static redis_request.RedisRequestOuterClass.RequestType.Decr;
Expand Down Expand Up @@ -3457,6 +3459,44 @@ public T touch(@NonNull String[] keys) {
return getThis();
}

/**
* Copies the value stored at the <code>source</code> to the <code>destination</code> key. When
* <code>replace</code> is true, removes the <code>destination</code> key first if it already
* exists, otherwise performs no action.
*
* @since Redis 6.2.0 and above.
* @see <a href="https://redis.io/commands/copy/">redis.io</a> for details.
* @param source The key to the source value.
* @param destination The key where the value should be copied to.
* @param replace If the destination key should be removed before copying the value to it.
* @return Command Response - <code>1L</code> if <code>source</code> was copied, <code>0L</code>
* if <code>source</code> was not copied.
*/
public T copy(@NonNull String source, @NonNull String destination, boolean replace) {
String[] args = new String[] {source, destination};
if (replace) {
args = ArrayUtils.add(args, REPLACE_REDIS_API);
}
ArgsArray commandArgs = buildArgs(args);
protobufTransaction.addCommands(buildCommand(Copy, commandArgs));
return getThis();
}

/**
* Copies the value stored at the <code>source</code> to the <code>destination</code> key if the
* <code>destination</code> key does not yet exist.
*
* @since Redis 6.2.0 and above.
* @see <a href="https://redis.io/commands/copy/">redis.io</a> for details.
* @param source The key to the source value.
* @param destination The key where the value should be copied to.
* @return Command Response - <code>true</code> if <code>source</code> was copied, <code>false
* </code> if <code>source</code> was not copied.
*/
public T copy(@NonNull String source, @NonNull String destination) {
return copy(source, destination, false);
}

/**
* Counts the number of set bits (population counting) in a string stored at <code>key</code>.
*
Expand Down
47 changes: 47 additions & 0 deletions java/client/src/main/java/glide/api/models/Transaction.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
/** Copyright GLIDE-for-Redis Project Contributors - SPDX Identifier: Apache-2.0 */
package glide.api.models;

import static glide.api.commands.GenericBaseCommands.REPLACE_REDIS_API;
import static glide.api.commands.GenericCommands.DB_REDIS_API;
import static redis_request.RedisRequestOuterClass.RequestType.Copy;
import static redis_request.RedisRequestOuterClass.RequestType.Move;
import static redis_request.RedisRequestOuterClass.RequestType.Select;

import lombok.AllArgsConstructor;
import lombok.NonNull;
import org.apache.commons.lang3.ArrayUtils;
import redis_request.RedisRequestOuterClass.Command.ArgsArray;

/**
Expand Down Expand Up @@ -64,4 +69,46 @@ public Transaction move(String key, long dbIndex) {
protobufTransaction.addCommands(buildCommand(Move, commandArgs));
return this;
}

/**
* Copies the value stored at the <code>source</code> to the <code>destination</code> key on
* <code>destinationDB</code>. When <code>replace</code> is true, removes the <code>destination
* </code> key first if it already exists, otherwise performs no action.
*
* @since Redis 6.2.0 and above.
* @see <a href="https://redis.io/commands/copy/">redis.io</a> for details.
* @param source The key to the source value.
* @param destination The key where the value should be copied to.
* @param destinationDB The alternative logical database index for the destination key.
* @return Command Response - <code>true</code> if <code>source</code> was copied, <code>false
* </code> if <code>source</code> was not copied.
*/
public Transaction copy(@NonNull String source, @NonNull String destination, long destinationDB) {
return copy(source, destination, destinationDB, false);
}

/**
* Copies the value stored at the <code>source</code> to the <code>destination</code> key on
* <code>destinationDB</code>. When <code>replace</code> is true, removes the <code>destination
* </code> key first if it already exists, otherwise performs no action.
*
* @since Redis 6.2.0 and above.
* @see <a href="https://redis.io/commands/copy/">redis.io</a> for details.
* @param source The key to the source value.
* @param destination The key where the value should be copied to.
* @param destinationDB The alternative logical database index for the destination key.
* @param replace If the destination key should be removed before copying the value to it.
* @return Command Response - <code>true</code> if <code>source</code> was copied, <code>false
* </code> if <code>source</code> was not copied.
*/
public Transaction copy(
@NonNull String source, @NonNull String destination, long destinationDB, boolean replace) {
String[] args = new String[] {source, destination, DB_REDIS_API, Long.toString(destinationDB)};
if (replace) {
args = ArrayUtils.add(args, REPLACE_REDIS_API);
}
ArgsArray commandArgs = buildArgs(args);
protobufTransaction.addCommands(buildCommand(Copy, commandArgs));
return this;
}
}
Loading

0 comments on commit 1eaef18

Please sign in to comment.