DATAKV-36
add current sort-and-get draft
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2011 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.keyvalue.redis.core;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Wrapper class allowing for stream-like access across a list of values.
|
||||
*
|
||||
* @author Costin Leau
|
||||
*/
|
||||
class BulkIterable<T> implements Iterable<T> {
|
||||
|
||||
private final List<T> list;
|
||||
private volatile int index = 0;
|
||||
|
||||
public BulkIterable(List<T> list) {
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
public boolean hasMore() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
return new Iterator<T>() {
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return index < list.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
return list.get(index++);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2011 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.keyvalue.redis.core;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* Mapper translating Redis bulk value responses (typically returned by a sort query) to actual objects. Implementations of this interface do not have to worry
|
||||
* about exception or connection handling.
|
||||
* <p/>
|
||||
* Typically used by {@link RedisTemplate} <tt>sortAndGet</tt> methods.
|
||||
*
|
||||
* @author Costin Leau
|
||||
*/
|
||||
public interface BulkMapper<T> {
|
||||
|
||||
T mapBulk(Iterator<byte[]> valueStream);
|
||||
}
|
||||
@@ -32,10 +32,12 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.data.keyvalue.redis.connection.DataType;
|
||||
import org.springframework.data.keyvalue.redis.connection.DefaultSortParameters;
|
||||
import org.springframework.data.keyvalue.redis.connection.RedisConnection;
|
||||
import org.springframework.data.keyvalue.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.keyvalue.redis.connection.SortParameters;
|
||||
import org.springframework.data.keyvalue.redis.connection.RedisListCommands.Position;
|
||||
import org.springframework.data.keyvalue.redis.core.query.SortQuery;
|
||||
import org.springframework.data.keyvalue.redis.serializer.JdkSerializationRedisSerializer;
|
||||
import org.springframework.data.keyvalue.redis.serializer.RedisSerializer;
|
||||
import org.springframework.data.keyvalue.redis.serializer.StringRedisSerializer;
|
||||
@@ -145,7 +147,7 @@ public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperation
|
||||
* @return object returned by the action
|
||||
*/
|
||||
public <T> T execute(RedisCallback<T> action, boolean exposeConnection) {
|
||||
return execute(action, exposeConnection, valueSerializer);
|
||||
return execute(action, exposeConnection, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -158,35 +160,6 @@ public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperation
|
||||
* @return object returned by the action
|
||||
*/
|
||||
public <T> T execute(RedisCallback<T> action, boolean exposeConnection, boolean pipeline) {
|
||||
return execute(action, exposeConnection, pipeline, valueSerializer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the given action object within a connection, which can be exposed or not. Allows a custom serializer
|
||||
* to be specified for the returned object.
|
||||
*
|
||||
* @param <T> return type
|
||||
* @param action action callback object that specifies the Redis action
|
||||
* @param exposeConnection whether to enforce exposure of the native Redis Connection to callback code
|
||||
* @param returnSerializer serializer used for converting the binary data to the custom return type
|
||||
* @return returned by the action
|
||||
*/
|
||||
public <T> T execute(RedisCallback<T> action, boolean exposeConnection, RedisSerializer<?> returnSerializer) {
|
||||
return execute(action, exposeConnection, false, returnSerializer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the given action object within a connection, which can be exposed or not. Allows a custom serializer
|
||||
* to be specified for the returned object.
|
||||
*
|
||||
* @param <T> return type
|
||||
* @param action action callback object that specifies the Redis action
|
||||
* @param exposeConnection whether to enforce exposure of the native Redis Connection to callback code
|
||||
* @param pipeline whether to pipeline or not the connection for the execution duration
|
||||
* @param returnSerializer serializer used for converting the binary data to the custom return type
|
||||
* @return returned by the action
|
||||
*/
|
||||
public <T> T execute(RedisCallback<T> action, boolean exposeConnection, boolean pipeline, RedisSerializer<?> returnSerializer) {
|
||||
Assert.notNull(action, "Callback object must not be null");
|
||||
|
||||
RedisConnectionFactory factory = getConnectionFactory();
|
||||
@@ -203,7 +176,7 @@ public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperation
|
||||
try {
|
||||
RedisConnection connToExpose = (exposeConnection ? conn : createRedisConnectionProxy(conn));
|
||||
T result = action.doInRedis(connToExpose);
|
||||
// TODO: should do flush?
|
||||
// TODO: any other connection processing?
|
||||
return postProcessResult(result, conn, existingConnection);
|
||||
} finally {
|
||||
try {
|
||||
@@ -450,11 +423,15 @@ public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperation
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T extends Collection<V>> T deserializeValues(Collection<byte[]> rawValues, Class<? extends Collection> type) {
|
||||
Collection<V> values = (List.class.isAssignableFrom(type) ? new ArrayList<V>(rawValues.size())
|
||||
: new LinkedHashSet<V>(rawValues.size()));
|
||||
return deserializeValues(rawValues, type, valueSerializer);
|
||||
}
|
||||
|
||||
private <X, T extends Collection<X>> T deserializeValues(Collection<byte[]> rawValues, Class<? extends Collection> type, RedisSerializer<?> redisSerializer) {
|
||||
Collection<X> values = (List.class.isAssignableFrom(type) ? new ArrayList<X>(rawValues.size())
|
||||
: new LinkedHashSet<X>(rawValues.size()));
|
||||
for (byte[] bs : rawValues) {
|
||||
if (bs != null) {
|
||||
values.add((V) valueSerializer.deserialize(bs));
|
||||
values.add((X) redisSerializer.deserialize(bs));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1975,4 +1952,96 @@ public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperation
|
||||
return deserializeHashMap(entries);
|
||||
}
|
||||
}
|
||||
|
||||
// Sort operations
|
||||
public List<V> sort(SortQuery<K> query) {
|
||||
return sort(query, null);
|
||||
}
|
||||
|
||||
public List<V> sort(SortQuery<K> query, String getKeyPattern) {
|
||||
return sort(query, getKeyPattern, valueSerializer);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> List<T> sort(SortQuery<K> query, String getKeyPattern, RedisSerializer<T> resultSerializer) {
|
||||
final byte[] rawKey = rawKey(query.getKey());
|
||||
final SortParameters params = convertQuery(query,
|
||||
(getKeyPattern != null ? Collections.singletonList(getKeyPattern) : null), stringSerializer);
|
||||
|
||||
List<byte[]> vals = execute(new RedisCallback<List<byte[]>>() {
|
||||
@Override
|
||||
public List<byte[]> doInRedis(RedisConnection connection) throws DataAccessException {
|
||||
return connection.sort(rawKey, params);
|
||||
}
|
||||
}, true);
|
||||
|
||||
return (List<T>) deserializeValues(vals, List.class, resultSerializer);
|
||||
}
|
||||
|
||||
public <T> List<T> sort(SortQuery<K> query, List<String> getKeyPattern, BulkMapper<T> bulkMapper) {
|
||||
final byte[] rawKey = rawKey(query.getKey());
|
||||
final SortParameters params = convertQuery(query, getKeyPattern, stringSerializer);
|
||||
|
||||
List<byte[]> vals = execute(new RedisCallback<List<byte[]>>() {
|
||||
@Override
|
||||
public List<byte[]> doInRedis(RedisConnection connection) throws DataAccessException {
|
||||
return connection.sort(rawKey, params);
|
||||
}
|
||||
}, true);
|
||||
|
||||
int bulkSize = getKeyPattern.size();
|
||||
List<T> result = new ArrayList<T>(vals.size() / bulkSize + 1);
|
||||
|
||||
final List<byte[]> bulk = new ArrayList<byte[]>(bulkSize);
|
||||
final List<byte[]> listView = Collections.unmodifiableList(bulk);
|
||||
|
||||
for (byte[] bs : vals) {
|
||||
bulk.add(bs);
|
||||
if (bulk.size() == bulkSize) {
|
||||
bulkMapper.mapBulk(listView.iterator());
|
||||
bulk.clear();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void sortAndStore(SortQuery<K> query, K storeKey) {
|
||||
sortAndStore(query, null, storeKey);
|
||||
}
|
||||
|
||||
public void sortAndStore(SortQuery<K> query, List<String> getKeyPattern, K storeKey) {
|
||||
final byte[] rawStoreKey = rawKey(storeKey);
|
||||
final byte[] rawKey = rawKey(query.getKey());
|
||||
final SortParameters params = convertQuery(query, getKeyPattern, stringSerializer);
|
||||
|
||||
execute(new RedisCallback<Object>() {
|
||||
@Override
|
||||
public Object doInRedis(RedisConnection connection) throws DataAccessException {
|
||||
connection.sort(rawKey, params, rawStoreKey);
|
||||
return null;
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
|
||||
private static <K> SortParameters convertQuery(SortQuery<K> query, List<String> getKeyPattern, RedisSerializer<String> stringSerializer) {
|
||||
|
||||
return new DefaultSortParameters(stringSerializer.serialize(query.getBy()), query.getLimit(), serialize(
|
||||
getKeyPattern, stringSerializer), query.getOrder(), query.isAlphabetic());
|
||||
}
|
||||
|
||||
private static byte[][] serialize(List<String> strings, RedisSerializer<String> stringSerializer) {
|
||||
List<byte[]> raw = null;
|
||||
|
||||
if (strings == null) {
|
||||
raw = Collections.emptyList();
|
||||
}
|
||||
else {
|
||||
raw = new ArrayList<byte[]>(strings.size());
|
||||
for (String key : strings) {
|
||||
raw.add(stringSerializer.serialize(key));
|
||||
}
|
||||
}
|
||||
return raw.toArray(new byte[raw.size()][]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2011 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.keyvalue.redis.core.query;
|
||||
|
||||
import org.springframework.data.keyvalue.redis.connection.SortParameters.Order;
|
||||
import org.springframework.data.keyvalue.redis.connection.SortParameters.Range;
|
||||
|
||||
/**
|
||||
* @author Costin Leau
|
||||
*/
|
||||
class DefaultSortCriterion<K> implements SortCriterion<K> {
|
||||
|
||||
private final K key;
|
||||
private String by;
|
||||
|
||||
private Range limit;
|
||||
private Order order;
|
||||
private Boolean alpha;
|
||||
|
||||
DefaultSortCriterion(K key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortCriterion<K> alphabetical(boolean alpha) {
|
||||
this.alpha = Boolean.valueOf(alpha);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortQuery<K> build() {
|
||||
return new DefaultSortQuery<K>(key, by, limit, order, alpha);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortCriterion<K> limit(long offset, long count) {
|
||||
this.limit = new Range(offset, count);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortCriterion<K> limit(Range range) {
|
||||
this.limit = range;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortCriterion<K> order(Order order) {
|
||||
this.order = order;
|
||||
return this;
|
||||
}
|
||||
|
||||
SortCriterion<K> addBy(String keyPattern) {
|
||||
this.by = keyPattern;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2011 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.keyvalue.redis.core.query;
|
||||
|
||||
import org.springframework.data.keyvalue.redis.connection.SortParameters.Order;
|
||||
import org.springframework.data.keyvalue.redis.connection.SortParameters.Range;
|
||||
|
||||
/**
|
||||
* Default SortQuery implementation.
|
||||
*
|
||||
* @author Costin Leau
|
||||
*/
|
||||
class DefaultSortQuery<K> implements SortQuery<K> {
|
||||
|
||||
private final K key;
|
||||
private final Boolean alpha;
|
||||
private final Order order;
|
||||
private final Range limit;
|
||||
private final String by;
|
||||
|
||||
DefaultSortQuery(K key, String by, Range limit, Order order, Boolean alpha) {
|
||||
this.key = key;
|
||||
this.by = by;
|
||||
this.limit = limit;
|
||||
this.order = order;
|
||||
this.alpha = alpha;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBy() {
|
||||
return by;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Range getLimit() {
|
||||
return limit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Order getOrder() {
|
||||
return order;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isAlphabetic() {
|
||||
return alpha;
|
||||
}
|
||||
|
||||
@Override
|
||||
public K getKey() {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2011 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.keyvalue.redis.core.query;
|
||||
|
||||
import org.springframework.data.keyvalue.redis.connection.SortParameters.Order;
|
||||
import org.springframework.data.keyvalue.redis.connection.SortParameters.Range;
|
||||
|
||||
/**
|
||||
* @author Costin Leau
|
||||
*/
|
||||
public interface SortCriterion<K> {
|
||||
|
||||
SortCriterion<K> limit(long offset, long count);
|
||||
|
||||
SortCriterion<K> limit(Range range);
|
||||
|
||||
SortCriterion<K> order(Order order);
|
||||
|
||||
SortCriterion<K> alphabetical(boolean alpha);
|
||||
|
||||
SortQuery<K> build();
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2011 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.keyvalue.redis.core.query;
|
||||
|
||||
import org.springframework.data.keyvalue.redis.connection.SortParameters.Order;
|
||||
import org.springframework.data.keyvalue.redis.connection.SortParameters.Range;
|
||||
|
||||
/**
|
||||
* @author Costin Leau
|
||||
*/
|
||||
public interface SortQuery<K> {
|
||||
|
||||
/**
|
||||
* Returns the sorting order. Can be null if nothing is specified.
|
||||
*
|
||||
* @return sorting order
|
||||
*/
|
||||
Order getOrder();
|
||||
|
||||
/**
|
||||
* Indicates if the sorting is numeric (default) or alphabetical (lexicographical).
|
||||
* Can be null if nothing is specified.
|
||||
*
|
||||
* @return the type of sorting
|
||||
*/
|
||||
Boolean isAlphabetic();
|
||||
|
||||
|
||||
/**
|
||||
* Returns the sorting limit (range or pagination).
|
||||
* Can be null if nothing is specified.
|
||||
*
|
||||
* @return sorting limit/range
|
||||
*/
|
||||
Range getLimit();
|
||||
|
||||
/**
|
||||
* Target key for sorting.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
K getKey();
|
||||
|
||||
/**
|
||||
* Pattern of external key used for sorting.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String getBy();
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2011 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.keyvalue.redis.core.query;
|
||||
|
||||
|
||||
/**
|
||||
* Builder class for constructing {@link SortQuery}.
|
||||
*
|
||||
* @author Costin Leau
|
||||
*/
|
||||
public class SortQueryBuilder<K> extends DefaultSortCriterion<K> {
|
||||
|
||||
private static final String NO_SORT_KEY = "~";
|
||||
|
||||
private SortQueryBuilder(K key) {
|
||||
super(key);
|
||||
}
|
||||
|
||||
public static <K> SortQueryBuilder<K> sort(K key) {
|
||||
return new SortQueryBuilder<K>(key);
|
||||
}
|
||||
|
||||
public SortCriterion<K> by(String keyPattern) {
|
||||
return addBy(keyPattern);
|
||||
}
|
||||
|
||||
public SortCriterion<K> noSort() {
|
||||
return by(NO_SORT_KEY);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user