Skip to content

Commit

Permalink
Support COPY command #1508
Browse files Browse the repository at this point in the history
Original pull request: #1565.
  • Loading branch information
KowalczykBartek authored and mp911de committed Jan 8, 2021
1 parent 3637ace commit 3497253
Show file tree
Hide file tree
Showing 11 changed files with 272 additions and 3 deletions.
10 changes: 10 additions & 0 deletions src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java
Original file line number Diff line number Diff line change
Expand Up @@ -1571,6 +1571,16 @@ public RedisFuture<Long> unlink(Iterable<K> keys) {
return dispatch(commandBuilder.unlink(keys));
}

@Override
public RedisFuture<Boolean> copy(K source, K destination) {
return dispatch(commandBuilder.copy(source, destination));
}

@Override
public RedisFuture<Boolean> copy(K source, K destination, CopyArgs copyArgs) {
return dispatch(commandBuilder.copy(source, destination, copyArgs));
}

@Override
public RedisFuture<String> unwatch() {
return dispatch(commandBuilder.unwatch());
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java
Original file line number Diff line number Diff line change
Expand Up @@ -1647,6 +1647,16 @@ public Mono<Long> unlink(Iterable<K> keys) {
return createMono(() -> commandBuilder.unlink(keys));
}

@Override
public Mono<Boolean> copy(K source, K destination) {
return createMono(() -> commandBuilder.copy(source, destination));
}

@Override
public Mono<Boolean> copy(K source, K destination, CopyArgs copyArgs) {
return createMono(() -> commandBuilder.copy(source, destination, copyArgs));
}

@Override
public Mono<String> unwatch() {
return createMono(commandBuilder::unwatch);
Expand Down
101 changes: 101 additions & 0 deletions src/main/java/io/lettuce/core/CopyArgs.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* Copyright 2018-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.lettuce.core;

import io.lettuce.core.protocol.CommandArgs;
import io.lettuce.core.protocol.CommandKeyword;

/**
* Argument list builder for the Redis <a href="http://redis.io/commands/copy">COPY</a> command. Static import the methods from
* {@link CopyArgs.Builder} and call the methods: {@code destinationDb(…)} {@code replace(…)}.
*
* {@link CopyArgs} is a mutable object and instances should be used only once to avoid shared mutable state.
*
* @since 6.2
*/
public class CopyArgs {

private Long destinationDb;

private Boolean replace;

/**
* Builder entry points for {@link CopyArgs}.
*/
public static class Builder {

/**
* Utility constructor.
*/
private Builder() {
}

/**
* Creates new {@link CopyArgs} and sets {@literal DB}.
*
* @return new {@link CopyArgs} with {@literal DB} set.
*/
public static CopyArgs destinationDb(long destinationDb) {
return new CopyArgs().destinationDb(destinationDb);
}

/**
* Creates new {@link CopyArgs} and sets {@literal REPLACE}.
*
* @return new {@link CopyArgs} with {@literal REPLACE} set.
*/
public static CopyArgs replace(boolean replace) {
return new CopyArgs().replace(replace);
}

}

/**
* Specify an alternative logical database index for the destination key.
*
* @param destinationDb logical database index to apply for {@literal DB}.
* @return {@code this}.
*/
public CopyArgs destinationDb(long destinationDb) {

this.destinationDb = destinationDb;
return this;
}

/**
* Hint redis to remove the destination key before copying the value to it.
*
* @param replace remove destination key before copying the value {@literal REPLACE}.
* @return {@code this}.
*/
public CopyArgs replace(boolean replace) {

this.replace = replace;
return this;
}

public <K, V> void build(CommandArgs<K, V> args) {

if (destinationDb != null) {
args.add(CommandKeyword.DB).add(destinationDb);
}

if(replace != null) {
args.add(CommandKeyword.REPLACE);
}
}

}
18 changes: 18 additions & 0 deletions src/main/java/io/lettuce/core/RedisCommandBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import static io.lettuce.core.internal.LettuceStrings.*;
import static io.lettuce.core.protocol.CommandKeyword.*;
import static io.lettuce.core.protocol.CommandType.*;
import static io.lettuce.core.protocol.CommandType.COPY;

import java.nio.ByteBuffer;
import java.util.Arrays;
Expand Down Expand Up @@ -2192,6 +2193,23 @@ Command<K, V, Long> unlink(Iterable<K> keys) {
return createCommand(UNLINK, new IntegerOutput<>(codec), args);
}

Command<K, V, Boolean> copy(K source, K destination) {
LettuceAssert.notNull(source, "Source " + MUST_NOT_BE_NULL);
LettuceAssert.notNull(destination, "Destination " + MUST_NOT_BE_NULL);

CommandArgs<K, V> args = new CommandArgs<>(codec).addKey(source).addKey(destination);
return createCommand(COPY, new BooleanOutput<>(codec), args);
}

Command<K, V, Boolean> copy(K source, K destination, CopyArgs copyArgs) {
LettuceAssert.notNull(source, "Source " + MUST_NOT_BE_NULL);
LettuceAssert.notNull(destination, "Destination " + MUST_NOT_BE_NULL);

CommandArgs<K, V> args = new CommandArgs<>(codec).addKey(source).addKey(destination);
copyArgs.build(args);
return createCommand(COPY, new BooleanOutput<>(codec), args);
}

Command<K, V, String> unwatch() {
return createCommand(UNWATCH, new StatusOutput<>(codec));
}
Expand Down
27 changes: 27 additions & 0 deletions src/main/java/io/lettuce/core/api/async/RedisKeyAsyncCommands.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,33 @@ public interface RedisKeyAsyncCommands<K, V> {
*/
RedisFuture<Long> unlink(K... keys);

/**
* Copy the value stored at the source key to the destination key.
*
* @param source the source.
* @param destination the destination.
* @return Boolean integer-reply specifically:
*
* {@code 1} if source was copied. {@code 0} if source was not copied.
*
* @since 6.2
*/
RedisFuture<Boolean> copy(K source, K destination);

/**
* Copy the value stored at the source key to the destination key.
*
* @param source the source.
* @param destination the destination.
* @param copyArgs the copyArgs.
* @return Boolean integer-reply specifically:
*
* {@code 1} if source was copied. {@code 0} if source was not copied.
*
* @since 6.2
*/
RedisFuture<Boolean> copy(K source, K destination, CopyArgs copyArgs);

/**
* Return a serialized version of the value stored at the specified key.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,33 @@ public interface RedisKeyReactiveCommands<K, V> {
*/
Mono<Long> unlink(K... keys);

/**
* Copy the value stored at the source key to the destination key.
*
* @param source the source.
* @param destination the destination.
* @return Boolean integer-reply specifically:
*
* {@code 1} if source was copied. {@code 0} if source was not copied.
*
* @since 6.2
*/
Mono<Boolean> copy(K source, K destination);

/**
* Copy the value stored at the source key to the destination key.
*
* @param source the source.
* @param destination the destination.
* @param copyArgs the copyArgs.
* @return Boolean integer-reply specifically:
*
* {@code 1} if source was copied. {@code 0} if source was not copied.
*
* @since 6.2
*/
Mono<Boolean> copy(K source, K destination, CopyArgs copyArgs);

/**
* Return a serialized version of the value stored at the specified key.
*
Expand Down
27 changes: 27 additions & 0 deletions src/main/java/io/lettuce/core/api/sync/RedisKeyCommands.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,33 @@ public interface RedisKeyCommands<K, V> {
*/
Long unlink(K... keys);

/**
* Copy the value stored at the source key to the destination key.
*
* @param source the source.
* @param destination the destination.
* @return Boolean integer-reply specifically:
*
* {@code 1} if source was copied. {@code 0} if source was not copied.
*
* @since 6.2
*/
Boolean copy(K source, K destination);

/**
* Copy the value stored at the source key to the destination key.
*
* @param source the source.
* @param destination the destination.
* @param copyArgs the copyArgs.
* @return Boolean integer-reply specifically:
*
* {@code 1} if source was copied. {@code 0} if source was not copied.
*
* @since 6.2
*/
Boolean copy(K source, K destination, CopyArgs copyArgs);

/**
* Return a serialized version of the value stored at the specified key.
*
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/io/lettuce/core/protocol/CommandKeyword.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public enum CommandKeyword implements ProtocolKeyword {

ADDR, ADDSLOTS, AFTER, AGGREGATE, ALPHA, AND, ASK, ASC, ASYNC, BEFORE, BLOCK, BUMPEPOCH,

BY, CACHING, CHANNELS, COPY, COUNT, COUNTKEYSINSLOT, CONSUMERS, CREATE, DELSLOTS, DESC, SOFT, HARD, ENCODING,
BY, CACHING, CHANNELS, COPY, COUNT, COUNTKEYSINSLOT, CONSUMERS, CREATE, DB, DELSLOTS, DESC, SOFT, HARD, ENCODING,

FAILOVER, FORGET, FLUSH, FORCE, FLUSHSLOTS, GETNAME, GETKEYSINSLOT, GETREDIR, GROUP, GROUPS, HTSTATS, ID, IDLE,

Expand Down
2 changes: 1 addition & 1 deletion src/main/java/io/lettuce/core/protocol/CommandType.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public enum CommandType implements ProtocolKeyword {

// Keys

DEL, DUMP, EXISTS, EXPIRE, EXPIREAT, KEYS, MIGRATE, MOVE, OBJECT, PERSIST, PEXPIRE, PEXPIREAT, PTTL, RANDOMKEY, RENAME, RENAMENX, RESTORE, TOUCH, TTL, TYPE, SCAN, UNLINK,
COPY, DEL, DUMP, EXISTS, EXPIRE, EXPIREAT, KEYS, MIGRATE, MOVE, OBJECT, PERSIST, PEXPIRE, PEXPIREAT, PTTL, RANDOMKEY, RENAME, RENAMENX, RESTORE, TOUCH, TTL, TYPE, SCAN, UNLINK,

// String

Expand Down
27 changes: 27 additions & 0 deletions src/main/templates/io/lettuce/core/api/RedisKeyCommands.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,33 @@ public interface RedisKeyCommands<K, V> {
*/
Long unlink(K... keys);

/**
* Copy the value stored at the source key to the destination key.
*
* @param source the source.
* @param destination the destination.
* @return Boolean integer-reply specifically:
*
* {@code 1} if source was copied. {@code 0} if source was not copied.
*
* @since 6.2
*/
Boolean copy(K source, K destination);

/**
* Copy the value stored at the source key to the destination key.
*
* @param source the source.
* @param destination the destination.
* @param copyArgs the copyArgs.
* @return Boolean integer-reply specifically:
*
* {@code 1} if source was copied. {@code 0} if source was not copied.
*
* @since 6.2
*/
Boolean copy(K source, K destination, CopyArgs copyArgs);

/**
* Return a serialized version of the value stored at the specified key.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,36 @@ void del() {
@Test
@EnabledOnCommand("UNLINK")
void unlink() {

redis.set(key, value);
assertThat((long) redis.unlink(key)).isEqualTo(1);
redis.set(key + "1", value);
redis.set(key + "2", value);
assertThat(redis.unlink(key + "1", key + "2")).isEqualTo(2);
}

@Test
void copy() {
redis.set(key, value);
redis.copy(key, key + "2");
assertThat(redis.get(key + "2")).isEqualTo(value);
}

@Test
void copyWithReplace() {
redis.set(key, value);
redis.set(key + 2, "value to be overridden");
redis.copy(key, key + "2", CopyArgs.Builder.replace(true));
assertThat(redis.get(key + "2")).isEqualTo(value);
}

@Test
void copyWithDestinationDb() {
redis.set(key, value);
redis.copy(key, key, CopyArgs.Builder.destinationDb(2));
redis.select(2);
assertThat(redis.get(key)).isEqualTo(value);
}

@Test
void dump() {
assertThat(redis.dump("invalid")).isNull();
Expand Down

0 comments on commit 3497253

Please sign in to comment.