From ff37da51977f0d86b09e176ffa5785f5ab7533fc Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Wed, 8 Apr 2015 12:03:12 +0200 Subject: [PATCH] DATAREDIS-378 - Add support for ZRANGEBYLEX. We now support ZRANGEBYLEX on RedisConnection and StringRedisConnection when using the Jedis driver. The upper and lower bounds can be defined using the Range type which will be converted to the according binary representation including prefix and/or infinite operators. range().gt("a") => (a + range().gte("a") => [a + range().lt("z") => - (z range().lte("z") => - [z range().gte("a").lt("z") => [a (z --- .../DefaultStringRedisConnection.java | 61 +++++- .../redis/connection/RedisZSetCommands.java | 192 +++++++++++++++++- .../connection/StringRedisConnection.java | 34 +++- .../connection/jedis/JedisConnection.java | 55 +++++ .../connection/jedis/JedisConverters.java | 37 +++- .../connection/jredis/JredisConnection.java | 29 ++- .../connection/lettuce/LettuceConnection.java | 29 ++- .../redis/connection/srp/SrpConnection.java | 29 ++- .../connection/RedisConnectionUnitTests.java | 17 +- .../JedisConnectionIntegrationTests.java | 38 +++- .../jedis/JedisConvertersUnitTests.java | 77 ++++++- 11 files changed, 587 insertions(+), 11 deletions(-) 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 7c0219857..8abeaed3e 100644 --- a/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2014 the original author or authors. + * Copyright 2011-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. @@ -2494,4 +2494,63 @@ public class DefaultStringRedisConnection implements StringRedisConnection { this.pfMerge(serialize(destinationKey), serializeMulti(sourceKeys)); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByLex(byte[]) + */ + @Override + public Set zRangeByLex(byte[] key) { + return delegate.zRangeByLex(key); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByLex(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) + */ + @Override + public Set zRangeByLex(byte[] key, Range range) { + return delegate.zRangeByLex(key, range); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByLex(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) + */ + @Override + public Set zRangeByLex(byte[] key, Range range, Limit limit) { + return delegate.zRangeByLex(key, range, limit); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.StringRedisConnection#zRangeByLex(java.lang.String) + */ + @Override + public Set zRangeByLex(String key) { + return this.zRangeByLex(key, Range.unbounded()); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.StringRedisConnection#zRangeByLex(java.lang.String, org.springframework.data.redis.connection.RedisZSetCommands.Range) + */ + @Override + public Set zRangeByLex(String key, Range range) { + return this.zRangeByLex(key, range, null); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.StringRedisConnection#zRangeByLex(java.lang.String, org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) + */ + @Override + public Set zRangeByLex(String key, Range range, Limit limit) { + + Set results = delegate.zRangeByLex(serialize(key), range); + if (isFutureConversion()) { + addResultConverter(byteSetToStringSet); + } + return byteSetToStringSet.convert(results); + } + } 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 438632145..a55c39eab 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisZSetCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisZSetCommands.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2014 the original author or authors. + * Copyright 2011-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. @@ -19,6 +19,7 @@ import java.util.Set; import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.ScanOptions; +import org.springframework.util.Assert; /** * ZSet(SortedSet)-specific commands supported by Redis. @@ -47,6 +48,163 @@ public interface RedisZSetCommands { Double getScore(); } + /** + * {@link Range} defines {@literal min} and {@literal max} values to retrieve from a {@literal ZSET}. + * + * @author Christoph Strobl + * @since 1.6 + */ + public class Range { + + Boundary min; + Boundary max; + + /** + * @return new {@link Range} + */ + public static Range range() { + return new Range(); + } + + /** + * @return new {@link Range} with {@literal min} and {@literal max} set to {@link Boundary#infinite()}. + */ + public static Range unbounded() { + + Range range = new Range(); + range.min = Boundary.infinite(); + range.max = Boundary.infinite(); + return range; + } + + /** + * Greater Than Equals + * + * @param min + * @return + */ + public Range gte(Object min) { + + Assert.notNull(min, "Min already set for range."); + this.min = new Boundary(min, true); + return this; + } + + /** + * Greater Than + * + * @param min + * @return + */ + public Range gt(Object min) { + + Assert.notNull(min, "Min already set for range."); + this.min = new Boundary(min, false); + return this; + } + + /** + * Less Then Equals + * + * @param max + * @return + */ + public Range lte(Object max) { + + Assert.notNull(max, "Max already set for range."); + this.max = new Boundary(max, true); + return this; + } + + /** + * Less Than + * + * @param max + * @return + */ + public Range lt(Object max) { + + Assert.notNull(max, "Max already set for range."); + this.max = new Boundary(max, false); + return this; + } + + /** + * @return {@literal null} if not set. + */ + public Boundary getMin() { + return min; + } + + /** + * @return {@literal null} if not set. + */ + public Boundary getMax() { + return max; + } + + /** + * @author Christoph Strobl + * @since 1.6 + */ + public static class Boundary { + + Object value; + boolean including; + + static Boundary infinite() { + return new Boundary(null, true); + } + + Boundary(Object value, boolean including) { + this.value = value; + this.including = including; + } + + public Object getValue() { + return value; + } + + public boolean isIncluding() { + return including; + } + } + + } + + /** + * @author Christoph Strobl + * @since 1.6 + */ + public class Limit { + + int offset; + int count; + + public static Limit limit() { + return new Limit(); + } + + public Limit offset(int offset) { + this.offset = offset; + return this; + } + + public Limit count(int count) { + this.count = count; + return this; + } + + public int getCount() { + return count; + } + + public int getOffset() { + return offset; + } + + } + /** * Add {@code value} to a sorted set at {@code key}, or update its {@code score} if it already exists. *

@@ -415,4 +573,36 @@ public interface RedisZSetCommands { * @return */ Set zRangeByScore(byte[] key, String min, String max, long offset, long count); + + /** + * Get all the elements in the sorted set at {@literal key} in lexicographical ordering. + * + * @param key must not be {@literal null}. + * @return + * @since 1.6 + */ + Set zRangeByLex(byte[] key); + + /** + * Get all the elements in {@link Range} from the sorted set at {@literal key} in lexicographical ordering. + * + * @param key must not be {@literal null}. + * @param range must not be {@literal null}. + * @return + * @since 1.6 + */ + Set zRangeByLex(byte[] key, Range range); + + /** + * Get all the elements in {@link Range} from the sorted set at {@literal key} in lexicographical ordering. Result is + * limited via {@link Limit}. + * + * @param key must not be {@literal null}. + * @param range must not be {@literal null}. + * @param range can be {@literal null}. + * @return + * @since 1.6 + */ + Set zRangeByLex(byte[] key, Range range, Limit limit); + } 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 ad3ebf2e8..c3c5b6548 100644 --- a/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2014 the original author or authors. + * Copyright 2011-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. @@ -392,4 +392,36 @@ public interface StringRedisConnection extends RedisConnection { * @since 1.5 */ void pfMerge(String destinationKey, String... sourceKeys); + + /** + * Get all elements in the sorted set at {@literal key} in lexicographical ordering. + * + * @param key must not be {@literal null}. + * @return + * @since 1.6 + */ + Set zRangeByLex(String key); + + /** + * Get the elements in {@link Range} from the sorted set at {@literal key} in lexicographical ordering + * + * @param key must not be {@literal null}. + * @param range must not be {@literal null}. + * @return + * @since 1.6 + */ + Set zRangeByLex(String key, Range range); + + /** + * Get the elements in {@link Range} from the sorted set at {@literal key} in lexicographical ordering. Result is + * limited via {@link Limit}. + * + * @param key must not be {@literal null}. + * @param range must not be {@literal null}. + * @param range can be {@literal null}. + * @return + * @since 1.6 + */ + Set zRangeByLex(String key, Range range, Limit limit); + } 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 f3fa64d6d..0ee2cb8a5 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 @@ -2139,6 +2139,61 @@ public class JedisConnection extends AbstractRedisConnection { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByLex(byte[]) + */ + public Set zRangeByLex(byte[] key) { + return zRangeByLex(key, Range.unbounded()); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByLex(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) + */ + public Set zRangeByLex(byte[] key, Range range) { + return zRangeByLex(key, range, null); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByLex(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) + */ + public Set zRangeByLex(byte[] key, Range range, Limit limit) { + + 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("+")); + + try { + if (isPipelined()) { + if (limit != null) { + pipeline(new JedisResult(pipeline.zrangeByLex(key, min, max, limit.getOffset(), limit.getCount()))); + } else { + pipeline(new JedisResult(pipeline.zrangeByLex(key, min, max))); + } + return null; + } + + if (isQueueing()) { + if (limit != null) { + transaction(new JedisResult(transaction.zrangeByLex(key, min, max, limit.getOffset(), limit.getCount()))); + } else { + transaction(new JedisResult(transaction.zrangeByLex(key, min, max))); + } + return null; + } + + if (limit != null) { + return jedis.zrangeByLex(key, min, max, limit.getOffset(), limit.getCount()); + } + return jedis.zrangeByLex(key, min, max); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + public Set zRangeByScore(byte[] key, double min, double max) { try { if (isPipelined()) { 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 c779d0168..6a3587a4a 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 @@ -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. @@ -15,6 +15,7 @@ */ package org.springframework.data.redis.connection.jedis; +import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -28,6 +29,7 @@ import org.springframework.data.redis.connection.DefaultTuple; import org.springframework.data.redis.connection.RedisListCommands.Position; import org.springframework.data.redis.connection.RedisServer; 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.SortParameters; import org.springframework.data.redis.connection.SortParameters.Order; @@ -249,4 +251,37 @@ abstract public class JedisConverters extends Converters { throw new IllegalArgumentException(); } } + + /** + * Converts a given {@link Boundary} to its binary representation suitable for ZRANGEBYLEX command. + * + * @param boundary + * @return + * @since 1.6 + */ + public static byte[] boundaryToBytesForZRangeByLex(Boundary boundary, byte[] defaultValue) { + + if (boundary == null || boundary.getValue() == null) { + return defaultValue; + } + + byte[] prefix = boundary.isIncluding() ? toBytes("[") : toBytes("("); + byte[] value = null; + if (boundary.getValue() instanceof byte[]) { + value = (byte[]) boundary.getValue(); + } else if (boundary.getValue() instanceof Long) { + value = toBytes((Long) boundary.getValue()); + } else if (boundary.getValue() instanceof Integer) { + value = toBytes((Integer) boundary.getValue()); + } else if (boundary.getValue() instanceof String) { + value = toBytes((String) boundary.getValue()); + } else { + throw new IllegalArgumentException(String.format("Cannot convert %s to binary format", boundary.getValue())); + } + + ByteBuffer buffer = ByteBuffer.allocate(prefix.length + value.length); + 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 cca0a97c5..a0cb7a1a6 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 @@ -1,5 +1,5 @@ /* - * Copyright 2011-2014 the original author or authors. + * Copyright 2011-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. @@ -1319,4 +1319,31 @@ public class JredisConnection extends AbstractRedisConnection { public void pfMerge(byte[] destinationKey, byte[]... sourceKeys) { throw new UnsupportedOperationException(); } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByLex(byte[]) + */ + @Override + public Set zRangeByLex(byte[] key) { + throw new UnsupportedOperationException("ZRANGEBYLEX is no supported for jredis."); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByLex(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) + */ + @Override + public Set zRangeByLex(byte[] key, Range range) { + throw new UnsupportedOperationException("ZRANGEBYLEX is no supported for jredis."); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByLex(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) + */ + @Override + public Set zRangeByLex(byte[] key, Range range, Limit limit) { + throw new UnsupportedOperationException("ZRANGEBYLEX is no supported for jredis."); + } } 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 08fefdad8..4f22d3826 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 @@ -1,5 +1,5 @@ /* - * Copyright 2011-2014 the original author or authors. + * Copyright 2011-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. @@ -3683,4 +3683,31 @@ public class LettuceConnection extends AbstractRedisConnection { throw new UnsupportedOperationException(); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByLex(byte[]) + */ + @Override + public Set zRangeByLex(byte[] key) { + throw new UnsupportedOperationException("ZRANGEBYLEX is no supported for lettuce."); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByLex(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) + */ + @Override + public Set zRangeByLex(byte[] key, Range range) { + throw new UnsupportedOperationException("ZRANGEBYLEX is no supported for lettuce."); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByLex(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) + */ + @Override + public Set zRangeByLex(byte[] key, Range range, Limit limit) { + throw new UnsupportedOperationException("ZRANGEBYLEX is no supported for lettuce."); + } + } 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 bdd4470e7..2c1de63f3 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 @@ -1,5 +1,5 @@ /* - * Copyright 2011-2014 the original author or authors. + * Copyright 2011-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. @@ -2530,4 +2530,31 @@ public class SrpConnection extends AbstractRedisConnection { public void pfMerge(byte[] destinationKey, byte[]... sourceKeys) { throw new UnsupportedOperationException(); } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByLex(byte[]) + */ + @Override + public Set zRangeByLex(byte[] key) { + throw new UnsupportedOperationException("ZRANGEBYLEX is no supported for srp."); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByLex(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) + */ + @Override + public Set zRangeByLex(byte[] key, Range range) { + throw new UnsupportedOperationException("ZRANGEBYLEX is no supported for srp."); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByLex(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) + */ + @Override + public Set zRangeByLex(byte[] key, Range range, Limit limit) { + throw new UnsupportedOperationException("ZRANGEBYLEX is no supported for srp."); + } } 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 bb89db8ea..c03621571 100644 --- a/src/test/java/org/springframework/data/redis/connection/RedisConnectionUnitTests.java +++ b/src/test/java/org/springframework/data/redis/connection/RedisConnectionUnitTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 the original author or authors. + * Copyright 2014-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. @@ -816,5 +816,20 @@ public class RedisConnectionUnitTests { public void pfMerge(byte[] destinationKey, byte[]... sourceKeys) { delegate.pfMerge(destinationKey, sourceKeys); } + + @Override + public Set zRangeByLex(byte[] key) { + return delegate.zRangeByLex(key); + } + + @Override + public Set zRangeByLex(byte[] key, Range range) { + return delegate.zRangeByLex(key, range); + } + + @Override + public Set zRangeByLex(byte[] key, Range range, Limit limit) { + return delegate.zRangeByLex(key, range, limit); + } } } diff --git a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionIntegrationTests.java index 729e65739..d6fc4986d 100644 --- a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionIntegrationTests.java @@ -43,6 +43,7 @@ import org.springframework.data.redis.connection.Message; import org.springframework.data.redis.connection.MessageListener; import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.connection.RedisSentinelConfiguration; +import org.springframework.data.redis.connection.RedisZSetCommands.Range; import org.springframework.data.redis.connection.ReturnType; import org.springframework.data.redis.connection.StringRedisConnection.StringTuple; import org.springframework.data.redis.test.util.RedisSentinelRule; @@ -411,9 +412,42 @@ public class JedisConnectionIntegrationTests extends AbstractConnectionIntegrati connection.zAdd("myzset", 1, "one"); connection.zAdd("myzset", 2, "two"); connection.zAdd("myzset", 3, "three"); - + Set zRangeByScore = connection.zRangeByScore("myzset", "(1", "2"); - + assertEquals("two", new String(zRangeByScore.iterator().next())); } + + /** + * @see DATAREDIS-378 + */ + @Test + @IfProfileValue(name = "redisVersion", value = "2.8+") + public void zRangeByLexTest() { + + connection.zAdd("myzset", 0, "a"); + connection.zAdd("myzset", 0, "b"); + connection.zAdd("myzset", 0, "c"); + connection.zAdd("myzset", 0, "d"); + connection.zAdd("myzset", 0, "e"); + connection.zAdd("myzset", 0, "f"); + connection.zAdd("myzset", 0, "g"); + + Set values = connection.zRangeByLex("myzset", Range.range().lte("c")); + + assertThat(values, hasItems("a", "b", "c")); + assertThat(values, not(hasItems("d", "e", "f", "g"))); + + values = connection.zRangeByLex("myzset", Range.range().lt("c")); + assertThat(values, hasItems("a", "b")); + assertThat(values, not(hasItem("c"))); + + values = connection.zRangeByLex("myzset", Range.range().gte("aaa").lt("g")); + assertThat(values, hasItems("b", "c", "d", "e", "f")); + assertThat(values, not(hasItems("a", "g"))); + + values = connection.zRangeByLex("myzset", Range.range().gte("e")); + assertThat(values, hasItems("e", "f", "g")); + assertThat(values, not(hasItems("a", "b", "c", "d"))); + } } 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 5f9780ad6..e13030394 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 @@ -1,5 +1,5 @@ /* - * Copyright 2014 the original author or authors. + * Copyright 2014-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. @@ -22,12 +22,14 @@ import static org.junit.Assert.*; import java.util.Arrays; import java.util.Collections; +import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import org.junit.Test; import org.springframework.data.redis.connection.RedisServer; +import org.springframework.data.redis.connection.RedisZSetCommands.Range; import org.springframework.data.redis.core.types.RedisClientInfo; /** @@ -112,6 +114,79 @@ public class JedisConvertersUnitTests { assertThat(JedisConverters.toListOfRedisServer(null), notNullValue()); } + /** + * @see DATAREDIS-378 + */ + @Test + public void boundaryToBytesForZRangeByLexShouldReturnDefaultValueWhenBoundaryIsNull() { + + byte[] defaultValue = "tyrion".getBytes(); + + assertThat(JedisConverters.boundaryToBytesForZRangeByLex(null, defaultValue), is(defaultValue)); + } + + /** + * @see DATAREDIS-378 + */ + @Test + public void boundaryToBytesForZRangeByLexShouldReturnDefaultValueWhenBoundaryValueIsNull() { + + byte[] defaultValue = "tyrion".getBytes(); + + assertThat(JedisConverters.boundaryToBytesForZRangeByLex(Range.unbounded().getMax(), defaultValue), + is(defaultValue)); + } + + /** + * @see DATAREDIS-378 + */ + @Test + public void boundaryToBytesForZRangeByLexShouldReturnValueCorrectlyWhenBoundaryIsIncluing() { + + assertThat( + JedisConverters.boundaryToBytesForZRangeByLex(Range.range().gte(JedisConverters.toBytes("a")).getMin(), null), + is(JedisConverters.toBytes("[a"))); + } + + /** + * @see DATAREDIS-378 + */ + @Test + public void boundaryToBytesForZRangeByLexShouldReturnValueCorrectlyWhenBoundaryIsExcluding() { + + assertThat( + JedisConverters.boundaryToBytesForZRangeByLex(Range.range().gt(JedisConverters.toBytes("a")).getMin(), null), + is(JedisConverters.toBytes("(a"))); + } + + /** + * @see DATAREDIS-378 + */ + @Test + public void boundaryToBytesForZRangeByLexShouldReturnValueCorrectlyWhenBoundaryIsAString() { + + assertThat(JedisConverters.boundaryToBytesForZRangeByLex(Range.range().gt("a").getMin(), null), + is(JedisConverters.toBytes("(a"))); + } + + /** + * @see DATAREDIS-378 + */ + @Test + public void boundaryToBytesForZRangeByLexShouldReturnValueCorrectlyWhenBoundaryIsANumber() { + + assertThat(JedisConverters.boundaryToBytesForZRangeByLex(Range.range().gt(1L).getMin(), null), + is(JedisConverters.toBytes("(1"))); + } + + /** + * @see DATAREDIS-378 + */ + @Test(expected = IllegalArgumentException.class) + public void boundaryToBytesForZRangeByLexShouldThrowExceptionWhenBoundaryHoldsUnknownType() { + JedisConverters.boundaryToBytesForZRangeByLex(Range.range().gt(new Date()).getMin(), null); + } + private void verifyRedisServerInfo(RedisServer server, Map values) { for (Map.Entry entry : values.entrySet()) {