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 8abeaed3e..751d00d9c 100644 --- a/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java @@ -972,6 +972,20 @@ public class DefaultStringRedisConnection implements StringRedisConnection { return result; } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zCount(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) + */ + @Override + public Long zCount(byte[] key, Range range) { + + Long result = delegate.zCount(key, range); + if (isFutureConversion()) { + addResultConverter(identityConverter); + } + return result; + } + public Double zIncrBy(byte[] key, double increment, byte[] value) { Double result = delegate.zIncrBy(key, increment, value); if (isFutureConversion()) { @@ -1012,6 +1026,48 @@ public class DefaultStringRedisConnection implements StringRedisConnection { return results; } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) + */ + @Override + public Set zRangeByScore(byte[] key, Range range) { + + Set results = delegate.zRangeByScore(key, range); + if (isFutureConversion()) { + addResultConverter(identityConverter); + } + return results; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) + */ + @Override + public Set zRangeByScore(byte[] key, Range range, Limit limit) { + + Set results = delegate.zRangeByScore(key, range, limit); + if (isFutureConversion()) { + addResultConverter(identityConverter); + } + return results; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScoreWithScores(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) + */ + @Override + public Set zRangeByScoreWithScores(byte[] key, Range range) { + + Set results = delegate.zRangeByScoreWithScores(key, range); + if (isFutureConversion()) { + addResultConverter(identityConverter); + } + return results; + } + public Set zRangeByScore(byte[] key, double min, double max) { Set results = delegate.zRangeByScore(key, min, max); if (isFutureConversion()) { @@ -1028,6 +1084,20 @@ public class DefaultStringRedisConnection implements StringRedisConnection { return results; } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScoreWithScores(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) + */ + @Override + public Set zRangeByScoreWithScores(byte[] key, Range range, Limit limit) { + + Set results = delegate.zRangeByScoreWithScores(key, range, limit); + if (isFutureConversion()) { + addResultConverter(identityConverter); + } + return results; + } + public Set zRangeByScoreWithScores(byte[] key, double min, double max) { Set results = delegate.zRangeByScoreWithScores(key, min, max); if (isFutureConversion()) { @@ -1052,6 +1122,20 @@ public class DefaultStringRedisConnection implements StringRedisConnection { return results; } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) + */ + @Override + public Set zRevRangeByScore(byte[] key, Range range) { + + Set results = delegate.zRevRangeByScore(key, range); + if (isFutureConversion()) { + addResultConverter(identityConverter); + } + return results; + } + public Set zRevRangeByScore(byte[] key, double min, double max) { Set results = delegate.zRevRangeByScore(key, min, max); if (isFutureConversion()) { @@ -1060,6 +1144,20 @@ public class DefaultStringRedisConnection implements StringRedisConnection { return results; } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) + */ + @Override + public Set zRevRangeByScore(byte[] key, Range range, Limit limit) { + + Set results = delegate.zRevRangeByScore(key, range, limit); + if (isFutureConversion()) { + addResultConverter(identityConverter); + } + return results; + } + public Set zRevRangeByScoreWithScores(byte[] key, double min, double max, long offset, long count) { Set results = delegate.zRevRangeByScoreWithScores(key, min, max, offset, count); if (isFutureConversion()) { @@ -1068,6 +1166,34 @@ public class DefaultStringRedisConnection implements StringRedisConnection { return results; } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScoreWithScores(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) + */ + @Override + public Set zRevRangeByScoreWithScores(byte[] key, Range range) { + + Set results = delegate.zRevRangeByScoreWithScores(key, range); + if (isFutureConversion()) { + addResultConverter(identityConverter); + } + return results; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScoreWithScores(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) + */ + @Override + public Set zRevRangeByScoreWithScores(byte[] key, Range range, Limit limit) { + + Set results = delegate.zRevRangeByScoreWithScores(key, range, limit); + if (isFutureConversion()) { + addResultConverter(identityConverter); + } + return results; + } + public Set zRevRangeByScoreWithScores(byte[] key, double min, double max) { Set results = delegate.zRevRangeByScoreWithScores(key, min, max); if (isFutureConversion()) { @@ -1108,6 +1234,15 @@ public class DefaultStringRedisConnection implements StringRedisConnection { return result; } + @Override + public Long zRemRangeByScore(byte[] key, Range range) { + Long result = delegate.zRemRangeByScore(key, range); + if (isFutureConversion()) { + addResultConverter(identityConverter); + } + return result; + } + public Set zRevRange(byte[] key, long start, long end) { Set results = delegate.zRevRange(key, start, end); if (isFutureConversion()) { diff --git a/src/main/java/org/springframework/data/redis/connection/RedisZSetCommands.java b/src/main/java/org/springframework/data/redis/connection/RedisZSetCommands.java index a55c39eab..35ef742a6 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisZSetCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisZSetCommands.java @@ -309,6 +309,16 @@ public interface RedisZSetCommands { */ Set zRangeByScore(byte[] key, double min, double max); + /** + * Get set of {@link Tuple}s where score is between {@code Range#min} and {@code Range#max} from sorted set. + * + * @param key + * @param range + * @return + * @since 1.6 + */ + Set zRangeByScoreWithScores(byte[] key, Range range); + /** * Get set of {@link Tuple}s where score is between {@code min} and {@code max} from sorted set. *

@@ -351,6 +361,18 @@ public interface RedisZSetCommands { */ Set zRangeByScoreWithScores(byte[] key, double min, double max, long offset, long count); + /** + * Get set of {@link Tuple}s in range from {@code Limit#offset} to {@code Limit#offset + Limit#count} where score is + * between {@code Range#min} and {@code Range#max} from sorted set. + * + * @param key + * @param range + * @param limit + * @return + * @since 1.6 + */ + Set zRangeByScoreWithScores(byte[] key, Range range, Limit limit); + /** * Get elements in range from {@code begin} to {@code end} from sorted set ordered from high to low. *

@@ -387,6 +409,17 @@ public interface RedisZSetCommands { */ Set zRevRangeByScore(byte[] key, double min, double max); + /** + * Get elements where score is between {@code Range#min} and {@code Range#max} from sorted set ordered from high to + * low. + * + * @param key + * @param range + * @return + * @since 1.6 + */ + Set zRevRangeByScore(byte[] key, Range range); + /** * Get set of {@link Tuple} where score is between {@code min} and {@code max} from sorted set ordered from high to * low. @@ -415,6 +448,18 @@ public interface RedisZSetCommands { */ Set zRevRangeByScore(byte[] key, double min, double max, long offset, long count); + /** + * Get elements in range from {@code Limit#offset} to {@code Limit#offset + Limit#count} where score is between + * {@code Range#min} and {@code Range#max} from sorted set ordered high -> low. + * + * @param key + * @param range + * @param limit + * @return + * @since 1.6 + */ + Set zRevRangeByScore(byte[] key, Range range, Limit limit); + /** * Get set of {@link Tuple} in range from {@code begin} to {@code end} where score is between {@code min} and * {@code max} from sorted set ordered high -> low. @@ -430,6 +475,29 @@ public interface RedisZSetCommands { */ Set zRevRangeByScoreWithScores(byte[] key, double min, double max, long offset, long count); + /** + * Get set of {@link Tuple} where score is between {@code Range#min} and {@code Range#max} from sorted set ordered + * from high to low. + * + * @param key + * @param range + * @return + * @since 1.6 + */ + Set zRevRangeByScoreWithScores(byte[] key, Range range); + + /** + * Get set of {@link Tuple} in range from {@code Limit#offset} to {@code Limit#count} where score is between + * {@code Range#min} and {@code Range#max} from sorted set ordered high -> low. + * + * @param key + * @param range + * @param limit + * @return + * @since 1.6 + */ + Set zRevRangeByScoreWithScores(byte[] key, Range range, Limit limit); + /** * Count number of elements within sorted set with scores between {@code min} and {@code max}. *

@@ -442,6 +510,17 @@ public interface RedisZSetCommands { */ Long zCount(byte[] key, double min, double max); + /** + * Count number of elements within sorted set with scores between {@code Range#min} and {@code Range#max}. + * + * @param key + * @param min + * @param max + * @return + * @since 1.6 + */ + Long zCount(byte[] key, Range range); + /** * Get the size of sorted set with {@code key}. *

@@ -487,6 +566,16 @@ public interface RedisZSetCommands { */ Long zRemRangeByScore(byte[] key, double min, double max); + /** + * Remove elements with scores between {@code Range#min} and {@code Range#max} from sorted set with {@code key}. + * + * @param key + * @param range + * @return + * @since 1.6 + */ + Long zRemRangeByScore(byte[] key, Range range); + /** * Union sorted {@code sets} and store result in destination {@code key}. *

@@ -558,6 +647,16 @@ public interface RedisZSetCommands { */ Set zRangeByScore(byte[] key, String min, String max); + /** + * Get elements where score is between {@code Range#min} and {@code Range#max} from sorted set. + * + * @param key + * @param range + * @return + * @since 1.6 + */ + Set zRangeByScore(byte[] key, Range range); + /** * Get elements in range from {@code begin} to {@code end} where score is between {@code min} and {@code max} from * sorted set. @@ -574,6 +673,18 @@ public interface RedisZSetCommands { */ Set zRangeByScore(byte[] key, String min, String max, long offset, long count); + /** + * Get elements in range from {@code Limit#count} to {@code Limit#offset} where score is between {@code Range#min} and + * {@code Range#max} from sorted set. + * + * @param key + * @param range + * @param limit + * @return + * @since 1.6 + */ + Set zRangeByScore(byte[] key, Range range, Limit limit); + /** * Get all the elements in the sorted set at {@literal key} in lexicographical ordering. * 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 73c2b125a..2fe78a467 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 @@ -2058,6 +2058,24 @@ public class JedisConnection extends AbstractRedisConnection { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zCount(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) + */ + @Override + public Long zCount(byte[] key, Range range) { + + if (isPipelined() || isQueueing()) { + throw new UnsupportedOperationException( + "ZCOUNT not implemented in jedis for binary protocol on transaction and pipeline"); + } + + byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); + byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); + + return jedis.zcount(key, min, max); + } + public Double zIncrBy(byte[] key, double increment, byte[] value) { try { if (isPipelined()) { @@ -2164,8 +2182,8 @@ public class JedisConnection extends AbstractRedisConnection { Assert.notNull(range, "Range cannot be null for ZRANGEBYLEX."); - byte[] min = JedisConverters.boundaryToBytesForZRangeByLex(range.getMin(), JedisConverters.toBytes("-")); - byte[] max = JedisConverters.boundaryToBytesForZRangeByLex(range.getMax(), JedisConverters.toBytes("+")); + byte[] min = JedisConverters.boundaryToBytesForZRangeByLex(range.getMin(), JedisConverters.MINUS_BYTES); + byte[] max = JedisConverters.boundaryToBytesForZRangeByLex(range.getMax(), JedisConverters.PLUS_BYTES); try { if (isPipelined()) { @@ -2195,33 +2213,120 @@ public class JedisConnection extends AbstractRedisConnection { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScore(byte[], double, double) + */ public Set zRangeByScore(byte[] key, double min, double max) { + return zRangeByScore(key, new Range().gte(min).lte(max)); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) + */ + @Override + public Set zRangeByScore(byte[] key, Range range) { + return zRangeByScore(key, range, null); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) + */ + @Override + public Set zRangeByScore(byte[] key, Range range, Limit limit) { + + Assert.notNull(range, "Range cannot be null for ZRANGEBYSCORE."); + + byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); + byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); + try { if (isPipelined()) { - pipeline(new JedisResult(pipeline.zrangeByScore(key, min, max))); + if (limit != null) { + pipeline(new JedisResult(pipeline.zrangeByScore(key, min, max, limit.getOffset(), limit.getCount()))); + } else { + pipeline(new JedisResult(pipeline.zrangeByScore(key, min, max))); + } return null; } + if (isQueueing()) { - transaction(new JedisResult(transaction.zrangeByScore(key, min, max))); + if (limit != null) { + transaction(new JedisResult(transaction.zrangeByScore(key, min, max, limit.getOffset(), limit.getCount()))); + } else { + transaction(new JedisResult(transaction.zrangeByScore(key, min, max))); + } return null; } + + if (limit != null) { + return jedis.zrangeByScore(key, min, max, limit.getOffset(), limit.getCount()); + } return jedis.zrangeByScore(key, min, max); } catch (Exception ex) { throw convertJedisAccessException(ex); } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScoreWithScores(byte[], double, double) + */ public Set zRangeByScoreWithScores(byte[] key, double min, double max) { + return zRangeByScoreWithScores(key, new Range().gte(min).lte(max)); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScoreWithScores(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) + */ + @Override + public Set zRangeByScoreWithScores(byte[] key, Range range) { + return zRangeByScoreWithScores(key, range, null); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScoreWithScores(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) + */ + @Override + public Set zRangeByScoreWithScores(byte[] key, Range range, Limit limit) { + + Assert.notNull(range, "Range cannot be null for ZRANGEBYSCOREWITHSCORES."); + + byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); + byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); + try { if (isPipelined()) { - pipeline(new JedisResult(pipeline.zrangeByScoreWithScores(key, min, max), JedisConverters.tupleSetToTupleSet())); + if (limit != null) { + pipeline(new JedisResult( + pipeline.zrangeByScoreWithScores(key, min, max, limit.getOffset(), limit.getCount()), + JedisConverters.tupleSetToTupleSet())); + } else { + pipeline(new JedisResult(pipeline.zrangeByScoreWithScores(key, min, max), + JedisConverters.tupleSetToTupleSet())); + } return null; } + if (isQueueing()) { - transaction(new JedisResult(transaction.zrangeByScoreWithScores(key, min, max), - JedisConverters.tupleSetToTupleSet())); + if (limit != null) { + transaction(new JedisResult(transaction.zrangeByScoreWithScores(key, min, max, limit.getOffset(), + limit.getCount()), JedisConverters.tupleSetToTupleSet())); + } else { + transaction(new JedisResult(transaction.zrangeByScoreWithScores(key, min, max), + JedisConverters.tupleSetToTupleSet())); + } return null; } + + if (limit != null) { + return JedisConverters.toTupleSet(jedis.zrangeByScoreWithScores(key, min, max, limit.getOffset(), + limit.getCount())); + } return JedisConverters.toTupleSet(jedis.zrangeByScoreWithScores(key, min, max)); } catch (Exception ex) { throw convertJedisAccessException(ex); @@ -2243,110 +2348,173 @@ public class JedisConnection extends AbstractRedisConnection { } catch (Exception ex) { throw convertJedisAccessException(ex); } + } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScore(byte[], double, double, long, long) + */ + @Override public Set zRangeByScore(byte[] key, double min, double max, long offset, long count) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.zrangeByScore(key, min, max, (int) offset, (int) count))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.zrangeByScore(key, min, max, (int) offset, (int) count))); - return null; - } - return jedis.zrangeByScore(key, min, max, (int) offset, (int) count); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } + + return zRangeByScore(key, new Range().gte(min).lte(max), + new Limit().offset(Long.valueOf(offset).intValue()).count(Long.valueOf(count).intValue())); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScoreWithScores(byte[], double, double, long, long) + */ + @Override public Set zRangeByScoreWithScores(byte[] key, double min, double max, long offset, long count) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.zrangeByScoreWithScores(key, min, max, (int) offset, (int) count), - JedisConverters.tupleSetToTupleSet())); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.zrangeByScoreWithScores(key, min, max, (int) offset, (int) count), - JedisConverters.tupleSetToTupleSet())); - return null; - } - return JedisConverters.toTupleSet(jedis.zrangeByScoreWithScores(key, min, max, (int) offset, (int) count)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } + + return zRangeByScoreWithScores(key, new Range().gte(min).lte(max), + new Limit().offset(Long.valueOf(offset).intValue()).count(Long.valueOf(count).intValue())); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScore(byte[], double, double, long, long) + */ + @Override public Set zRevRangeByScore(byte[] key, double min, double max, long offset, long count) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.zrevrangeByScore(key, max, min, (int) offset, (int) count))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.zrevrangeByScore(key, max, min, (int) offset, (int) count))); - return null; - } - return jedis.zrevrangeByScore(key, max, min, (int) offset, (int) count); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } + + return zRevRangeByScore(key, new Range().gte(min).lte(max), new Limit().offset(Long.valueOf(offset).intValue()) + .count(Long.valueOf(count).intValue())); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScore(byte[], double, double) + */ + @Override public Set zRevRangeByScore(byte[] key, double min, double max) { + return zRevRangeByScore(key, new Range().gte(min).lte(max)); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) + */ + @Override + public Set zRevRangeByScore(byte[] key, Range range) { + return zRevRangeByScore(key, range, null); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) + */ + @Override + public Set zRevRangeByScore(byte[] key, Range range, Limit limit) { + + Assert.notNull(range, "Range cannot be null for ZREVRANGEBYSCORE."); + + byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); + byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); + try { if (isPipelined()) { - pipeline(new JedisResult(pipeline.zrevrangeByScore(key, max, min))); + if (limit != null) { + pipeline(new JedisResult(pipeline.zrevrangeByScore(key, max, min, limit.getOffset(), limit.getCount()))); + } else { + pipeline(new JedisResult(pipeline.zrevrangeByScore(key, max, min))); + } return null; } + if (isQueueing()) { - transaction(new JedisResult(transaction.zrevrangeByScore(key, max, min))); + if (limit != null) { + transaction(new JedisResult(transaction.zrevrangeByScore(key, max, min, limit.getOffset(), limit.getCount()))); + } else { + transaction(new JedisResult(transaction.zrevrangeByScore(key, max, min))); + } return null; } + + if (limit != null) { + return jedis.zrevrangeByScore(key, max, min, limit.getOffset(), limit.getCount()); + } return jedis.zrevrangeByScore(key, max, min); } catch (Exception ex) { throw convertJedisAccessException(ex); } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScoreWithScores(byte[], double, double, long, long) + */ + @Override public Set zRevRangeByScoreWithScores(byte[] key, double min, double max, long offset, long count) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.zrevrangeByScoreWithScores(key, max, min, (int) offset, (int) count), - JedisConverters.tupleSetToTupleSet())); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.zrevrangeByScoreWithScores(key, max, min, (int) offset, (int) count), - JedisConverters.tupleSetToTupleSet())); - return null; - } - return JedisConverters.toTupleSet(jedis.zrevrangeByScoreWithScores(key, max, min, (int) offset, (int) count)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } + + return zRevRangeByScoreWithScores(key, new Range().gte(min).lte(max), + new Limit().offset(Long.valueOf(offset).intValue()).count(Long.valueOf(count).intValue())); } - public Set zRevRangeByScoreWithScores(byte[] key, double min, double max) { + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScoreWithScores(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) + */ + @Override + public Set zRevRangeByScoreWithScores(byte[] key, Range range) { + return zRevRangeByScoreWithScores(key, range, null); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScoreWithScores(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) + */ + @Override + public Set zRevRangeByScoreWithScores(byte[] key, Range range, Limit limit) { + + Assert.notNull(range, "Range cannot be null for ZREVRANGEBYSCOREWITHSCORES."); + + byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); + byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); + try { if (isPipelined()) { - pipeline(new JedisResult(pipeline.zrevrangeByScoreWithScores(key, max, min), - JedisConverters.tupleSetToTupleSet())); + if (limit != null) { + pipeline(new JedisResult(pipeline.zrevrangeByScoreWithScores(key, max, min, limit.getOffset(), + limit.getCount()), JedisConverters.tupleSetToTupleSet())); + } else { + pipeline(new JedisResult(pipeline.zrevrangeByScoreWithScores(key, max, min), + JedisConverters.tupleSetToTupleSet())); + } return null; } + if (isQueueing()) { - transaction(new JedisResult(transaction.zrevrangeByScoreWithScores(key, max, min), - JedisConverters.tupleSetToTupleSet())); + if (limit != null) { + transaction(new JedisResult(transaction.zrevrangeByScoreWithScores(key, max, min, limit.getOffset(), + limit.getCount()), JedisConverters.tupleSetToTupleSet())); + } else { + transaction(new JedisResult(transaction.zrevrangeByScoreWithScores(key, max, min), + JedisConverters.tupleSetToTupleSet())); + } return null; } + + if (limit != null) { + return JedisConverters.toTupleSet(jedis.zrevrangeByScoreWithScores(key, max, min, limit.getOffset(), + limit.getCount())); + } return JedisConverters.toTupleSet(jedis.zrevrangeByScoreWithScores(key, max, min)); } catch (Exception ex) { throw convertJedisAccessException(ex); } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScoreWithScores(byte[], double, double) + */ + public Set zRevRangeByScoreWithScores(byte[] key, double min, double max) { + return zRevRangeByScoreWithScores(key, new Range().gte(min).lte(max), null); + } + public Long zRank(byte[] key, byte[] value) { try { if (isPipelined()) { @@ -2395,7 +2563,27 @@ public class JedisConnection extends AbstractRedisConnection { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRemRangeByScore(byte[], double, double) + */ + @Override public Long zRemRangeByScore(byte[] key, double min, double max) { + return zRemRangeByScore(key, new Range().gte(min).lte(max)); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRemRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) + */ + @Override + public Long zRemRangeByScore(byte[] key, Range range) { + + Assert.notNull(range, "Range cannot be null for ZREMRANGEBYSCORE."); + + byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); + byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); + try { if (isPipelined()) { pipeline(new JedisResult(pipeline.zremrangeByScore(key, min, max))); @@ -3330,4 +3518,5 @@ public class JedisConnection extends AbstractRedisConnection { throw convertJedisAccessException(ex); } } + } diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisConverters.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisConverters.java index 6a3587a4a..9c0404fee 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisConverters.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisConverters.java @@ -20,7 +20,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Properties; import java.util.Set; import org.springframework.core.convert.converter.Converter; @@ -50,7 +49,7 @@ import redis.clients.jedis.SortingParams; import redis.clients.util.SafeEncoder; /** - * Jedis type converters + * Jedis type converters. * * @author Jennifer Hickey * @author Christoph Strobl @@ -67,10 +66,15 @@ abstract public class JedisConverters extends Converters { private static final Converter EXCEPTION_CONVERTER = new JedisExceptionConverter(); private static final Converter> STRING_TO_CLIENT_INFO_CONVERTER = new StringToRedisClientInfoConverter(); private static final Converter TUPLE_CONVERTER; - private static final Converter PROPERTIES_TO_SENTINEL; private static final ListConverter TUPLE_LIST_TO_TUPLE_LIST_CONVERTER; + public static final byte[] PLUS_BYTES; + public static final byte[] MINUS_BYTES; + public static final byte[] POSITIVE_INFINITY_BYTES; + public static final byte[] NEGATIVE_INFINITY_BYTES; + static { + STRING_TO_BYTES = new Converter() { public byte[] convert(String source) { return source == null ? null : SafeEncoder.encode(source); @@ -87,14 +91,11 @@ abstract public class JedisConverters extends Converters { }; TUPLE_SET_TO_TUPLE_SET = new SetConverter(TUPLE_CONVERTER); TUPLE_LIST_TO_TUPLE_LIST_CONVERTER = new ListConverter(TUPLE_CONVERTER); - PROPERTIES_TO_SENTINEL = new Converter() { - - @Override - public RedisServer convert(Properties source) { - return source != null ? RedisServer.newServerFrom(source) : null; - - } - }; + + PLUS_BYTES = toBytes("+"); + MINUS_BYTES = toBytes("-"); + POSITIVE_INFINITY_BYTES = toBytes("+inf"); + NEGATIVE_INFINITY_BYTES = toBytes("-inf"); } public static Converter stringToBytes() { @@ -151,6 +152,15 @@ abstract public class JedisConverters extends Converters { return String.valueOf(source).getBytes(); } + /** + * @param source + * @return + * @since 1.6 + */ + public static byte[] toBytes(Double source) { + return toBytes(String.valueOf(source)); + } + public static byte[] toBytes(String source) { return STRING_TO_BYTES.convert(source); } @@ -252,6 +262,24 @@ abstract public class JedisConverters extends Converters { } } + /** + * Converts a given {@link Boundary} to its binary representation suitable for {@literal ZRANGEBY*} commands, despite + * {@literal ZRANGEBYLEX}. + * + * @param boundary + * @param defaultValue + * @return + * @since 1.6 + */ + public static byte[] boundaryToBytesForZRange(Boundary boundary, byte[] defaultValue) { + + if (boundary == null || boundary.getValue() == null) { + return defaultValue; + } + + return boundaryToBytes(boundary, new byte[] {}, toBytes("(")); + } + /** * Converts a given {@link Boundary} to its binary representation suitable for ZRANGEBYLEX command. * @@ -265,10 +293,17 @@ abstract public class JedisConverters extends Converters { return defaultValue; } - byte[] prefix = boundary.isIncluding() ? toBytes("[") : toBytes("("); + return boundaryToBytes(boundary, toBytes("["), toBytes("(")); + } + + private static byte[] boundaryToBytes(Boundary boundary, byte[] inclPrefix, byte[] exclPrefix) { + + byte[] prefix = boundary.isIncluding() ? inclPrefix : exclPrefix; byte[] value = null; if (boundary.getValue() instanceof byte[]) { value = (byte[]) boundary.getValue(); + } else if (boundary.getValue() instanceof Double) { + value = toBytes((Double) boundary.getValue()); } else if (boundary.getValue() instanceof Long) { value = toBytes((Long) boundary.getValue()); } else if (boundary.getValue() instanceof Integer) { @@ -283,5 +318,6 @@ abstract public class JedisConverters extends Converters { buffer.put(prefix); buffer.put(value); return buffer.array(); + } } 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 a0cb7a1a6..fc3908bc0 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 @@ -899,6 +899,17 @@ public class JredisConnection extends AbstractRedisConnection { } public Long zCount(byte[] key, double min, double max) { + return zCount(key, new Range().gte(min).lte(max)); + } + + @Override + public Long zCount(byte[] key, Range range) { + + Assert.notNull(range, "Range for ZCOUNT must not be null!"); + + double min = ((Double) range.getMin().getValue()).doubleValue(); + double max = ((Double) range.getMax().getValue()).doubleValue(); + try { return jredis.zcount(key, min, max); } catch (Exception ex) { @@ -946,6 +957,16 @@ public class JredisConnection extends AbstractRedisConnection { throw new UnsupportedOperationException(); } + @Override + public Set zRangeByScoreWithScores(byte[] key, Range range) { + throw new UnsupportedOperationException(); + } + + @Override + public Set zRangeByScoreWithScores(byte[] key, Range range, Limit limit) { + throw new UnsupportedOperationException(); + } + public Set zRangeByScore(byte[] key, double min, double max, long offset, long count) { throw new UnsupportedOperationException(); } @@ -1346,4 +1367,39 @@ public class JredisConnection extends AbstractRedisConnection { public Set zRangeByLex(byte[] key, Range range, Limit limit) { throw new UnsupportedOperationException("ZRANGEBYLEX is no supported for jredis."); } + + @Override + public Set zRevRangeByScore(byte[] key, Range range) { + throw new UnsupportedOperationException(); + } + + @Override + public Set zRevRangeByScore(byte[] key, Range range, Limit limit) { + throw new UnsupportedOperationException(); + } + + @Override + public Set zRevRangeByScoreWithScores(byte[] key, Range range, Limit limit) { + throw new UnsupportedOperationException(); + } + + @Override + public Long zRemRangeByScore(byte[] key, Range range) { + throw new UnsupportedOperationException(); + } + + @Override + public Set zRangeByScore(byte[] key, Range range) { + throw new UnsupportedOperationException(); + } + + @Override + public Set zRangeByScore(byte[] key, Range range, Limit limit) { + throw new UnsupportedOperationException(); + } + + @Override + public Set zRevRangeByScoreWithScores(byte[] key, Range range) { + throw new UnsupportedOperationException(); + } } 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 4f22d3826..2843a9987 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 @@ -2109,7 +2109,19 @@ public class LettuceConnection extends AbstractRedisConnection { } } + @Override public Long zCount(byte[] key, double min, double max) { + return zCount(key, new Range().gte(min).lte(max)); + } + + @Override + public Long zCount(byte[] key, Range range) { + + Assert.notNull(range, "Range for ZCOUNT must not be null!"); + + String min = LettuceConverters.boundaryToStringForZRange(range.getMin(), "-inf"); + String max = LettuceConverters.boundaryToStringForZRange(range.getMax(), "+inf"); + try { if (isPipelined()) { pipeline(new LettuceResult(getAsyncConnection().zcount(key, min, max))); @@ -2211,36 +2223,98 @@ public class LettuceConnection extends AbstractRedisConnection { } } + @Override public Set zRangeByScore(byte[] key, double min, double max) { + return zRangeByScore(key, new Range().gte(min).lte(max)); + } + + @Override + public Set zRangeByScore(byte[] key, Range range) { + return zRangeByScore(key, range, null); + } + + @Override + public Set zRangeByScore(byte[] key, Range range, Limit limit) { + + Assert.notNull(range, "Range for ZRANGEBYSCORE must not be null!"); + + String min = LettuceConverters.boundaryToStringForZRange(range.getMin(), "-inf"); + String max = LettuceConverters.boundaryToStringForZRange(range.getMax(), "+inf"); + try { if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().zrangebyscore(key, min, max), - LettuceConverters.bytesListToBytesSet())); + if (limit != null) { + pipeline(new LettuceResult(getAsyncConnection().zrangebyscore(key, min, max, limit.getOffset(), + limit.getCount()), LettuceConverters.bytesListToBytesSet())); + } else { + pipeline(new LettuceResult(getAsyncConnection().zrangebyscore(key, min, max), + LettuceConverters.bytesListToBytesSet())); + } return null; } if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().zrangebyscore(key, min, max), - LettuceConverters.bytesListToBytesSet())); + if (limit != null) { + transaction(new LettuceTxResult(getConnection().zrangebyscore(key, min, max, limit.getOffset(), + limit.getCount()), LettuceConverters.bytesListToBytesSet())); + } else { + transaction(new LettuceTxResult(getConnection().zrangebyscore(key, min, max), + LettuceConverters.bytesListToBytesSet())); + } return null; } + if (limit != null) { + return LettuceConverters.toBytesSet(getConnection().zrangebyscore(key, min, max, limit.getOffset(), + limit.getCount())); + } return LettuceConverters.toBytesSet(getConnection().zrangebyscore(key, min, max)); } catch (Exception ex) { throw convertLettuceAccessException(ex); } } + @Override public Set zRangeByScoreWithScores(byte[] key, double min, double max) { + return zRangeByScoreWithScores(key, new Range().gte(min).lte(max)); + } + + @Override + public Set zRangeByScoreWithScores(byte[] key, Range range) { + return zRangeByScoreWithScores(key, range, null); + } + + @Override + public Set zRangeByScoreWithScores(byte[] key, Range range, Limit limit) { + + Assert.notNull(range, "Range for ZRANGEBYSCOREWITHSCORES must not be null!"); + + String min = LettuceConverters.boundaryToStringForZRange(range.getMin(), "-inf"); + String max = LettuceConverters.boundaryToStringForZRange(range.getMax(), "+inf"); + try { if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().zrangebyscoreWithScores(key, min, max), - LettuceConverters.scoredValuesToTupleSet())); + if (limit != null) { + pipeline(new LettuceResult(getAsyncConnection().zrangebyscoreWithScores(key, min, max, limit.getOffset(), + limit.getCount()), LettuceConverters.scoredValuesToTupleSet())); + } else { + pipeline(new LettuceResult(getAsyncConnection().zrangebyscoreWithScores(key, min, max), + LettuceConverters.scoredValuesToTupleSet())); + } return null; } if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().zrangebyscoreWithScores(key, min, max), - LettuceConverters.scoredValuesToTupleSet())); + if (limit != null) { + transaction(new LettuceTxResult(getConnection().zrangebyscoreWithScores(key, min, max, limit.getOffset(), + limit.getCount()), LettuceConverters.scoredValuesToTupleSet())); + } else { + transaction(new LettuceTxResult(getConnection().zrangebyscoreWithScores(key, min, max), + LettuceConverters.scoredValuesToTupleSet())); + } return null; } + if (limit != null) { + return LettuceConverters.toTupleSet(getConnection().zrangebyscoreWithScores(key, min, max, limit.getOffset(), + limit.getCount())); + } return LettuceConverters.toTupleSet(getConnection().zrangebyscoreWithScores(key, min, max)); } catch (Exception ex) { throw convertLettuceAccessException(ex); @@ -2265,114 +2339,132 @@ public class LettuceConnection extends AbstractRedisConnection { } } + @Override public Set zRangeByScore(byte[] key, double min, double max, long offset, long count) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().zrangebyscore(key, min, max, offset, count), - LettuceConverters.bytesListToBytesSet())); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().zrangebyscore(key, min, max, offset, count), - LettuceConverters.bytesListToBytesSet())); - return null; - } - return LettuceConverters.toBytesSet(getConnection().zrangebyscore(key, min, max, offset, count)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + + return zRangeByScore(key, new Range().gte(min).lte(max), + new Limit().offset(Long.valueOf(offset).intValue()).count(Long.valueOf(count).intValue())); } + @Override public Set zRangeByScoreWithScores(byte[] key, double min, double max, long offset, long count) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().zrangebyscoreWithScores(key, min, max, offset, count), - LettuceConverters.scoredValuesToTupleSet())); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().zrangebyscoreWithScores(key, min, max, offset, count), - LettuceConverters.scoredValuesToTupleSet())); - return null; - } - return LettuceConverters.toTupleSet(getConnection().zrangebyscoreWithScores(key, min, max, offset, count)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + + return zRangeByScoreWithScores(key, new Range().gte(min).lte(max), + new Limit().offset(Long.valueOf(offset).intValue()).count(Long.valueOf(count).intValue())); } + @Override public Set zRevRangeByScore(byte[] key, double min, double max, long offset, long count) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().zrevrangebyscore(key, max, min, offset, count), - LettuceConverters.bytesListToBytesSet())); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().zrevrangebyscore(key, max, min, offset, count), - LettuceConverters.bytesListToBytesSet())); - return null; - } - return LettuceConverters.toBytesSet(getConnection().zrevrangebyscore(key, max, min, offset, count)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + + return zRevRangeByScore(key, new Range().gte(min).lte(max), new Limit().offset(Long.valueOf(offset).intValue()) + .count(Long.valueOf(count).intValue())); } - public Set zRevRangeByScore(byte[] key, double min, double max) { + @Override + public Set zRevRangeByScore(byte[] key, Range range) { + return zRevRangeByScore(key, range, null); + } + + @Override + public Set zRevRangeByScore(byte[] key, Range range, Limit limit) { + + Assert.notNull(range, "Range for ZREVRANGEBYSCORE must not be null!"); + + String min = LettuceConverters.boundaryToStringForZRange(range.getMin(), "-inf"); + String max = LettuceConverters.boundaryToStringForZRange(range.getMax(), "+inf"); + try { if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().zrevrangebyscore(key, max, min), - LettuceConverters.bytesListToBytesSet())); + if (limit != null) { + pipeline(new LettuceResult(getAsyncConnection().zrevrangebyscore(key, max, min, limit.getOffset(), + limit.getCount()), LettuceConverters.bytesListToBytesSet())); + } else { + pipeline(new LettuceResult(getAsyncConnection().zrevrangebyscore(key, max, min), + LettuceConverters.bytesListToBytesSet())); + } return null; } if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().zrevrangebyscore(key, max, min), - LettuceConverters.bytesListToBytesSet())); + if (limit != null) { + transaction(new LettuceTxResult(getConnection().zrevrangebyscore(key, max, min, limit.getOffset(), + limit.getCount()), LettuceConverters.bytesListToBytesSet())); + } else { + transaction(new LettuceTxResult(getConnection().zrevrangebyscore(key, max, min), + LettuceConverters.bytesListToBytesSet())); + } return null; } + if (limit != null) { + return LettuceConverters.toBytesSet(getConnection().zrevrangebyscore(key, max, min, limit.getOffset(), + limit.getCount())); + } return LettuceConverters.toBytesSet(getConnection().zrevrangebyscore(key, max, min)); } catch (Exception ex) { throw convertLettuceAccessException(ex); } } - public Set zRevRangeByScoreWithScores(byte[] key, double min, double max, long offset, long count) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().zrevrangebyscoreWithScores(key, max, min, offset, count), - LettuceConverters.scoredValuesToTupleSet())); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().zrevrangebyscoreWithScores(key, max, min, offset, count), - LettuceConverters.scoredValuesToTupleSet())); - return null; - } - return LettuceConverters.toTupleSet(getConnection().zrevrangebyscoreWithScores(key, max, min, offset, count)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + @Override + public Set zRevRangeByScore(byte[] key, double min, double max) { + return zRevRangeByScore(key, new Range().gte(min).lte(max)); } - public Set zRevRangeByScoreWithScores(byte[] key, double min, double max) { + @Override + public Set zRevRangeByScoreWithScores(byte[] key, double min, double max, long offset, long count) { + + return zRevRangeByScoreWithScores(key, new Range().gte(min).lte(max), + new Limit().offset(Long.valueOf(offset).intValue()).count(Long.valueOf(count).intValue())); + } + + @Override + public Set zRevRangeByScoreWithScores(byte[] key, Range range) { + return zRevRangeByScoreWithScores(key, range, null); + } + + @Override + public Set zRevRangeByScoreWithScores(byte[] key, Range range, Limit limit) { + + Assert.notNull(range, "Range for ZREVRANGEBYSCOREWITHSCORES must not be null!"); + + String min = LettuceConverters.boundaryToStringForZRange(range.getMin(), "-inf"); + String max = LettuceConverters.boundaryToStringForZRange(range.getMax(), "+inf"); + try { if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().zrevrangebyscoreWithScores(key, max, min), - LettuceConverters.scoredValuesToTupleSet())); + if (limit != null) { + pipeline(new LettuceResult(getAsyncConnection().zrevrangebyscoreWithScores(key, max, min, limit.getOffset(), + limit.getCount()), LettuceConverters.scoredValuesToTupleSet())); + } else { + pipeline(new LettuceResult(getAsyncConnection().zrevrangebyscoreWithScores(key, max, min), + LettuceConverters.scoredValuesToTupleSet())); + } return null; } if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().zrevrangebyscoreWithScores(key, max, min), - LettuceConverters.scoredValuesToTupleSet())); + if (limit != null) { + transaction(new LettuceTxResult(getConnection().zrevrangebyscoreWithScores(key, max, min, limit.getOffset(), + limit.getCount()), LettuceConverters.scoredValuesToTupleSet())); + } else { + transaction(new LettuceTxResult(getConnection().zrevrangebyscoreWithScores(key, max, min), + LettuceConverters.scoredValuesToTupleSet())); + } return null; } + if (limit != null) { + return LettuceConverters.toTupleSet(getConnection().zrevrangebyscoreWithScores(key, max, min, + limit.getOffset(), limit.getCount())); + } return LettuceConverters.toTupleSet(getConnection().zrevrangebyscoreWithScores(key, max, min)); } catch (Exception ex) { throw convertLettuceAccessException(ex); } } + @Override + public Set zRevRangeByScoreWithScores(byte[] key, double min, double max) { + return zRevRangeByScoreWithScores(key, new Range().gte(min).lte(max)); + } + public Long zRank(byte[] key, byte[] value) { try { if (isPipelined()) { @@ -2421,7 +2513,19 @@ public class LettuceConnection extends AbstractRedisConnection { } } + @Override public Long zRemRangeByScore(byte[] key, double min, double max) { + return zRemRangeByScore(key, new Range().gte(min).lte(max)); + } + + @Override + public Long zRemRangeByScore(byte[] key, Range range) { + + Assert.notNull(range, "Range for ZREMRANGEBYSCORE must not be null!"); + + String min = LettuceConverters.boundaryToStringForZRange(range.getMin(), "-inf"); + String max = LettuceConverters.boundaryToStringForZRange(range.getMax(), "+inf"); + try { if (isPipelined()) { pipeline(new LettuceResult(getAsyncConnection().zremrangebyscore(key, min, max))); diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java index c7b266981..a30a72c38 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java @@ -30,6 +30,7 @@ import org.springframework.core.convert.converter.Converter; import org.springframework.dao.DataAccessException; import org.springframework.data.redis.connection.DefaultTuple; import org.springframework.data.redis.connection.RedisListCommands.Position; +import org.springframework.data.redis.connection.RedisZSetCommands.Range.Boundary; import org.springframework.data.redis.connection.RedisZSetCommands.Tuple; import org.springframework.data.redis.connection.ReturnType; import org.springframework.data.redis.connection.SortParameters; @@ -329,4 +330,26 @@ abstract public class LettuceConverters extends Converters { return stringToRedisClientListConverter().convert(clientList); } + public static String boundaryToStringForZRange(Boundary boundary, String defaultValue) { + + if (boundary == null || boundary.getValue() == null) { + return defaultValue; + } + + return boundaryToString(boundary, "", "("); + } + + private static String boundaryToString(Boundary boundary, String inclPrefix, String exclPrefix) { + + String prefix = boundary.isIncluding() ? inclPrefix : exclPrefix; + String value = null; + if (boundary.getValue() instanceof byte[]) { + value = toString((byte[]) boundary.getValue()); + } else { + value = boundary.getValue().toString(); + } + + return prefix + value; + } + } 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 2c1de63f3..8ca5e02a7 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 @@ -1574,6 +1574,15 @@ public class SrpConnection extends AbstractRedisConnection { } public Long zCount(byte[] key, double min, double max) { + return zCount(key, new Range().gte(min).lte(max)); + } + + @Override + public Long zCount(byte[] key, Range range) { + + byte[] min = SrpConverters.boundaryToBytesForZRange(range.getMin(), SrpConverters.toBytes("-inf")); + byte[] max = SrpConverters.boundaryToBytesForZRange(range.getMax(), SrpConverters.toBytes("+inf")); + try { if (isPipelined()) { pipeline(new SrpResult(pipeline.zcount(key, min, max))); @@ -1638,26 +1647,61 @@ public class SrpConnection extends AbstractRedisConnection { } public Set zRangeByScore(byte[] key, double min, double max) { + return zRangeByScore(key, new Range().gte(min).lte(max)); + } + + @Override + public Set zRangeByScore(byte[] key, Range range) { + return zRangeByScore(key, range, null); + } + + @Override + public Set zRangeByScore(byte[] key, Range range, Limit limit) { + + Assert.notNull(range, "Range for ZRANGEBYSCORE must not be null!"); + + byte[] min = SrpConverters.boundaryToBytesForZRange(range.getMin(), SrpConverters.toBytes("-inf")); + byte[] max = SrpConverters.boundaryToBytesForZRange(range.getMax(), SrpConverters.toBytes("+inf")); + + Object[] params = limit != null ? limitParams(limit.getOffset(), limit.getCount()) : EMPTY_PARAMS_ARRAY; + try { if (isPipelined()) { - pipeline(new SrpResult(pipeline.zrangebyscore(key, min, max, null, EMPTY_PARAMS_ARRAY), - SrpConverters.repliesToBytesSet())); + pipeline(new SrpResult(pipeline.zrangebyscore(key, min, max, null, params), SrpConverters.repliesToBytesSet())); return null; } - return SrpConverters.toBytesSet(client.zrangebyscore(key, min, max, null, EMPTY_PARAMS_ARRAY).data()); + return SrpConverters.toBytesSet(client.zrangebyscore(key, min, max, null, params).data()); } catch (Exception ex) { throw convertSrpAccessException(ex); } } public Set zRangeByScoreWithScores(byte[] key, double min, double max) { + return zRangeByScoreWithScores(key, new Range().gte(min).lte(max)); + } + + @Override + public Set zRangeByScoreWithScores(byte[] key, Range range) { + return zRangeByScoreWithScores(key, range, null); + } + + @Override + public Set zRangeByScoreWithScores(byte[] key, Range range, Limit limit) { + + Assert.notNull(range, "Range for ZRANGEBYSCOREWITHSCORES must not be null!"); + + byte[] min = SrpConverters.boundaryToBytesForZRange(range.getMin(), SrpConverters.toBytes("-inf")); + byte[] max = SrpConverters.boundaryToBytesForZRange(range.getMax(), SrpConverters.toBytes("+inf")); + + Object[] params = limit != null ? limitParams(limit.getOffset(), limit.getCount()) : EMPTY_PARAMS_ARRAY; + try { if (isPipelined()) { - pipeline(new SrpResult(pipeline.zrangebyscore(key, min, max, WITHSCORES, EMPTY_PARAMS_ARRAY), + pipeline(new SrpResult(pipeline.zrangebyscore(key, min, max, WITHSCORES, params), SrpConverters.repliesToTupleSet())); return null; } - return SrpConverters.toTupleSet(client.zrangebyscore(key, min, max, WITHSCORES, EMPTY_PARAMS_ARRAY).data()); + return SrpConverters.toTupleSet(client.zrangebyscore(key, min, max, WITHSCORES, params).data()); } catch (Exception ex) { throw convertSrpAccessException(ex); } @@ -1675,81 +1719,91 @@ public class SrpConnection extends AbstractRedisConnection { } } + @Override public Set zRangeByScore(byte[] key, double min, double max, long offset, long count) { - try { - Object[] limit = limitParams(offset, count); - if (isPipelined()) { - pipeline(new SrpResult(pipeline.zrangebyscore(key, min, max, null, limit), SrpConverters.repliesToBytesSet())); - return null; - } - return SrpConverters.toBytesSet(client.zrangebyscore(key, min, max, null, limit).data()); - } catch (Exception ex) { - throw convertSrpAccessException(ex); - } + + return zRangeByScore(key, new Range().gte(min).lte(max), + new Limit().offset(Long.valueOf(offset).intValue()).count(Long.valueOf(count).intValue())); } + @Override public Set zRangeByScoreWithScores(byte[] key, double min, double max, long offset, long count) { - try { - Object[] limit = limitParams(offset, count); - if (isPipelined()) { - pipeline(new SrpResult(pipeline.zrangebyscore(key, min, max, WITHSCORES, limit), - SrpConverters.repliesToTupleSet())); - return null; - } - return SrpConverters.toTupleSet(client.zrangebyscore(key, min, max, WITHSCORES, limit).data()); - } catch (Exception ex) { - throw convertSrpAccessException(ex); - } + + return zRangeByScoreWithScores(key, new Range().gte(min).lte(max), + new Limit().offset(Long.valueOf(offset).intValue()).count(Long.valueOf(count).intValue())); } public Set zRevRangeByScore(byte[] key, double min, double max, long offset, long count) { - try { - Object[] limit = limitParams(offset, count); - if (isPipelined()) { - pipeline(new SrpResult(pipeline.zrevrangebyscore(key, max, min, null, limit), SrpConverters.repliesToBytesSet())); - return null; - } - return SrpConverters.toBytesSet(client.zrevrangebyscore(key, max, min, null, limit).data()); - } catch (Exception ex) { - throw convertSrpAccessException(ex); - } + return zRevRangeByScore(key, new Range().gte(min).lte(max), new Limit().offset(Long.valueOf(offset).intValue()) + .count(Long.valueOf(count).intValue())); + } + @Override public Set zRevRangeByScore(byte[] key, double min, double max) { + return zRevRangeByScore(key, new Range().gte(min).lte(max)); + } + + @Override + public Set zRevRangeByScoreWithScores(byte[] key, double min, double max, long offset, long count) { + return zRevRangeByScoreWithScores(key, new Range().gte(min).lte(max), + new Limit().offset(Long.valueOf(offset).intValue()).count(Long.valueOf(count).intValue())); + } + + @Override + public Set zRevRangeByScoreWithScores(byte[] key, double min, double max) { + return zRevRangeByScoreWithScores(key, new Range().gte(min).lte(max)); + } + + @Override + public Set zRevRangeByScore(byte[] key, Range range) { + return zRevRangeByScore(key, range, null); + } + + @Override + public Set zRevRangeByScore(byte[] key, Range range, Limit limit) { + + Assert.notNull(range, "Range for ZRANGEBYSCOREWITHSCORES must not be null!"); + + byte[] min = SrpConverters.boundaryToBytesForZRange(range.getMin(), SrpConverters.toBytes("-inf")); + byte[] max = SrpConverters.boundaryToBytesForZRange(range.getMax(), SrpConverters.toBytes("+inf")); + + Object[] params = limit != null ? limitParams(limit.getOffset(), limit.getCount()) : EMPTY_PARAMS_ARRAY; + try { if (isPipelined()) { - pipeline(new SrpResult(pipeline.zrevrangebyscore(key, max, min, null, EMPTY_PARAMS_ARRAY), + pipeline(new SrpResult(pipeline.zrevrangebyscore(key, max, min, null, params), SrpConverters.repliesToBytesSet())); return null; } - return SrpConverters.toBytesSet(client.zrevrangebyscore(key, max, min, null, EMPTY_PARAMS_ARRAY).data()); + return SrpConverters.toBytesSet(client.zrevrangebyscore(key, max, min, null, params).data()); } catch (Exception ex) { throw convertSrpAccessException(ex); } } - public Set zRevRangeByScoreWithScores(byte[] key, double min, double max, long offset, long count) { - try { - Object[] limit = limitParams(offset, count); - if (isPipelined()) { - pipeline(new SrpResult(pipeline.zrevrangebyscore(key, max, min, WITHSCORES, limit), - SrpConverters.repliesToTupleSet())); - return null; - } - return SrpConverters.toTupleSet(client.zrevrangebyscore(key, max, min, WITHSCORES, limit).data()); - } catch (Exception ex) { - throw convertSrpAccessException(ex); - } + @Override + public Set zRevRangeByScoreWithScores(byte[] key, Range range) { + return zRevRangeByScoreWithScores(key, range, null); } - public Set zRevRangeByScoreWithScores(byte[] key, double min, double max) { + @Override + public Set zRevRangeByScoreWithScores(byte[] key, Range range, Limit limit) { + + Assert.notNull(range, "Range for ZRANGEBYSCOREWITHSCORES must not be null!"); + + byte[] min = SrpConverters.boundaryToBytesForZRange(range.getMin(), SrpConverters.toBytes("-inf")); + byte[] max = SrpConverters.boundaryToBytesForZRange(range.getMax(), SrpConverters.toBytes("+inf")); + + Object[] params = limit != null ? limitParams(limit.getOffset(), limit.getCount()) : EMPTY_PARAMS_ARRAY; + try { if (isPipelined()) { - pipeline(new SrpResult(pipeline.zrevrangebyscore(key, max, min, WITHSCORES, EMPTY_PARAMS_ARRAY), + pipeline(new SrpResult(pipeline.zrevrangebyscore(key, max, min, WITHSCORES, params), SrpConverters.repliesToTupleSet())); return null; } - return SrpConverters.toTupleSet(client.zrevrangebyscore(key, max, min, WITHSCORES, EMPTY_PARAMS_ARRAY).data()); + return SrpConverters.toTupleSet(client.zrevrangebyscore(key, max, min, WITHSCORES, params).data()); } catch (Exception ex) { throw convertSrpAccessException(ex); } @@ -1792,6 +1846,15 @@ public class SrpConnection extends AbstractRedisConnection { } public Long zRemRangeByScore(byte[] key, double min, double max) { + return zRemRangeByScore(key, new Range().gte(min).lte(max)); + } + + @Override + public Long zRemRangeByScore(byte[] key, Range range) { + + byte[] min = SrpConverters.boundaryToBytesForZRange(range.getMin(), SrpConverters.toBytes("-inf")); + byte[] max = SrpConverters.boundaryToBytesForZRange(range.getMax(), SrpConverters.toBytes("+inf")); + try { if (isPipelined()) { pipeline(new SrpResult(pipeline.zremrangebyscore(key, min, max))); @@ -2557,4 +2620,5 @@ public class SrpConnection extends AbstractRedisConnection { public Set zRangeByLex(byte[] key, Range range, Limit limit) { throw new UnsupportedOperationException("ZRANGEBYLEX is no supported for srp."); } + } diff --git a/src/main/java/org/springframework/data/redis/connection/srp/SrpConverters.java b/src/main/java/org/springframework/data/redis/connection/srp/SrpConverters.java index c036a8229..27314cefd 100644 --- a/src/main/java/org/springframework/data/redis/connection/srp/SrpConverters.java +++ b/src/main/java/org/springframework/data/redis/connection/srp/SrpConverters.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2014 the original author or authors. + * Copyright 2013-2015 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. @@ -16,6 +16,7 @@ package org.springframework.data.redis.connection.srp; import java.io.IOException; +import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashMap; @@ -32,6 +33,7 @@ import org.springframework.data.redis.RedisSystemException; import org.springframework.data.redis.connection.DefaultTuple; import org.springframework.data.redis.connection.RedisListCommands.Position; import org.springframework.data.redis.connection.RedisStringCommands.BitOperation; +import org.springframework.data.redis.connection.RedisZSetCommands.Range.Boundary; import org.springframework.data.redis.connection.RedisZSetCommands.Tuple; import org.springframework.data.redis.connection.convert.Converters; import org.springframework.data.redis.connection.convert.LongToBooleanConverter; @@ -413,4 +415,42 @@ abstract public class SrpConverters extends Converters { public static Converter exceptionConverter() { return EXCEPTION_CONVERTER; } + + /** + * Converts a given {@link Boundary} to its binary representation suitable for {@literal ZRANGEBY*} commands, despite + * {@literal ZRANGEBYLEX}. + * + * @param boundary + * @param defaultValue + * @return + * @since 1.6 + */ + public static byte[] boundaryToBytesForZRange(Boundary boundary, byte[] defaultValue) { + + if (boundary == null || boundary.getValue() == null) { + return defaultValue; + } + return boundaryToBytes(boundary, new byte[] {}, "(".getBytes(Charsets.UTF_8)); + } + + public static byte[] toBytes(String source) { + return source.getBytes(Charsets.UTF_8); + } + + private static byte[] boundaryToBytes(Boundary boundary, byte[] inclPrefix, byte[] exclPrefix) { + + byte[] prefix = boundary.isIncluding() ? inclPrefix : exclPrefix; + byte[] value = null; + if (boundary.getValue() instanceof byte[]) { + value = (byte[]) boundary.getValue(); + } else { + value = toBytes(boundary.getValue().toString()); + } + + ByteBuffer buffer = ByteBuffer.allocate(prefix.length + value.length); + buffer.put(prefix); + buffer.put(value); + return buffer.array(); + + } } diff --git a/src/test/java/org/springframework/data/redis/connection/RedisConnectionUnitTests.java b/src/test/java/org/springframework/data/redis/connection/RedisConnectionUnitTests.java index c03621571..a032f6ef8 100644 --- a/src/test/java/org/springframework/data/redis/connection/RedisConnectionUnitTests.java +++ b/src/test/java/org/springframework/data/redis/connection/RedisConnectionUnitTests.java @@ -831,5 +831,55 @@ public class RedisConnectionUnitTests { public Set zRangeByLex(byte[] key, Range range, Limit limit) { return delegate.zRangeByLex(key, range, limit); } + + @Override + public Set zRangeByScoreWithScores(byte[] key, Range range, Limit limit) { + return delegate.zRangeByScoreWithScores(key, range, limit); + } + + @Override + public Set zRevRangeByScore(byte[] key, Range range) { + return delegate.zRevRangeByScore(key, range); + } + + @Override + public Set zRevRangeByScore(byte[] key, Range range, Limit limit) { + return delegate.zRevRangeByScore(key, range, limit); + } + + @Override + public Set zRevRangeByScoreWithScores(byte[] key, Range range, Limit limit) { + return delegate.zRevRangeByScoreWithScores(key, range, limit); + } + + @Override + public Long zCount(byte[] key, Range range) { + return delegate.zCount(key, range); + } + + @Override + public Long zRemRangeByScore(byte[] key, Range range) { + return delegate.zRemRangeByScore(key, range); + } + + @Override + public Set zRangeByScore(byte[] key, Range range) { + return delegate.zRangeByScore(key, range); + } + + @Override + public Set zRangeByScore(byte[] key, Range range, Limit limit) { + return delegate.zRangeByScore(key, range, limit); + } + + @Override + public Set zRangeByScoreWithScores(byte[] key, Range range) { + return delegate.zRangeByScoreWithScores(key, range); + } + + @Override + public Set zRevRangeByScoreWithScores(byte[] key, Range range) { + return delegate.zRevRangeByScoreWithScores(key, range); + } } } diff --git a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConvertersUnitTests.java b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConvertersUnitTests.java index e13030394..4757185b1 100644 --- a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConvertersUnitTests.java +++ b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConvertersUnitTests.java @@ -187,6 +187,77 @@ public class JedisConvertersUnitTests { JedisConverters.boundaryToBytesForZRangeByLex(Range.range().gt(new Date()).getMin(), null); } + /** + * @see DATAREDIS-352 + */ + @Test + public void boundaryToBytesForZRangeByShouldReturnDefaultValueWhenBoundaryIsNull() { + + byte[] defaultValue = "tyrion".getBytes(); + + assertThat(JedisConverters.boundaryToBytesForZRange(null, defaultValue), is(defaultValue)); + } + + /** + * @see DATAREDIS-352 + */ + @Test + public void boundaryToBytesForZRangeByShouldReturnDefaultValueWhenBoundaryValueIsNull() { + + byte[] defaultValue = "tyrion".getBytes(); + + assertThat(JedisConverters.boundaryToBytesForZRange(Range.unbounded().getMax(), defaultValue), is(defaultValue)); + } + + /** + * @see DATAREDIS-352 + */ + @Test + public void boundaryToBytesForZRangeByShouldReturnValueCorrectlyWhenBoundaryIsIncluing() { + + assertThat( + JedisConverters.boundaryToBytesForZRange(Range.range().gte(JedisConverters.toBytes("a")).getMin(), null), + is(JedisConverters.toBytes("a"))); + } + + /** + * @see DATAREDIS-352 + */ + @Test + public void boundaryToBytesForZRangeByShouldReturnValueCorrectlyWhenBoundaryIsExcluding() { + + assertThat(JedisConverters.boundaryToBytesForZRange(Range.range().gt(JedisConverters.toBytes("a")).getMin(), null), + is(JedisConverters.toBytes("(a"))); + } + + /** + * @see DATAREDIS-352 + */ + @Test + public void boundaryToBytesForZRangeByShouldReturnValueCorrectlyWhenBoundaryIsAString() { + + assertThat(JedisConverters.boundaryToBytesForZRange(Range.range().gt("a").getMin(), null), + is(JedisConverters.toBytes("(a"))); + } + + /** + * @see DATAREDIS-352 + */ + @Test + public void boundaryToBytesForZRangeByShouldReturnValueCorrectlyWhenBoundaryIsANumber() { + + assertThat(JedisConverters.boundaryToBytesForZRange(Range.range().gt(1L).getMin(), null), + is(JedisConverters.toBytes("(1"))); + } + + /** + * @see DATAREDIS-352 + */ + @Test(expected = IllegalArgumentException.class) + public void boundaryToBytesForZRangeByShouldThrowExceptionWhenBoundaryHoldsUnknownType() { + JedisConverters.boundaryToBytesForZRange(Range.range().gt(new Date()).getMin(), null); + } + private void verifyRedisServerInfo(RedisServer server, Map values) { for (Map.Entry entry : values.entrySet()) {