diff --git a/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java b/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java index ae78072a2..97f25e336 100644 --- a/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java @@ -305,8 +305,8 @@ public class DefaultStringRedisConnection implements StringRedisConnection { return delegate.getSubscription(); } - public Boolean hDel(byte[] key, byte[] field) { - Boolean result = delegate.hDel(key, field); + public Long hDel(byte[] key, byte[]... fields) { + Long result = delegate.hDel(key, fields); if(isFutureConversion()) { addResultConverter(identityConverter); } @@ -1345,8 +1345,8 @@ public class DefaultStringRedisConnection implements StringRedisConnection { } - public Boolean hDel(String key, String field) { - Boolean result = delegate.hDel(serialize(key), serialize(field)); + public Long hDel(String key, String... fields) { + Long result = delegate.hDel(serialize(key), serializeMulti(fields)); if(isFutureConversion()) { addResultConverter(identityConverter); } diff --git a/src/main/java/org/springframework/data/redis/connection/RedisHashCommands.java b/src/main/java/org/springframework/data/redis/connection/RedisHashCommands.java index 2fd75449f..c3457c017 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisHashCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisHashCommands.java @@ -43,7 +43,7 @@ public interface RedisHashCommands { Boolean hExists(byte[] key, byte[] field); - Boolean hDel(byte[] key, byte[] field); + Long hDel(byte[] key, byte[]... fields); Long hLen(byte[] key); diff --git a/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java b/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java index 8870bc5b5..347c343b0 100644 --- a/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java @@ -257,7 +257,7 @@ public interface StringRedisConnection extends RedisConnection { Boolean hExists(String key, String field); - Boolean hDel(String key, String field); + Long hDel(String key, String... fields); Long hLen(String key); diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java index 18578a337..8e293bf71 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java @@ -2364,17 +2364,21 @@ public class JedisConnection implements RedisConnection { } - public Boolean hDel(byte[] key, byte[] field) { + public Long hDel(byte[] key, byte[]... fields) { + if((isPipelined() || isQueueing()) && fields.length > 1) { + throw new UnsupportedOperationException("hDel of multiple fields not supported " + + "in pipeline or transaction"); + } try { if (isPipelined()) { - pipeline(new JedisResult(pipeline.hdel(key, field), JedisConverters.longToBoolean())); + pipeline(new JedisResult(pipeline.hdel(key, fields[0]))); return null; } if (isQueueing()) { - transaction(new JedisResult(transaction.hdel(key, field), JedisConverters.longToBoolean())); + transaction(new JedisResult(transaction.hdel(key, fields[0]))); return null; } - return JedisConverters.toBoolean(jedis.hdel(key, field)); + return jedis.hdel(key, fields); } catch (Exception ex) { throw convertJedisAccessException(ex); } diff --git a/src/main/java/org/springframework/data/redis/connection/jredis/JredisConnection.java b/src/main/java/org/springframework/data/redis/connection/jredis/JredisConnection.java index 9c77db5c0..f158b4ceb 100644 --- a/src/main/java/org/springframework/data/redis/connection/jredis/JredisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/jredis/JredisConnection.java @@ -1116,9 +1116,12 @@ public class JredisConnection implements RedisConnection { } - public Boolean hDel(byte[] key, byte[] field) { + public Long hDel(byte[] key, byte[]... fields) { + if(fields.length > 1) { + throw new UnsupportedOperationException("hDel of multiple fields not supported"); + } try { - return jredis.hdel(key, field); + return JredisUtils.toLong(jredis.hdel(key, fields[0])); } catch (Exception ex) { throw convertJredisAccessException(ex); } diff --git a/src/main/java/org/springframework/data/redis/connection/jredis/JredisUtils.java b/src/main/java/org/springframework/data/redis/connection/jredis/JredisUtils.java index f6cbef95e..5424fbb72 100644 --- a/src/main/java/org/springframework/data/redis/connection/jredis/JredisUtils.java +++ b/src/main/java/org/springframework/data/redis/connection/jredis/JredisUtils.java @@ -123,4 +123,8 @@ public abstract class JredisUtils { info.putAll(map); return info; } + + static Long toLong(Boolean source) { + return source ? 1l : 0l; + } } \ No newline at end of file diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java index c533a39ab..440d0f5a6 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java @@ -2460,17 +2460,17 @@ public class LettuceConnection implements RedisConnection { } - public Boolean hDel(byte[] key, byte[] field) { + public Long hDel(byte[] key, byte[]... fields) { try { if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().hdel(key, field), LettuceConverters.longToBoolean())); + pipeline(new LettuceResult(getAsyncConnection().hdel(key, fields))); return null; } if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().hdel(key, field), LettuceConverters.longToBoolean())); + transaction(new LettuceTxResult(getConnection().hdel(key, fields))); return null; } - return LettuceConverters.toBoolean(getConnection().hdel(key, field)); + return getConnection().hdel(key, fields); } catch (Exception ex) { throw convertLettuceAccessException(ex); } diff --git a/src/main/java/org/springframework/data/redis/connection/srp/SrpConnection.java b/src/main/java/org/springframework/data/redis/connection/srp/SrpConnection.java index 158f0cb06..c98ed8201 100644 --- a/src/main/java/org/springframework/data/redis/connection/srp/SrpConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/srp/SrpConnection.java @@ -1887,13 +1887,13 @@ public class SrpConnection implements RedisConnection { } - public Boolean hDel(byte[] key, byte[] field) { + public Long hDel(byte[] key, byte[]... fields) { try { if (isPipelined()) { - pipeline(new SrpResult(pipeline.hdel(key, new Object[] { field }), SrpConverters.longToBoolean())); + pipeline(new SrpResult(pipeline.hdel(key, (Object[])fields))); return null; } - return SrpConverters.toBoolean(client.hdel(key, new Object[] { field }).data()); + return client.hdel(key, (Object[])fields).data(); } catch (Exception ex) { throw convertSrpAccessException(ex); } diff --git a/src/main/java/org/springframework/data/redis/core/AbstractOperations.java b/src/main/java/org/springframework/data/redis/core/AbstractOperations.java index 83da06de4..60b5e36a1 100644 --- a/src/main/java/org/springframework/data/redis/core/AbstractOperations.java +++ b/src/main/java/org/springframework/data/redis/core/AbstractOperations.java @@ -33,6 +33,7 @@ import org.springframework.util.Assert; * Internal base class used by various RedisTemplate XXXOperations implementations. * * @author Costin Leau + * @author Jennifer Hickey */ abstract class AbstractOperations { @@ -97,6 +98,7 @@ abstract class AbstractOperations { return keySerializer().serialize(key); } + @SuppressWarnings("unchecked") byte[] rawString(String key) { return stringSerializer().serialize(key); } @@ -118,6 +120,15 @@ abstract class AbstractOperations { return hashKeySerializer().serialize(hashKey); } + byte[][] rawHashKeys(HK... hashKeys) { + final byte[][] rawHashKeys = new byte[hashKeys.length][]; + int i = 0; + for (HK hashKey : hashKeys) { + rawHashKeys[i++] = rawHashKey(hashKey); + } + return rawHashKeys; + } + @SuppressWarnings("unchecked") byte[] rawHashValue(HV value) { if(hashValueSerializer() == null & value instanceof byte[]) { @@ -163,7 +174,7 @@ abstract class AbstractOperations { return SerializationUtils.deserialize(rawValues, valueSerializer()); } - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) Set> deserializeTupleValues(Set rawValues) { if(rawValues == null) { return null; diff --git a/src/main/java/org/springframework/data/redis/core/BoundHashOperations.java b/src/main/java/org/springframework/data/redis/core/BoundHashOperations.java index 43500a5e4..54e0a3648 100644 --- a/src/main/java/org/springframework/data/redis/core/BoundHashOperations.java +++ b/src/main/java/org/springframework/data/redis/core/BoundHashOperations.java @@ -51,7 +51,7 @@ public interface BoundHashOperations extends BoundKeyOperations { Long size(); - void delete(Object key); + void delete(Object... keys); Map entries(); } diff --git a/src/main/java/org/springframework/data/redis/core/DefaultBoundHashOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultBoundHashOperations.java index 69237311f..8c7793770 100644 --- a/src/main/java/org/springframework/data/redis/core/DefaultBoundHashOperations.java +++ b/src/main/java/org/springframework/data/redis/core/DefaultBoundHashOperations.java @@ -43,8 +43,8 @@ class DefaultBoundHashOperations extends DefaultBoundKeyOperations } - public void delete(Object key) { - ops.delete(getKey(), key); + public void delete(Object... keys) { + ops.delete(getKey(), keys); } diff --git a/src/main/java/org/springframework/data/redis/core/DefaultHashOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultHashOperations.java index 5c36776bb..46a85c4b9 100644 --- a/src/main/java/org/springframework/data/redis/core/DefaultHashOperations.java +++ b/src/main/java/org/springframework/data/redis/core/DefaultHashOperations.java @@ -209,14 +209,14 @@ class DefaultHashOperations extends AbstractOperations imp } - public void delete(K key, Object hashKey) { + public void delete(K key, Object... hashKeys) { final byte[] rawKey = rawKey(key); - final byte[] rawHashKey = rawHashKey(hashKey); + final byte[][] rawHashKeys = rawHashKeys(hashKeys); execute(new RedisCallback() { public Object doInRedis(RedisConnection connection) { - connection.hDel(rawKey, rawHashKey); + connection.hDel(rawKey, rawHashKeys); return null; } }, true); diff --git a/src/main/java/org/springframework/data/redis/core/HashOperations.java b/src/main/java/org/springframework/data/redis/core/HashOperations.java index 790c30f82..ad3bc9506 100644 --- a/src/main/java/org/springframework/data/redis/core/HashOperations.java +++ b/src/main/java/org/springframework/data/redis/core/HashOperations.java @@ -27,7 +27,7 @@ import java.util.Set; */ public interface HashOperations { - void delete(H key, Object hashKey); + void delete(H key, Object... hashKeys); Boolean hasKey(H key, Object hashKey); diff --git a/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java index ec712497e..fdd124d7c 100644 --- a/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java @@ -1762,7 +1762,17 @@ public abstract class AbstractConnectionIntegrationTests { actual.add(connection.hDel("test", "key")); actual.add(connection.hDel("test", "foo")); actual.add(connection.hExists("test", "key")); - verifyResults(Arrays.asList(new Object[] { true, true, false, false })); + verifyResults(Arrays.asList(new Object[] { true, 1l, 0l, false })); + } + + @Test + public void testHDelMultiple() { + actual.add(connection.hSet("test", "key", "val")); + actual.add(connection.hSet("test", "foo", "bar")); + actual.add(connection.hDel("test", "key", "foo")); + actual.add(connection.hExists("test", "key")); + actual.add(connection.hExists("test", "foo")); + verifyResults(Arrays.asList(new Object[] { true, true, 2l, false, false })); } @Test diff --git a/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionPipelineTests.java b/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionPipelineTests.java index 05a84c669..230fabdfc 100644 --- a/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionPipelineTests.java +++ b/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionPipelineTests.java @@ -254,13 +254,13 @@ public class DefaultStringRedisConnectionPipelineTests extends DefaultStringRedi @Test public void testHDelBytes() { - doReturn(Arrays.asList(new Object[] { true })).when(nativeConnection).closePipeline(); + doReturn(Arrays.asList(new Object[] { 1l })).when(nativeConnection).closePipeline(); super.testHDelBytes(); } @Test public void testHDel() { - doReturn(Arrays.asList(new Object[] { true })).when(nativeConnection).closePipeline(); + doReturn(Arrays.asList(new Object[] { 1l })).when(nativeConnection).closePipeline(); super.testHDel(); } diff --git a/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionPipelineTxTests.java b/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionPipelineTxTests.java index f07b8f4af..b3f927bb9 100644 --- a/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionPipelineTxTests.java +++ b/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionPipelineTxTests.java @@ -222,13 +222,13 @@ public class DefaultStringRedisConnectionPipelineTxTests extends @Test public void testHDelBytes() { - doReturn(Arrays.asList(new Object[] {Arrays.asList(new Object[] { true })})).when(nativeConnection).closePipeline(); + doReturn(Arrays.asList(new Object[] {Arrays.asList(new Object[] { 1l })})).when(nativeConnection).closePipeline(); super.testHDelBytes(); } @Test public void testHDel() { - doReturn(Arrays.asList(new Object[] {Arrays.asList(new Object[] { true })})).when(nativeConnection).closePipeline(); + doReturn(Arrays.asList(new Object[] {Arrays.asList(new Object[] { 1l })})).when(nativeConnection).closePipeline(); super.testHDel(); } diff --git a/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionTests.java b/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionTests.java index d131a37da..15759d738 100644 --- a/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionTests.java +++ b/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionTests.java @@ -326,16 +326,16 @@ public class DefaultStringRedisConnectionTests { @Test public void testHDelBytes() { - doReturn(true).when(nativeConnection).hDel(fooBytes, barBytes); + doReturn(1l).when(nativeConnection).hDel(fooBytes, barBytes); actual.add(connection.hDel(fooBytes, barBytes)); - verifyResults(Arrays.asList(new Object[] { true })); + verifyResults(Arrays.asList(new Object[] { 1l })); } @Test public void testHDel() { - doReturn(true).when(nativeConnection).hDel(fooBytes, barBytes); + doReturn(1l).when(nativeConnection).hDel(fooBytes, barBytes); actual.add(connection.hDel(foo, bar)); - verifyResults(Arrays.asList(new Object[] { true })); + verifyResults(Arrays.asList(new Object[] { 1l })); } @Test diff --git a/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionTxTests.java b/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionTxTests.java index a04ddb9ec..6c8d4fc9f 100644 --- a/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionTxTests.java +++ b/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionTxTests.java @@ -221,13 +221,13 @@ public class DefaultStringRedisConnectionTxTests extends DefaultStringRedisConne @Test public void testHDelBytes() { - doReturn(Arrays.asList(new Object[] { true })).when(nativeConnection).exec(); + doReturn(Arrays.asList(new Object[] { 1l })).when(nativeConnection).exec(); super.testHDelBytes(); } @Test public void testHDel() { - doReturn(Arrays.asList(new Object[] { true })).when(nativeConnection).exec(); + doReturn(Arrays.asList(new Object[] { 1l })).when(nativeConnection).exec(); super.testHDel(); } diff --git a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionPipelineIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionPipelineIntegrationTests.java index a4a58dcd4..80684396e 100644 --- a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionPipelineIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionPipelineIntegrationTests.java @@ -426,4 +426,9 @@ public class JedisConnectionPipelineIntegrationTests extends public void testInfoBySection() throws Exception { super.testInfoBySection(); } + + @Test(expected=UnsupportedOperationException.class) + public void testHDelMultiple() { + super.testHDelMultiple(); + } } diff --git a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionTransactionIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionTransactionIntegrationTests.java index 88245f43c..b1155d22d 100644 --- a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionTransactionIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionTransactionIntegrationTests.java @@ -362,4 +362,9 @@ public class JedisConnectionTransactionIntegrationTests extends public void testLastSave() { super.testLastSave(); } + + @Test(expected=UnsupportedOperationException.class) + public void testHDelMultiple() { + super.testHDelMultiple(); + } } diff --git a/src/test/java/org/springframework/data/redis/connection/jredis/JRedisConnectionIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/jredis/JRedisConnectionIntegrationTests.java index 6a409d873..d8d1bb1ed 100644 --- a/src/test/java/org/springframework/data/redis/connection/jredis/JRedisConnectionIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/jredis/JRedisConnectionIntegrationTests.java @@ -560,6 +560,11 @@ public class JRedisConnectionIntegrationTests extends AbstractConnectionIntegrat super.testInfoBySection(); } + @Test(expected=UnsupportedOperationException.class) + public void testHDelMultiple() { + super.testHDelMultiple(); + } + // Jredis returns null for rPush and lPush @Test public void testLLen() { diff --git a/src/test/java/org/springframework/data/redis/core/DefaultHashOperationsTests.java b/src/test/java/org/springframework/data/redis/core/DefaultHashOperationsTests.java index 156769a32..50b8dbdeb 100644 --- a/src/test/java/org/springframework/data/redis/core/DefaultHashOperationsTests.java +++ b/src/test/java/org/springframework/data/redis/core/DefaultHashOperationsTests.java @@ -16,6 +16,7 @@ package org.springframework.data.redis.core; import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; import static org.springframework.data.redis.matcher.RedisTestMatchers.isEqual; import java.util.Arrays; @@ -117,4 +118,17 @@ public class DefaultHashOperationsTests { expected.put(key2, val2); assertThat(hashOps.entries(key), isEqual(expected)); } + + @Test + public void testDelete() { + K key = keyFactory.instance(); + HK key1 = hashKeyFactory.instance(); + HV val1 = hashValueFactory.instance(); + HK key2 = hashKeyFactory.instance(); + HV val2 = hashValueFactory.instance(); + hashOps.put(key, key1, val1); + hashOps.put(key, key2, val2); + hashOps.delete(key, key1, key2); + assertTrue(hashOps.keys(key).isEmpty()); + } }