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
This commit is contained in:
committed by
Thomas Darimont
parent
b916ff7549
commit
ff37da5197
@@ -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<byte[]> 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<byte[]> 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<byte[]> 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<String> 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<String> 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<String> zRangeByLex(String key, Range range, Limit limit) {
|
||||
|
||||
Set<byte[]> results = delegate.zRangeByLex(serialize(key), range);
|
||||
if (isFutureConversion()) {
|
||||
addResultConverter(byteSetToStringSet);
|
||||
}
|
||||
return byteSetToStringSet.convert(results);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
* <p>
|
||||
@@ -415,4 +573,36 @@ public interface RedisZSetCommands {
|
||||
* @return
|
||||
*/
|
||||
Set<byte[]> 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<byte[]> 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<byte[]> 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<byte[]> zRangeByLex(byte[] key, Range range, Limit limit);
|
||||
|
||||
}
|
||||
|
||||
@@ -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<String> 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<String> 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<String> zRangeByLex(String key, Range range, Limit limit);
|
||||
|
||||
}
|
||||
|
||||
@@ -2139,6 +2139,61 @@ public class JedisConnection extends AbstractRedisConnection {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByLex(byte[])
|
||||
*/
|
||||
public Set<byte[]> 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<byte[]> 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<byte[]> 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<byte[]> zRangeByScore(byte[] key, double min, double max) {
|
||||
try {
|
||||
if (isPipelined()) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<byte[]> 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<byte[]> 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<byte[]> zRangeByLex(byte[] key, Range range, Limit limit) {
|
||||
throw new UnsupportedOperationException("ZRANGEBYLEX is no supported for jredis.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<byte[]> 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<byte[]> 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<byte[]> zRangeByLex(byte[] key, Range range, Limit limit) {
|
||||
throw new UnsupportedOperationException("ZRANGEBYLEX is no supported for lettuce.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<byte[]> 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<byte[]> 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<byte[]> zRangeByLex(byte[] key, Range range, Limit limit) {
|
||||
throw new UnsupportedOperationException("ZRANGEBYLEX is no supported for srp.");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user