/*
* Copyright 2011-2016 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.redis.support.collections;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Set;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.redis.connection.DataType;
import org.springframework.data.redis.connection.RedisZSetCommands.Limit;
import org.springframework.data.redis.connection.RedisZSetCommands.Range;
import org.springframework.data.redis.core.BoundZSetOperations;
import org.springframework.data.redis.core.ConvertingCursor;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.ZSetOperations.TypedTuple;
/**
* Default implementation for {@link RedisZSet}. Note that the collection support works only with normal,
* non-pipeline/multi-exec connections as it requires a reply to be sent right away.
*
* @author Costin Leau
* @author Christoph Strobl
* @author Mark Paluch
*/
public class DefaultRedisZSet<E> extends AbstractRedisCollection<E> implements RedisZSet<E> {
private final BoundZSetOperations<String, E> boundZSetOps;
private double defaultScore = 1;
private class DefaultRedisSortedSetIterator extends RedisIterator<E> {
public DefaultRedisSortedSetIterator(Iterator<E> delegate) {
super(delegate);
}
protected void removeFromRedisStorage(E item) {
DefaultRedisZSet.this.remove(item);
}
}
/**
* Constructs a new <code>DefaultRedisZSet</code> instance with a default score of '1'.
*
* @param key
* @param operations
*/
public DefaultRedisZSet(String key, RedisOperations<String, E> operations) {
this(key, operations, 1);
}
/**
* Constructs a new <code>DefaultRedisSortedSet</code> instance.
*
* @param key
* @param operations
* @param defaultScore
*/
public DefaultRedisZSet(String key, RedisOperations<String, E> operations, double defaultScore) {
super(key, operations);
boundZSetOps = operations.boundZSetOps(key);
this.defaultScore = defaultScore;
}
/**
* Constructs a new <code>DefaultRedisZSet</code> instance with a default score of '1'.
*
* @param boundOps
*/
public DefaultRedisZSet(BoundZSetOperations<String, E> boundOps) {
this(boundOps, 1);
}
/**
* Constructs a new <code>DefaultRedisZSet</code> instance.
*
* @param boundOps
* @param defaultScore
*/
public DefaultRedisZSet(BoundZSetOperations<String, E> boundOps, double defaultScore) {
super(boundOps.getKey(), boundOps.getOperations());
this.boundZSetOps = boundOps;
this.defaultScore = defaultScore;
}
public RedisZSet<E> intersectAndStore(RedisZSet<?> set, String destKey) {
boundZSetOps.intersectAndStore(set.getKey(), destKey);
return new DefaultRedisZSet<E>(boundZSetOps.getOperations().boundZSetOps(destKey), getDefaultScore());
}
public RedisZSet<E> intersectAndStore(Collection<? extends RedisZSet<?>> sets, String destKey) {
boundZSetOps.intersectAndStore(CollectionUtils.extractKeys(sets), destKey);
return new DefaultRedisZSet<E>(boundZSetOps.getOperations().boundZSetOps(destKey), getDefaultScore());
}
public Set<E> range(long start, long end) {
return boundZSetOps.range(start, end);
}
public Set<E> reverseRange(long start, long end) {
return boundZSetOps.reverseRange(start, end);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.support.collections.RedisZSet#rangeByLex(org.springframework.data.redis.connection.RedisZSetCommands.Range)
*/
@Override
public Set<E> rangeByLex(Range range) {
return boundZSetOps.rangeByLex(range);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.support.collections.RedisZSet#rangeByLex(org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit)
*/
@Override
public Set<E> rangeByLex(Range range, Limit limit) {
return boundZSetOps.rangeByLex(range, limit);
}
public Set<E> rangeByScore(double min, double max) {
return boundZSetOps.rangeByScore(min, max);
}
public Set<E> reverseRangeByScore(double min, double max) {
return boundZSetOps.reverseRangeByScore(min, max);
}
public Set<TypedTuple<E>> rangeByScoreWithScores(double min, double max) {
return boundZSetOps.rangeByScoreWithScores(min, max);
}
public Set<TypedTuple<E>> rangeWithScores(long start, long end) {
return boundZSetOps.rangeWithScores(start, end);
}
public Set<TypedTuple<E>> reverseRangeByScoreWithScores(double min, double max) {
return boundZSetOps.reverseRangeByScoreWithScores(min, max);
}
public Set<TypedTuple<E>> reverseRangeWithScores(long start, long end) {
return boundZSetOps.reverseRangeWithScores(start, end);
}
public RedisZSet<E> remove(long start, long end) {
boundZSetOps.removeRange(start, end);
return this;
}
public RedisZSet<E> removeByScore(double min, double max) {
boundZSetOps.removeRangeByScore(min, max);
return this;
}
public RedisZSet<E> unionAndStore(RedisZSet<?> set, String destKey) {
boundZSetOps.unionAndStore(set.getKey(), destKey);
return new DefaultRedisZSet<E>(boundZSetOps.getOperations().boundZSetOps(destKey), getDefaultScore());
}
public RedisZSet<E> unionAndStore(Collection<? extends RedisZSet<?>> sets, String destKey) {
boundZSetOps.unionAndStore(CollectionUtils.extractKeys(sets), destKey);
return new DefaultRedisZSet<E>(boundZSetOps.getOperations().boundZSetOps(destKey), getDefaultScore());
}
public boolean add(E e) {
Boolean result = add(e, getDefaultScore());
checkResult(result);
return result;
}
public boolean add(E e, double score) {
Boolean result = boundZSetOps.add(e, score);
checkResult(result);
return result;
}
public void clear() {
boundZSetOps.removeRange(0, -1);
}
public boolean contains(Object o) {
return (boundZSetOps.rank(o) != null);
}
public Iterator<E> iterator() {
Set<E> members = boundZSetOps.range(0, -1);
checkResult(members);
return new DefaultRedisSortedSetIterator(members.iterator());
}
public boolean remove(Object o) {
Long result = boundZSetOps.remove(o);
checkResult(result);
return result == 1;
}
public int size() {
Long result = boundZSetOps.size();
checkResult(result);
return result.intValue();
}
public Double getDefaultScore() {
return defaultScore;
}
public E first() {
Set<E> members = boundZSetOps.range(0, 0);
checkResult(members);
Iterator<E> iterator = members.iterator();
if (iterator.hasNext())
return iterator.next();
throw new NoSuchElementException();
}
public E last() {
Set<E> members = boundZSetOps.reverseRange(0, 0);
checkResult(members);
Iterator<E> iterator = members.iterator();
if (iterator.hasNext())
return iterator.next();
throw new NoSuchElementException();
}
public Long rank(Object o) {
return boundZSetOps.rank(o);
}
public Long reverseRank(Object o) {
return boundZSetOps.reverseRank(o);
}
public Double score(Object o) {
return boundZSetOps.score(o);
}
public DataType getType() {
return DataType.ZSET;
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.support.collections.RedisZSet#scan()
*/
@Override
public Cursor<E> scan() {
return new ConvertingCursor<TypedTuple<E>, E>(scan(ScanOptions.NONE), new Converter<TypedTuple<E>, E>() {
@Override
public E convert(TypedTuple<E> source) {
return source.getValue();
}
});
}
/**
* @since 1.4
* @param options
* @return
*/
public Cursor<TypedTuple<E>> scan(ScanOptions options) {
return boundZSetOps.scan(options);
}
}