Skip to content

Add support for COPY via RedisOperations #2059

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

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
* @author Tugdual Grall
* @author Andrey Shlykov
* @author dengliming
* @author ihaohong
*/
public class DefaultStringRedisConnection implements StringRedisConnection, DecoratedRedisConnection {

Expand Down Expand Up @@ -276,6 +277,15 @@ public Long del(byte[]... keys) {
return convertAndReturn(delegate.del(keys), Converters.identityConverter());
}

/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisKeyCommands#copy(byte[], byte[])
*/
@Override
public Boolean copy(byte[] sourceKey, byte[] targetKey) {
return convertAndReturn(delegate.copy(sourceKey, targetKey), Converters.identityConverter());
}

/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisKeyCommands#unlink(byte[][])
Expand Down Expand Up @@ -1899,6 +1909,15 @@ public Long del(String... keys) {
return del(serializeMulti(keys));
}

/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.StringRedisConnection#copy(java.lang.String[])
*/
@Override
public Boolean copy(String sourceKey, String targetKey) {
return copy(serialize(sourceKey), serialize(targetKey));
}

/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.StringRedisConnection#unlink(java.lang.String[])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
* @author Mark Paluch
* @author Tugdual Grall
* @author Andrey Shlykov
* @author ihaohong
* @since 2.0
*/
public interface DefaultedRedisConnection extends RedisConnection {
Expand Down Expand Up @@ -83,6 +84,13 @@ default Long del(byte[]... keys) {
return keyCommands().del(keys);
}

/** @deprecated in favor of {@link RedisConnection#keyCommands()}. */
@Override
@Deprecated
default Boolean copy(byte[] sourceKey, byte[] targetKey) {
return keyCommands().copy(sourceKey, targetKey);
}

/** @deprecated in favor of {@link RedisConnection#keyCommands()}. */
@Override
@Deprecated
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
* @author Costin Leau
* @author Christoph Strobl
* @author Mark Paluch
* @author ihaohong
*/
public interface RedisKeyCommands {

Expand Down Expand Up @@ -71,6 +72,17 @@ default Boolean exists(byte[] key) {
@Nullable
Long del(byte[]... keys);

/**
* Copy given {@code sourceKey} to {@code targetKey}.
*
* @param sourceKey must not be {@literal null}.
* @param targetKey must not be {@literal null}.
* @return
* @see <a href="https://redis.io/commands/copy">Redis Documentation: COPY</a>
*/
@Nullable
Boolean copy(byte[] sourceKey, byte[] targetKey);

/**
* Unlink the {@code keys} from the keyspace. Unlike with {@link #del(byte[]...)} the actual memory reclaiming here
* happens asynchronously.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@
* @author Tugdual Grall
* @author Dengliming
* @author Andrey Shlykov
* @author ihaohong
*
* @see RedisCallback
* @see RedisSerializer
* @see StringRedisTemplate
Expand Down Expand Up @@ -132,6 +134,17 @@ interface StringTuple extends Tuple {
*/
Long del(String... keys);

/**
* Copy given {@code sourceKey} to {@code targetKey}.
*
* @param sourceKey must not be {@literal null}.
* @param targetKey must not be {@literal null}.
* @return
* @see <a href="https://redis.io/commands/copy">Redis Documentation: COPY</a>
* @see RedisKeyCommands#copy(byte[], byte[])
*/
Boolean copy(String sourceKey, String targetKey);

/**
* Unlink the {@code keys} from the keyspace. Unlike with {@link #del(String...)} the actual memory reclaiming here
* happens asynchronously.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
/**
* @author Christoph Strobl
* @author Mark Paluch
* @author ihaohong
* @since 2.0
*/
class JedisClusterKeyCommands implements RedisKeyCommands {
Expand Down Expand Up @@ -87,6 +88,18 @@ public Long del(byte[]... keys) {
.resultsAsList().size();
}

/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisKeyCommands#copy(byte[], byte[])
*/
@Override
public Boolean copy(byte[] sourceKey, byte[] targetKey) {
Assert.notNull(sourceKey, "source key must not be null!");
Assert.notNull(targetKey, "target key must not be null!");

return connection.getCluster().copy(sourceKey, targetKey, false);
}

/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisKeyCommands#unlink(byte[][])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
/**
* @author Christoph Strobl
* @author Mark Paluch
* @author ihaohong
* @since 2.0
*/
class JedisKeyCommands implements RedisKeyCommands {
Expand Down Expand Up @@ -90,6 +91,17 @@ public Long del(byte[]... keys) {
return connection.invoke().just(BinaryJedis::del, MultiKeyPipelineBase::del, keys);
}

/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisKeyCommands#copy(byte[], byte[])
*/
public Boolean copy(byte[] sourceKey, byte[] targetKey) {
Assert.notNull(sourceKey, "source key must not be null!");
Assert.notNull(targetKey, "target key must not be null!");

return connection.invoke().just(BinaryJedis::copy, MultiKeyPipelineBase::copy, sourceKey, targetKey, false);
}

/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisKeyCommands#unlink(byte[][])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
* @author Mark Paluch
* @author Ninad Divadkar
* @author Tamil Selvan
* @author ihaohong
*/
public class LettuceConnection extends AbstractRedisConnection {

Expand Down Expand Up @@ -1161,6 +1162,7 @@ static class TypeHints {
COMMAND_OUTPUT_TYPE_MAPPING.put(DECR, IntegerOutput.class);
COMMAND_OUTPUT_TYPE_MAPPING.put(DECRBY, IntegerOutput.class);
COMMAND_OUTPUT_TYPE_MAPPING.put(DEL, IntegerOutput.class);
COMMAND_OUTPUT_TYPE_MAPPING.put(COPY, IntegerOutput.class);
COMMAND_OUTPUT_TYPE_MAPPING.put(GETBIT, IntegerOutput.class);
COMMAND_OUTPUT_TYPE_MAPPING.put(HDEL, IntegerOutput.class);
COMMAND_OUTPUT_TYPE_MAPPING.put(HINCRBY, IntegerOutput.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
/**
* @author Christoph Strobl
* @author Mark Paluch
* @author ihaohong
* @since 2.0
*/
class LettuceKeyCommands implements RedisKeyCommands {
Expand Down Expand Up @@ -90,6 +91,18 @@ public Long del(byte[]... keys) {
return connection.invoke().just(RedisKeyAsyncCommands::del, keys);
}

/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisKeyCommands#copy(byte[], byte[])
*/
@Override
public Boolean copy(byte[] sourceKey, byte[] targetKey) {
Assert.notNull(sourceKey, "source key must not be null!");
Assert.notNull(targetKey, "target key must not be null!");

return connection.invoke().just(RedisKeyAsyncCommands::copy, targetKey, sourceKey);
}

/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisKeyCommands#unlink(byte[][])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
* @author Christoph Strobl
* @author Ninad Divadkar
* @author Mark Paluch
* @author ihaohong
*/
public interface RedisOperations<K, V> {

Expand Down Expand Up @@ -199,6 +200,17 @@ <T> T execute(RedisScript<T> script, RedisSerializer<?> argsSerializer, RedisSer
@Nullable
Long delete(Collection<K> keys);

/**
* Copy given {@code sourceKey} to {@code targetKey}.
*
* @param sourceKey must not be {@literal null}.
* @param targetKey must not be {@literal null}.
* @return
* @see <a href="https://redis.io/commands/copy">Redis Documentation: COPY</a>
*/
@Nullable
Boolean copy(K sourceKey, K targetKey);

/**
* Unlink the {@code key} from the keyspace. Unlike with {@link #delete(Object)} the actual memory reclaiming here
* happens asynchronously.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@
* @author Anqing Shao
* @author Mark Paluch
* @author Denis Zavedeev
* @author ihaohong
*
* @param <K> the Redis key type against which the template works (usually a String)
* @param <V> the Redis value type against which the template works
* @see StringRedisTemplate
Expand Down Expand Up @@ -710,6 +712,14 @@ public Boolean delete(K key) {
return result != null && result.intValue() == 1;
}

@Override
public Boolean copy(K source, K target) {
byte[] sourceKey = rawKey(source);
byte[] targetKey = rawKey(target);

return execute(connection -> connection.copy(sourceKey, targetKey), true);
}

/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.RedisOperations#delete(java.util.Collection)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,12 @@ public void testDel() {
super.testDel();
}

@Test
public void testCopy() {
doReturn(Collections.singletonList(Boolean.TRUE)).when(nativeConnection).closePipeline();
super.testCopy();
}

@Test
public void testEchoBytes() {
doReturn(Arrays.asList(new Object[] { barBytes })).when(nativeConnection).closePipeline();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,13 @@ public void testDel() {
super.testDel();
}

@Test
public void testCopy() {
doReturn(Collections.singletonList(Collections.singletonList(Boolean.TRUE))).when(nativeConnection).closePipeline();
super.testCopy();
}


@Test
public void testEchoBytes() {
doReturn(Collections.singletonList(Arrays.asList(new Object[] { barBytes }))).when(nativeConnection)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
* @author Christoph Strobl
* @author Ninad Divadkar
* @author Mark Paluch
* @author ihaohong
*/
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
Expand Down Expand Up @@ -234,6 +235,13 @@ public void testDel() {
verifyResults(Collections.singletonList(1L));
}

@Test
public void testCopy() {
doReturn(Boolean.TRUE).when(nativeConnection).copy(fooBytes, barBytes);
actual.add(connection.copy(foo, bar));
verifyResults(Collections.singletonList(Boolean.TRUE));
}

@Test
public void testEchoBytes() {
doReturn(barBytes).when(nativeConnection).echo(fooBytes);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,10 @@ public Long del(byte[]... keys) {
return delegate.del(keys);
}

public Boolean copy(byte[] sourceKey, byte[] targetKey) {
return delegate.copy(sourceKey, targetKey);
}

public void close() throws DataAccessException {
super.close();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
* @author Anqing Shao
* @author Duobiao Ou
* @author Mark Paluch
* @author ihaohong
*/
@MethodSource("testParams")
public class RedisTemplateIntegrationTests<K, V> {
Expand Down Expand Up @@ -390,6 +391,20 @@ void testDelete() {
assertThat(redisTemplate.hasKey(key1)).isFalse();
}

@ParameterizedRedisTest
void testCopy() {
K key1 = keyFactory.instance();
K key2 = keyFactory.instance();
V value1 = valueFactory.instance();

redisTemplate.opsForValue().set(key1, value1);

assertThat(redisTemplate.hasKey(key2)).isFalse();
redisTemplate.copy(key1, key2);
assertThat(redisTemplate.hasKey(key2)).isTrue();
assertThat(redisTemplate.opsForValue().get(key2)).isEqualTo(value1);
}

@ParameterizedRedisTest // DATAREDIS-688
void testDeleteMultiple() {

Expand Down