DATAREDIS-316 - Add EX/PX, NX/XX options to SET command.
We now support EX/PX and NX/XX arguments along with the SET command for both xetorthio/jedis and mp911de/lettuce. Jedis 2.8 does not support all combinations of EX/PX and NX/XX. To work around those limitations we delegate to the according set methods to execute related commands or fail fast if there is no way for delegation. Original pull request: #170.
This commit is contained in:
committed by
Mark Paluch
parent
68da4a4ee5
commit
0c6c127b5e
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2015 the original author or authors.
|
||||
* 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.
|
||||
@@ -36,6 +36,7 @@ import org.springframework.data.redis.connection.convert.SetConverter;
|
||||
import org.springframework.data.redis.core.ConvertingCursor;
|
||||
import org.springframework.data.redis.core.Cursor;
|
||||
import org.springframework.data.redis.core.ScanOptions;
|
||||
import org.springframework.data.redis.core.types.Expiration;
|
||||
import org.springframework.data.redis.core.types.RedisClientInfo;
|
||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
@@ -730,6 +731,15 @@ public class DefaultStringRedisConnection implements StringRedisConnection {
|
||||
delegate.set(key, value);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.redis.connection.RedisStringCommands#set(byte[], byte[], org.springframework.data.redis.core.types.Expiration, org.springframework.data.redis.connection.RedisStringCommands.SetOptions)
|
||||
*/
|
||||
@Override
|
||||
public void set(byte[] key, byte[] value, Expiration expiration, SetOption option) {
|
||||
delegate.set(key, value, expiration, option);
|
||||
}
|
||||
|
||||
public Boolean setBit(byte[] key, long offset, boolean value) {
|
||||
return delegate.setBit(key, offset, value);
|
||||
}
|
||||
@@ -1860,6 +1870,14 @@ public class DefaultStringRedisConnection implements StringRedisConnection {
|
||||
delegate.set(serialize(key), serialize(value));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.redis.connection.StringRedisConnection#set(java.lang.String, java.lang.String, org.springframework.data.redis.core.types.Expiration, org.springframework.data.redis.connection.RedisStringCommands.SetOptions)
|
||||
*/
|
||||
public void set(String key, String value, Expiration expiration, SetOption option) {
|
||||
set(serialize(key), serialize(value), expiration, option);
|
||||
}
|
||||
|
||||
public Boolean setBit(String key, long offset, boolean value) {
|
||||
return delegate.setBit(serialize(key), offset, value);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2014 the original author or authors.
|
||||
* 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.
|
||||
@@ -18,6 +18,8 @@ package org.springframework.data.redis.connection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.data.redis.core.types.Expiration;
|
||||
|
||||
/**
|
||||
* String/Value-specific commands supported by Redis.
|
||||
*
|
||||
@@ -71,6 +73,18 @@ public interface RedisStringCommands {
|
||||
*/
|
||||
void set(byte[] key, byte[] value);
|
||||
|
||||
/**
|
||||
* Set {@code value} for {@code key} applying timeouts from {@code expiration} if set and inserting/updating values
|
||||
* depending on {@code options}.
|
||||
*
|
||||
* @param key must not be {@literal null}.
|
||||
* @param value must not be {@literal null}.
|
||||
* @param expiration can be {@literal null}. Defaulted to {@link Expiration#persistent()}.
|
||||
* @param option can be {@literal null}. Defaulted to {@link SetOption#UPSERT}.
|
||||
* @since 1.7
|
||||
*/
|
||||
void set(byte[] key, byte[] value, Expiration expiration, SetOption option);
|
||||
|
||||
/**
|
||||
* Set {@code value} for {@code key}, only if {@code key} does not exist.
|
||||
* <p>
|
||||
@@ -278,4 +292,61 @@ public interface RedisStringCommands {
|
||||
* @return
|
||||
*/
|
||||
Long strLen(byte[] key);
|
||||
|
||||
/**
|
||||
* {@code SET} command arguments for {@code NX}, {@code XX}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
public static enum SetOption {
|
||||
|
||||
/**
|
||||
* Do not set any additional command argument.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
UPSERT,
|
||||
|
||||
/**
|
||||
* {@code NX}
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
SET_IF_ABSENT,
|
||||
|
||||
/**
|
||||
* {@code XX}
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
SET_IF_PRESENT;
|
||||
|
||||
/**
|
||||
* Do not set any additional command argument.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static SetOption upsert() {
|
||||
return UPSERT;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code XX}
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static SetOption ifPresent() {
|
||||
return SET_IF_PRESENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code NX}
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static SetOption ifAbsent() {
|
||||
return SET_IF_ABSENT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.springframework.data.redis.core.Cursor;
|
||||
import org.springframework.data.redis.core.RedisCallback;
|
||||
import org.springframework.data.redis.core.ScanOptions;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.data.redis.core.types.Expiration;
|
||||
import org.springframework.data.redis.core.types.RedisClientInfo;
|
||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||
|
||||
@@ -95,6 +96,18 @@ public interface StringRedisConnection extends RedisConnection {
|
||||
|
||||
void set(String key, String value);
|
||||
|
||||
/**
|
||||
* Set {@code value} for {@code key} applying timeouts from {@code expiration} if set and inserting/updating values
|
||||
* depending on {@code options}.
|
||||
*
|
||||
* @param key must not be {@literal null}.
|
||||
* @param value must not be {@literal null}.
|
||||
* @param expiration can be {@literal null}. Defaulted to {@link Expiration#persistent()}.
|
||||
* @param option can be {@literal null}. Defaulted to {@link SetOption#UPSERT}.
|
||||
* @since 1.7
|
||||
*/
|
||||
void set(String key, String value, Expiration expiration, SetOption option);
|
||||
|
||||
Boolean setNX(String key, String value);
|
||||
|
||||
void setEx(String key, long seconds, String value);
|
||||
|
||||
@@ -28,6 +28,7 @@ import java.util.Map.Entry;
|
||||
import java.util.Properties;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.beans.DirectFieldAccessor;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
@@ -61,10 +62,11 @@ import org.springframework.data.redis.core.Cursor;
|
||||
import org.springframework.data.redis.core.ScanCursor;
|
||||
import org.springframework.data.redis.core.ScanIteration;
|
||||
import org.springframework.data.redis.core.ScanOptions;
|
||||
import org.springframework.data.redis.core.types.Expiration;
|
||||
import org.springframework.data.redis.core.types.RedisClientInfo;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import redis.clients.jedis.BinaryJedisPubSub;
|
||||
import redis.clients.jedis.Jedis;
|
||||
@@ -249,7 +251,8 @@ public class JedisClusterConnection implements RedisClusterConnection {
|
||||
@Override
|
||||
public byte[] randomKey() {
|
||||
|
||||
List<RedisClusterNode> nodes = new ArrayList<RedisClusterNode>(topologyProvider.getTopology().getActiveMasterNodes());
|
||||
List<RedisClusterNode> nodes = new ArrayList<RedisClusterNode>(topologyProvider.getTopology()
|
||||
.getActiveMasterNodes());
|
||||
Set<RedisNode> inspectedNodes = new HashSet<RedisNode>(nodes.size());
|
||||
|
||||
do {
|
||||
@@ -594,6 +597,49 @@ public class JedisClusterConnection implements RedisClusterConnection {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.redis.connection.RedisStringCommands#set(byte[], byte[], org.springframework.data.redis.core.types.Expiration, org.springframework.data.redis.connection.RedisStringCommands.SetOptions)
|
||||
*/
|
||||
@Override
|
||||
public void set(byte[] key, byte[] value, Expiration expiration, SetOption option) {
|
||||
|
||||
if (expiration == null || expiration.isPersitent()) {
|
||||
|
||||
if (option == null || ObjectUtils.nullSafeEquals(SetOption.UPSERT, option)) {
|
||||
set(key, value);
|
||||
} else {
|
||||
|
||||
// BinaryCluster does not support set with nxxx and binary key/value pairs.
|
||||
if (ObjectUtils.nullSafeEquals(SetOption.SET_IF_PRESENT, option)) {
|
||||
throw new UnsupportedOperationException("Jedis does not support SET XX without PX or EX on BinaryCluster.");
|
||||
}
|
||||
|
||||
setNX(key, value);
|
||||
}
|
||||
} else {
|
||||
|
||||
if (option == null || ObjectUtils.nullSafeEquals(SetOption.UPSERT, option)) {
|
||||
|
||||
if (ObjectUtils.nullSafeEquals(TimeUnit.MILLISECONDS, expiration.getTimeUnit())) {
|
||||
pSetEx(key, expiration.getExpirationTime(), value);
|
||||
} else {
|
||||
setEx(key, expiration.getExpirationTime(), value);
|
||||
}
|
||||
} else {
|
||||
|
||||
byte[] nxxx = JedisConverters.toSetCommandNxXxArgument(option);
|
||||
byte[] expx = JedisConverters.toSetCommandExPxArgument(expiration);
|
||||
|
||||
try {
|
||||
cluster.set(key, value, nxxx, expx, expiration.getExpirationTime());
|
||||
} catch (Exception ex) {
|
||||
throw convertJedisAccessException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.redis.connection.RedisStringCommands#setNX(byte[], byte[])
|
||||
@@ -3432,7 +3478,8 @@ public class JedisClusterConnection implements RedisClusterConnection {
|
||||
@Override
|
||||
public void clusterForget(final RedisClusterNode node) {
|
||||
|
||||
Set<RedisClusterNode> nodes = new LinkedHashSet<RedisClusterNode>(topologyProvider.getTopology().getActiveMasterNodes());
|
||||
Set<RedisClusterNode> nodes = new LinkedHashSet<RedisClusterNode>(topologyProvider.getTopology()
|
||||
.getActiveMasterNodes());
|
||||
final RedisClusterNode nodeToRemove = topologyProvider.getTopology().lookup(node);
|
||||
nodes.remove(nodeToRemove);
|
||||
|
||||
@@ -3536,8 +3583,7 @@ public class JedisClusterConnection implements RedisClusterConnection {
|
||||
|
||||
Assert.notNull(master, "Master cannot be null!");
|
||||
|
||||
final RedisClusterNode nodeToUse = topologyProvider.getTopology()
|
||||
.lookup(master);
|
||||
final RedisClusterNode nodeToUse = topologyProvider.getTopology().lookup(master);
|
||||
|
||||
return JedisConverters.toSetOfRedisClusterNodes(clusterCommandExecutor.executeCommandOnSingleNode(
|
||||
new JedisClusterCommandCallback<List<String>>() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2015 the original author or authors.
|
||||
* 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.
|
||||
@@ -54,6 +54,7 @@ import org.springframework.data.redis.core.KeyBoundCursor;
|
||||
import org.springframework.data.redis.core.ScanCursor;
|
||||
import org.springframework.data.redis.core.ScanIteration;
|
||||
import org.springframework.data.redis.core.ScanOptions;
|
||||
import org.springframework.data.redis.core.types.Expiration;
|
||||
import org.springframework.data.redis.core.types.RedisClientInfo;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
@@ -1139,6 +1140,87 @@ public class JedisConnection extends AbstractRedisConnection {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.redis.connection.RedisStringCommands#set(byte[], byte[], org.springframework.data.redis.core.types.Expiration, org.springframework.data.redis.connection.RedisStringCommands.SetOption)
|
||||
*/
|
||||
@Override
|
||||
public void set(byte[] key, byte[] value, Expiration expiration, SetOption option) {
|
||||
|
||||
if (expiration == null || expiration.isPersitent()) {
|
||||
|
||||
if (option == null || ObjectUtils.nullSafeEquals(SetOption.UPSERT, option)) {
|
||||
set(key, value);
|
||||
} else {
|
||||
|
||||
try {
|
||||
|
||||
byte[] nxxx = JedisConverters.toSetCommandNxXxArgument(option);
|
||||
|
||||
if (isPipelined()) {
|
||||
|
||||
pipeline(new JedisStatusResult(pipeline.set(key, value, nxxx)));
|
||||
return;
|
||||
}
|
||||
if (isQueueing()) {
|
||||
|
||||
transaction(new JedisStatusResult(transaction.set(key, value, nxxx)));
|
||||
return;
|
||||
}
|
||||
|
||||
jedis.set(key, value, nxxx);
|
||||
} catch (Exception ex) {
|
||||
throw convertJedisAccessException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (option == null || ObjectUtils.nullSafeEquals(SetOption.UPSERT, option)) {
|
||||
|
||||
if (ObjectUtils.nullSafeEquals(TimeUnit.MILLISECONDS, expiration.getTimeUnit())) {
|
||||
pSetEx(key, expiration.getExpirationTime(), value);
|
||||
} else {
|
||||
setEx(key, expiration.getExpirationTime(), value);
|
||||
}
|
||||
} else {
|
||||
|
||||
byte[] nxxx = JedisConverters.toSetCommandNxXxArgument(option);
|
||||
byte[] expx = JedisConverters.toSetCommandExPxArgument(expiration);
|
||||
|
||||
try {
|
||||
if (isPipelined()) {
|
||||
|
||||
if (expiration.getExpirationTime() > Integer.MAX_VALUE) {
|
||||
|
||||
throw new IllegalArgumentException(
|
||||
"Expiration.exprirationTime must be less than equals Integer.MAX_VALUE for pipeline in Jedis.");
|
||||
}
|
||||
|
||||
pipeline(new JedisStatusResult(pipeline.set(key, value, nxxx, expx, (int) expiration.getExpirationTime())));
|
||||
return;
|
||||
}
|
||||
if (isQueueing()) {
|
||||
|
||||
if (expiration.getExpirationTime() > Integer.MAX_VALUE) {
|
||||
throw new IllegalArgumentException(
|
||||
"Expiration.exprirationTime must be less than equals Integer.MAX_VALUE for transactions in Jedis.");
|
||||
}
|
||||
|
||||
transaction(new JedisStatusResult(transaction.set(key, value, nxxx, expx,
|
||||
(int) expiration.getExpirationTime())));
|
||||
return;
|
||||
}
|
||||
|
||||
jedis.set(key, value, nxxx, expx, expiration.getExpirationTime());
|
||||
|
||||
} catch (Exception ex) {
|
||||
throw convertJedisAccessException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] getSet(byte[] key, byte[] value) {
|
||||
try {
|
||||
if (isPipelined()) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2015 the original author or authors.
|
||||
* Copyright 2013-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.
|
||||
@@ -17,11 +17,11 @@ package org.springframework.data.redis.connection.jedis;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
@@ -29,7 +29,9 @@ import org.springframework.data.redis.connection.DefaultTuple;
|
||||
import org.springframework.data.redis.connection.RedisClusterNode;
|
||||
import org.springframework.data.redis.connection.RedisListCommands.Position;
|
||||
import org.springframework.data.redis.connection.RedisServer;
|
||||
import org.springframework.data.redis.connection.RedisStringCommands;
|
||||
import org.springframework.data.redis.connection.RedisStringCommands.BitOperation;
|
||||
import org.springframework.data.redis.connection.RedisStringCommands.SetOption;
|
||||
import org.springframework.data.redis.connection.RedisZSetCommands.Range.Boundary;
|
||||
import org.springframework.data.redis.connection.RedisZSetCommands.Tuple;
|
||||
import org.springframework.data.redis.connection.SortParameters;
|
||||
@@ -40,9 +42,11 @@ import org.springframework.data.redis.connection.convert.ListConverter;
|
||||
import org.springframework.data.redis.connection.convert.MapConverter;
|
||||
import org.springframework.data.redis.connection.convert.SetConverter;
|
||||
import org.springframework.data.redis.connection.convert.StringToRedisClientInfoConverter;
|
||||
import org.springframework.data.redis.core.types.Expiration;
|
||||
import org.springframework.data.redis.core.types.RedisClientInfo;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import redis.clients.jedis.BinaryClient.LIST_POSITION;
|
||||
@@ -71,11 +75,17 @@ abstract public class JedisConverters extends Converters {
|
||||
private static final Converter<redis.clients.jedis.Tuple, Tuple> TUPLE_CONVERTER;
|
||||
private static final ListConverter<redis.clients.jedis.Tuple, Tuple> TUPLE_LIST_TO_TUPLE_LIST_CONVERTER;
|
||||
private static final Converter<Object, RedisClusterNode> OBJECT_TO_CLUSTER_NODE_CONVERTER;
|
||||
private static final Converter<Expiration, byte[]> EXPIRATION_TO_COMMAND_OPTION_CONVERTER;
|
||||
private static final Converter<SetOption, byte[]> SET_OPTION_TO_COMMAND_OPTION_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;
|
||||
private static final byte[] EX;
|
||||
private static final byte[] PX;
|
||||
private static final byte[] NX;
|
||||
private static final byte[] XX;
|
||||
|
||||
static {
|
||||
|
||||
@@ -113,6 +123,46 @@ abstract public class JedisConverters extends Converters {
|
||||
((Number) nodeInfo.get(1)).intValue(), range);
|
||||
}
|
||||
};
|
||||
|
||||
EX = toBytes("EX");
|
||||
PX = toBytes("PX");
|
||||
EXPIRATION_TO_COMMAND_OPTION_CONVERTER = new Converter<Expiration, byte[]>() {
|
||||
|
||||
@Override
|
||||
public byte[] convert(Expiration source) {
|
||||
|
||||
if (source == null || source.isPersitent()) {
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
if (ObjectUtils.nullSafeEquals(TimeUnit.MILLISECONDS, source.getTimeUnit())) {
|
||||
return PX;
|
||||
}
|
||||
|
||||
return EX;
|
||||
}
|
||||
};
|
||||
|
||||
NX = toBytes("NX");
|
||||
XX = toBytes("XX");
|
||||
SET_OPTION_TO_COMMAND_OPTION_CONVERTER = new Converter<RedisStringCommands.SetOption, byte[]>() {
|
||||
|
||||
@Override
|
||||
public byte[] convert(SetOption source) {
|
||||
|
||||
switch (source) {
|
||||
case UPSERT:
|
||||
return new byte[0];
|
||||
case SET_IF_ABSENT:
|
||||
return NX;
|
||||
case SET_IF_PRESENT:
|
||||
return XX;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(String.format("Invalid argument %s for SetOption.", source));
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
public static Converter<String, byte[]> stringToBytes() {
|
||||
@@ -322,6 +372,42 @@ abstract public class JedisConverters extends Converters {
|
||||
return boundaryToBytes(boundary, toBytes("["), toBytes("("));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a given {@link Expiration} to the according {@code SET} command argument.<br />
|
||||
* <dl>
|
||||
* <dt>{@link TimeUnit#SECONDS}</dt>
|
||||
* <dd>{@code EX}</dd>
|
||||
* <dt>{@link TimeUnit#MILLISECONDS}</dt>
|
||||
* <dd>{@code PX}</dd>
|
||||
* </dl>
|
||||
*
|
||||
* @param expiration
|
||||
* @return
|
||||
* @since 1.7
|
||||
*/
|
||||
public static byte[] toSetCommandExPxArgument(Expiration expiration) {
|
||||
return EXPIRATION_TO_COMMAND_OPTION_CONVERTER.convert(expiration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a given {@link SetOption} to the according {@code SET} command argument.<br />
|
||||
* <dl>
|
||||
* <dt>{@link SetOption#UPSERT}</dt>
|
||||
* <dd>{@code byte[0]}</dd>
|
||||
* <dt>{@link SetOption#SET_IF_ABSENT}</dt>
|
||||
* <dd>{@code NX}</dd>
|
||||
* <dt>{@link SetOption#SET_IF_PRESENT}</dt>
|
||||
* <dd>{@code XX}</dd>
|
||||
* </dl>
|
||||
*
|
||||
* @param option
|
||||
* @return
|
||||
* @since 1.7
|
||||
*/
|
||||
public static byte[] toSetCommandNxXxArgument(SetOption option) {
|
||||
return SET_OPTION_TO_COMMAND_OPTION_CONVERTER.convert(option);
|
||||
}
|
||||
|
||||
private static byte[] boundaryToBytes(Boundary boundary, byte[] inclPrefix, byte[] exclPrefix) {
|
||||
|
||||
byte[] prefix = boundary.isIncluding() ? inclPrefix : exclPrefix;
|
||||
|
||||
@@ -47,6 +47,7 @@ import org.springframework.data.redis.connection.SortParameters;
|
||||
import org.springframework.data.redis.connection.Subscription;
|
||||
import org.springframework.data.redis.core.Cursor;
|
||||
import org.springframework.data.redis.core.ScanOptions;
|
||||
import org.springframework.data.redis.core.types.Expiration;
|
||||
import org.springframework.data.redis.core.types.RedisClientInfo;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
@@ -470,6 +471,16 @@ public class JredisConnection extends AbstractRedisConnection {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.redis.connection.RedisStringCommands#set(byte[], byte[], org.springframework.data.redis.core.types.Expiration, org.springframework.data.redis.connection.RedisStringCommands.SetOption)
|
||||
*/
|
||||
@Override
|
||||
public void set(byte[] key, byte[] value, Expiration expiration, SetOption option) {
|
||||
throw new UnsupportedOperationException(
|
||||
"SET with options is not supported for JRedis. Please use SETNX, SETEX, PSETEX.");
|
||||
}
|
||||
|
||||
public byte[] getSet(byte[] key, byte[] value) {
|
||||
try {
|
||||
return jredis.getset(key, value);
|
||||
|
||||
@@ -62,6 +62,7 @@ import org.springframework.data.redis.core.RedisCommand;
|
||||
import org.springframework.data.redis.core.ScanCursor;
|
||||
import org.springframework.data.redis.core.ScanIteration;
|
||||
import org.springframework.data.redis.core.ScanOptions;
|
||||
import org.springframework.data.redis.core.types.Expiration;
|
||||
import org.springframework.data.redis.core.types.RedisClientInfo;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
@@ -1218,6 +1219,30 @@ public class LettuceConnection extends AbstractRedisConnection {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.redis.connection.RedisStringCommands#set(byte[], byte[], org.springframework.data.redis.core.types.Expiration, org.springframework.data.redis.connection.RedisStringCommands.SetOption)
|
||||
*/
|
||||
@Override
|
||||
public void set(byte[] key, byte[] value, Expiration expiration, SetOption option) {
|
||||
|
||||
try {
|
||||
if (isPipelined()) {
|
||||
pipeline(new LettuceStatusResult(getAsyncConnection().set(key, value,
|
||||
LettuceConverters.toSetArgs(expiration, option))));
|
||||
return;
|
||||
}
|
||||
if (isQueueing()) {
|
||||
transaction(new LettuceTxStatusResult(getConnection().set(key, value,
|
||||
LettuceConverters.toSetArgs(expiration, option))));
|
||||
return;
|
||||
}
|
||||
getConnection().set(key, value, LettuceConverters.toSetArgs(expiration, option));
|
||||
} catch (Exception ex) {
|
||||
throw convertLettuceAccessException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] getSet(byte[] key, byte[] value) {
|
||||
try {
|
||||
if (isPipelined()) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2015 the original author or authors.
|
||||
* Copyright 2013-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.
|
||||
@@ -26,6 +26,7 @@ import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
@@ -39,6 +40,7 @@ import org.springframework.data.redis.connection.RedisNode;
|
||||
import org.springframework.data.redis.connection.RedisNode.NodeType;
|
||||
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
|
||||
import org.springframework.data.redis.connection.RedisServer;
|
||||
import org.springframework.data.redis.connection.RedisStringCommands.SetOption;
|
||||
import org.springframework.data.redis.connection.RedisZSetCommands.Range.Boundary;
|
||||
import org.springframework.data.redis.connection.RedisZSetCommands.Tuple;
|
||||
import org.springframework.data.redis.connection.ReturnType;
|
||||
@@ -47,6 +49,7 @@ import org.springframework.data.redis.connection.SortParameters.Order;
|
||||
import org.springframework.data.redis.connection.convert.Converters;
|
||||
import org.springframework.data.redis.connection.convert.LongToBooleanConverter;
|
||||
import org.springframework.data.redis.connection.convert.StringToRedisClientInfoConverter;
|
||||
import org.springframework.data.redis.core.types.Expiration;
|
||||
import org.springframework.data.redis.core.types.RedisClientInfo;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
@@ -60,6 +63,7 @@ import com.lambdaworks.redis.SortArgs;
|
||||
import com.lambdaworks.redis.cluster.models.partitions.Partitions;
|
||||
import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode.NodeFlag;
|
||||
import com.lambdaworks.redis.protocol.LettuceCharsets;
|
||||
import com.lambdaworks.redis.protocol.SetArgs;
|
||||
|
||||
/**
|
||||
* Lettuce type converters
|
||||
@@ -614,4 +618,43 @@ abstract public class LettuceConverters extends Converters {
|
||||
return CLUSTER_NODE_TO_CLUSTER_NODE_CONVERTER.convert(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a given {@link Expiration} and {@link SetOption} to the according {@link SetArgs}.<br />
|
||||
*
|
||||
* @param expiration can be {@literal null}.
|
||||
* @param option can be {@literal null}.
|
||||
* @since 1.7
|
||||
*/
|
||||
public static SetArgs toSetArgs(Expiration expiration, SetOption option) {
|
||||
|
||||
SetArgs args = new SetArgs();
|
||||
if (expiration != null && !expiration.isPersitent()) {
|
||||
|
||||
switch (expiration.getTimeUnit()) {
|
||||
case SECONDS:
|
||||
args.ex(expiration.getExpirationTime());
|
||||
break;
|
||||
default:
|
||||
args.px(expiration.getConverted(TimeUnit.MILLISECONDS));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (option != null) {
|
||||
|
||||
switch (option) {
|
||||
case SET_IF_ABSENT:
|
||||
args.nx();
|
||||
break;
|
||||
case SET_IF_PRESENT:
|
||||
args.xx();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ import org.springframework.data.redis.connection.SortParameters;
|
||||
import org.springframework.data.redis.connection.Subscription;
|
||||
import org.springframework.data.redis.core.Cursor;
|
||||
import org.springframework.data.redis.core.ScanOptions;
|
||||
import org.springframework.data.redis.core.types.Expiration;
|
||||
import org.springframework.data.redis.core.types.RedisClientInfo;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -875,6 +876,16 @@ public class SrpConnection extends AbstractRedisConnection {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.redis.connection.RedisStringCommands#set(byte[], byte[], org.springframework.data.redis.core.types.Expiration, org.springframework.data.redis.connection.RedisStringCommands.SetOption)
|
||||
*/
|
||||
@Override
|
||||
public void set(byte[] key, byte[] value, Expiration expiration, SetOption option) {
|
||||
throw new UnsupportedOperationException(
|
||||
"SET with options is not supported for Srp. Please use SETNX, SETEX, PSETEX.");
|
||||
}
|
||||
|
||||
public byte[] getSet(byte[] key, byte[] value) {
|
||||
try {
|
||||
if (isPipelined()) {
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright 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.core.types;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Expiration holds a value with its associated {@link TimeUnit}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
public class Expiration {
|
||||
|
||||
private long expirationTime;
|
||||
private TimeUnit timeUnit;
|
||||
|
||||
/**
|
||||
* Creates new {@link Expiration}.
|
||||
*
|
||||
* @param expirationTime can be {@literal null}. Defaulted to {@link TimeUnit#SECONDS}
|
||||
* @param timeUnit
|
||||
*/
|
||||
protected Expiration(long expirationTime, TimeUnit timeUnit) {
|
||||
|
||||
this.expirationTime = expirationTime;
|
||||
this.timeUnit = timeUnit != null ? timeUnit : TimeUnit.SECONDS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the expiration time converted into {@link TimeUnit#MILLISECONDS}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public long getExpirationTimeInMilliseconds() {
|
||||
return getConverted(TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the expiration time converted into {@link TimeUnit#SECONDS}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public long getExpirationTimeInSeconds() {
|
||||
return getConverted(TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the expiration time.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public long getExpirationTime() {
|
||||
return expirationTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the time unit for the expiration time.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public TimeUnit getTimeUnit() {
|
||||
return this.timeUnit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the expiration time converted into the desired {@code targetTimeUnit}.
|
||||
*
|
||||
* @param targetTimeUnit must not {@literal null}.
|
||||
* @return
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
public long getConverted(TimeUnit targetTimeUnit) {
|
||||
|
||||
Assert.notNull(targetTimeUnit, "TargetTimeUnit must not be null!");
|
||||
return targetTimeUnit.convert(expirationTime, timeUnit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Expiration} with {@link TimeUnit#SECONDS}.
|
||||
*
|
||||
* @param expirationTime
|
||||
* @return
|
||||
*/
|
||||
public static Expiration seconds(long expirationTime) {
|
||||
return new Expiration(expirationTime, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Expiration} with {@link TimeUnit#MILLISECONDS}.
|
||||
*
|
||||
* @param expirationTime
|
||||
* @return
|
||||
*/
|
||||
public static Expiration milliseconds(long expirationTime) {
|
||||
return new Expiration(expirationTime, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new persistent {@link Expiration}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static Expiration persistent() {
|
||||
return new Expiration(-1, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@literal true} if {@link Expiration} is set to persistent.
|
||||
*/
|
||||
public boolean isPersitent() {
|
||||
return expirationTime == -1;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2015 the original author or authors.
|
||||
* 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.
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.data.redis.connection;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.hamcrest.number.IsCloseTo.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assume.*;
|
||||
import static org.springframework.data.redis.SpinBarrier.*;
|
||||
@@ -52,6 +53,7 @@ import org.springframework.data.redis.RedisVersionUtils;
|
||||
import org.springframework.data.redis.TestCondition;
|
||||
import org.springframework.data.redis.connection.RedisListCommands.Position;
|
||||
import org.springframework.data.redis.connection.RedisStringCommands.BitOperation;
|
||||
import org.springframework.data.redis.connection.RedisStringCommands.SetOption;
|
||||
import org.springframework.data.redis.connection.RedisZSetCommands.Aggregate;
|
||||
import org.springframework.data.redis.connection.RedisZSetCommands.Range;
|
||||
import org.springframework.data.redis.connection.RedisZSetCommands.Tuple;
|
||||
@@ -60,6 +62,7 @@ import org.springframework.data.redis.connection.StringRedisConnection.StringTup
|
||||
import org.springframework.data.redis.core.Cursor;
|
||||
import org.springframework.data.redis.core.ScanOptions;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.data.redis.core.types.Expiration;
|
||||
import org.springframework.data.redis.core.types.RedisClientInfo;
|
||||
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
|
||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||
@@ -2220,6 +2223,282 @@ public abstract class AbstractConnectionIntegrationTests {
|
||||
assertThat(values, not(hasItems("a", "b", "c", "d")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
@WithRedisDriver({ RedisDriver.JEDIS, RedisDriver.LETTUCE })
|
||||
public void setWithExpirationAndNullOpionShouldSetTtlWhenKeyDoesNotExist() {
|
||||
|
||||
String key = "exp-" + UUID.randomUUID();
|
||||
connection.set(key, "foo", Expiration.milliseconds(500), null);
|
||||
|
||||
actual.add(connection.exists(key));
|
||||
actual.add(connection.pTtl(key));
|
||||
|
||||
List<Object> result = getResults();
|
||||
assertThat((Boolean) result.get(0), is(Boolean.TRUE));
|
||||
assertThat(((Long) result.get(1)).doubleValue(), is(closeTo(500d, 499d)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
@WithRedisDriver({ RedisDriver.JEDIS, RedisDriver.LETTUCE })
|
||||
public void setWithExpirationAndUpsertOpionShouldSetTtlWhenKeyDoesNotExist() {
|
||||
|
||||
String key = "exp-" + UUID.randomUUID();
|
||||
connection.set(key, "foo", Expiration.milliseconds(500), SetOption.upsert());
|
||||
|
||||
actual.add(connection.exists(key));
|
||||
actual.add(connection.pTtl(key));
|
||||
|
||||
List<Object> result = getResults();
|
||||
assertThat((Boolean) result.get(0), is(Boolean.TRUE));
|
||||
assertThat(((Long) result.get(1)).doubleValue(), is(closeTo(500d, 499d)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
@WithRedisDriver({ RedisDriver.JEDIS, RedisDriver.LETTUCE })
|
||||
public void setWithExpirationAndUpsertOpionShouldSetTtlWhenKeyDoesExist() {
|
||||
|
||||
String key = "exp-" + UUID.randomUUID();
|
||||
connection.set(key, "spring");
|
||||
connection.set(key, "data", Expiration.milliseconds(500), SetOption.upsert());
|
||||
|
||||
actual.add(connection.exists(key));
|
||||
actual.add(connection.pTtl(key));
|
||||
actual.add(connection.get(key));
|
||||
|
||||
List<Object> result = getResults();
|
||||
assertThat((Boolean) result.get(0), is(Boolean.TRUE));
|
||||
assertThat(((Long) result.get(1)).doubleValue(), is(closeTo(500d, 499d)));
|
||||
assertThat(((String) result.get(2)), is(equalTo("data")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
@WithRedisDriver({ RedisDriver.JEDIS, RedisDriver.LETTUCE })
|
||||
public void setWithExpirationAndAbsentOptionShouldSetTtlWhenKeyDoesExist() {
|
||||
|
||||
String key = "exp-" + UUID.randomUUID();
|
||||
connection.set(key, "spring");
|
||||
connection.set(key, "data", Expiration.milliseconds(500), SetOption.ifAbsent());
|
||||
|
||||
actual.add(connection.exists(key));
|
||||
actual.add(connection.pTtl(key));
|
||||
actual.add(connection.get(key));
|
||||
|
||||
List<Object> result = getResults();
|
||||
assertThat((Boolean) result.get(0), is(Boolean.TRUE));
|
||||
assertThat(((Long) result.get(1)).doubleValue(), is(closeTo(-1, 0)));
|
||||
assertThat(((String) result.get(2)), is(equalTo("spring")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
@WithRedisDriver({ RedisDriver.JEDIS, RedisDriver.LETTUCE })
|
||||
public void setWithExpirationAndAbsentOptionShouldSetTtlWhenKeyDoesNotExist() {
|
||||
|
||||
String key = "exp-" + UUID.randomUUID();
|
||||
connection.set(key, "data", Expiration.milliseconds(500), SetOption.ifAbsent());
|
||||
|
||||
actual.add(connection.exists(key));
|
||||
actual.add(connection.pTtl(key));
|
||||
actual.add(connection.get(key));
|
||||
|
||||
List<Object> result = getResults();
|
||||
assertThat((Boolean) result.get(0), is(Boolean.TRUE));
|
||||
assertThat(((Long) result.get(1)).doubleValue(), is(closeTo(500d, 499d)));
|
||||
assertThat(((String) result.get(2)), is(equalTo("data")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
@WithRedisDriver({ RedisDriver.JEDIS, RedisDriver.LETTUCE })
|
||||
public void setWithExpirationAndPresentOptionShouldSetTtlWhenKeyDoesExist() {
|
||||
|
||||
String key = "exp-" + UUID.randomUUID();
|
||||
connection.set(key, "spring");
|
||||
connection.set(key, "data", Expiration.milliseconds(500), SetOption.ifPresent());
|
||||
|
||||
actual.add(connection.exists(key));
|
||||
actual.add(connection.pTtl(key));
|
||||
actual.add(connection.get(key));
|
||||
|
||||
List<Object> result = getResults();
|
||||
assertThat((Boolean) result.get(0), is(Boolean.TRUE));
|
||||
assertThat(((Long) result.get(1)).doubleValue(), is(closeTo(500, 499)));
|
||||
assertThat(((String) result.get(2)), is(equalTo("data")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
@WithRedisDriver({ RedisDriver.JEDIS, RedisDriver.LETTUCE })
|
||||
public void setWithExpirationAndPresentOptionShouldSetTtlWhenKeyDoesNotExist() {
|
||||
|
||||
String key = "exp-" + UUID.randomUUID();
|
||||
connection.set(key, "data", Expiration.milliseconds(500), SetOption.ifPresent());
|
||||
|
||||
actual.add(connection.exists(key));
|
||||
actual.add(connection.pTtl(key));
|
||||
actual.add(connection.get(key));
|
||||
|
||||
List<Object> result = getResults();
|
||||
assertThat((Boolean) result.get(0), is(Boolean.FALSE));
|
||||
assertThat(((Long) result.get(1)).doubleValue(), is(closeTo(-2, 0)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
@WithRedisDriver({ RedisDriver.JEDIS, RedisDriver.LETTUCE })
|
||||
public void setWithNullExpirationAndUpsertOpionShouldSetTtlWhenKeyDoesNotExist() {
|
||||
|
||||
String key = "exp-" + UUID.randomUUID();
|
||||
connection.set(key, "foo", null, SetOption.upsert());
|
||||
|
||||
actual.add(connection.exists(key));
|
||||
actual.add(connection.pTtl(key));
|
||||
|
||||
List<Object> result = getResults();
|
||||
assertThat((Boolean) result.get(0), is(Boolean.TRUE));
|
||||
assertThat(((Long) result.get(1)).doubleValue(), is(closeTo(-1, 0)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
@WithRedisDriver({ RedisDriver.JEDIS, RedisDriver.LETTUCE })
|
||||
public void setWithoutExpirationAndUpsertOpionShouldSetTtlWhenKeyDoesNotExist() {
|
||||
|
||||
String key = "exp-" + UUID.randomUUID();
|
||||
connection.set(key, "foo", Expiration.persistent(), SetOption.upsert());
|
||||
|
||||
actual.add(connection.exists(key));
|
||||
actual.add(connection.pTtl(key));
|
||||
|
||||
List<Object> result = getResults();
|
||||
assertThat((Boolean) result.get(0), is(Boolean.TRUE));
|
||||
assertThat(((Long) result.get(1)).doubleValue(), is(closeTo(-1, 0)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
@WithRedisDriver({ RedisDriver.JEDIS, RedisDriver.LETTUCE })
|
||||
public void setWithoutExpirationAndUpsertOpionShouldSetTtlWhenKeyDoesExist() {
|
||||
|
||||
String key = "exp-" + UUID.randomUUID();
|
||||
connection.set(key, "spring");
|
||||
connection.set(key, "data", Expiration.persistent(), SetOption.upsert());
|
||||
|
||||
actual.add(connection.exists(key));
|
||||
actual.add(connection.pTtl(key));
|
||||
actual.add(connection.get(key));
|
||||
|
||||
List<Object> result = getResults();
|
||||
assertThat((Boolean) result.get(0), is(Boolean.TRUE));
|
||||
assertThat(((Long) result.get(1)).doubleValue(), is(closeTo(-1, 0)));
|
||||
assertThat(((String) result.get(2)), is(equalTo("data")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
@WithRedisDriver({ RedisDriver.JEDIS, RedisDriver.LETTUCE })
|
||||
public void setWithoutExpirationAndAbsentOptionShouldSetTtlWhenKeyDoesExist() {
|
||||
|
||||
String key = "exp-" + UUID.randomUUID();
|
||||
connection.set(key, "spring");
|
||||
connection.set(key, "data", Expiration.persistent(), SetOption.ifAbsent());
|
||||
|
||||
actual.add(connection.exists(key));
|
||||
actual.add(connection.pTtl(key));
|
||||
actual.add(connection.get(key));
|
||||
|
||||
List<Object> result = getResults();
|
||||
assertThat((Boolean) result.get(0), is(Boolean.TRUE));
|
||||
assertThat(((Long) result.get(1)).doubleValue(), is(closeTo(-1, 0)));
|
||||
assertThat(((String) result.get(2)), is(equalTo("spring")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
@WithRedisDriver({ RedisDriver.JEDIS, RedisDriver.LETTUCE })
|
||||
public void setWithoutExpirationAndAbsentOptionShouldSetTtlWhenKeyDoesNotExist() {
|
||||
|
||||
String key = "exp-" + UUID.randomUUID();
|
||||
connection.set(key, "data", Expiration.persistent(), SetOption.ifAbsent());
|
||||
|
||||
actual.add(connection.exists(key));
|
||||
actual.add(connection.pTtl(key));
|
||||
actual.add(connection.get(key));
|
||||
|
||||
List<Object> result = getResults();
|
||||
assertThat((Boolean) result.get(0), is(Boolean.TRUE));
|
||||
assertThat(((Long) result.get(1)).doubleValue(), is(closeTo(-1, 0)));
|
||||
assertThat(((String) result.get(2)), is(equalTo("data")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
@WithRedisDriver({ RedisDriver.JEDIS, RedisDriver.LETTUCE })
|
||||
public void setWithoutExpirationAndPresentOptionShouldSetTtlWhenKeyDoesExist() {
|
||||
|
||||
String key = "exp-" + UUID.randomUUID();
|
||||
connection.set(key, "spring");
|
||||
connection.set(key, "data", Expiration.persistent(), SetOption.ifPresent());
|
||||
|
||||
actual.add(connection.exists(key));
|
||||
actual.add(connection.pTtl(key));
|
||||
actual.add(connection.get(key));
|
||||
|
||||
List<Object> result = getResults();
|
||||
assertThat((Boolean) result.get(0), is(Boolean.TRUE));
|
||||
assertThat(((Long) result.get(1)).doubleValue(), is(closeTo(-1, 0)));
|
||||
assertThat(((String) result.get(2)), is(equalTo("data")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
@WithRedisDriver({ RedisDriver.JEDIS, RedisDriver.LETTUCE })
|
||||
public void setWithoutExpirationAndPresentOptionShouldSetTtlWhenKeyDoesNotExist() {
|
||||
|
||||
String key = "exp-" + UUID.randomUUID();
|
||||
connection.set(key, "data", Expiration.persistent(), SetOption.ifPresent());
|
||||
|
||||
actual.add(connection.exists(key));
|
||||
actual.add(connection.pTtl(key));
|
||||
actual.add(connection.get(key));
|
||||
|
||||
List<Object> result = getResults();
|
||||
assertThat((Boolean) result.get(0), is(Boolean.FALSE));
|
||||
assertThat(((Long) result.get(1)).doubleValue(), is(closeTo(-2, 0)));
|
||||
}
|
||||
|
||||
protected void verifyResults(List<Object> expected) {
|
||||
assertEquals(expected, getResults());
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
* Copyright 2015-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.
|
||||
@@ -15,6 +15,9 @@
|
||||
*/
|
||||
package org.springframework.data.redis.connection;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public interface ClusterConnectionTests {
|
||||
|
||||
/**
|
||||
@@ -893,4 +896,44 @@ public interface ClusterConnectionTests {
|
||||
*/
|
||||
void clusterGetMasterSlaveMapShouldListMastersAndSlavesCorrectly();
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
void setWithExpirationInSecondsShouldWorkCorrectly();
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
void setWithExpirationInMillisecondsShouldWorkCorrectly();
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
void setWithOptionIfPresentShouldWorkCorrectly();
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
void setWithOptionIfAbsentShouldWorkCorrectly();
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
void setWithExpirationAndIfAbsentShouldWorkCorrectly();
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
void setWithExpirationAndIfAbsentShouldNotBeAppliedWhenKeyExists();
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
void setWithExpirationAndIfPresentShouldWorkCorrectly();
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
void setWithExpirationAndIfPresentShouldNotBeAppliedWhenKeyDoesNotExists();
|
||||
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.data.redis.connection.RedisNode.RedisNodeBuilder;
|
||||
import org.springframework.data.redis.core.Cursor;
|
||||
import org.springframework.data.redis.core.ScanOptions;
|
||||
import org.springframework.data.redis.core.types.Expiration;
|
||||
import org.springframework.data.redis.core.types.RedisClientInfo;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
@@ -891,5 +892,10 @@ public class RedisConnectionUnitTests {
|
||||
public void migrate(byte[] key, RedisNode target, int dbIndex, MigrateOption option, long timeout) {
|
||||
delegate.migrate(key, target, dbIndex, option, timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(byte[] key, byte[] value, Expiration expiration, SetOption options) {
|
||||
delegate.set(key, value, expiration, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
* Copyright 2015-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.
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.data.redis.connection.jedis;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.hamcrest.number.IsCloseTo.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.*;
|
||||
|
||||
@@ -46,10 +47,12 @@ import org.springframework.data.redis.connection.RedisClusterNode;
|
||||
import org.springframework.data.redis.connection.RedisListCommands.Position;
|
||||
import org.springframework.data.redis.connection.RedisNode;
|
||||
import org.springframework.data.redis.connection.RedisStringCommands.BitOperation;
|
||||
import org.springframework.data.redis.connection.RedisStringCommands.SetOption;
|
||||
import org.springframework.data.redis.connection.RedisZSetCommands.Range;
|
||||
import org.springframework.data.redis.connection.RedisZSetCommands.Tuple;
|
||||
import org.springframework.data.redis.core.Cursor;
|
||||
import org.springframework.data.redis.core.ScanOptions;
|
||||
import org.springframework.data.redis.core.types.Expiration;
|
||||
import org.springframework.data.redis.test.util.RedisClusterRule;
|
||||
|
||||
import redis.clients.jedis.HostAndPort;
|
||||
@@ -2308,4 +2311,103 @@ public class JedisClusterConnectionTests implements ClusterConnectionTests {
|
||||
assertThat(masterSlaveMap.get(new RedisClusterNode(CLUSTER_HOST, MASTER_NODE_2_PORT)).isEmpty(), is(true));
|
||||
assertThat(masterSlaveMap.get(new RedisClusterNode(CLUSTER_HOST, MASTER_NODE_3_PORT)).isEmpty(), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
public void setWithExpirationInSecondsShouldWorkCorrectly() {
|
||||
|
||||
clusterConnection.set(KEY_1_BYTES, VALUE_1_BYTES, Expiration.seconds(1), SetOption.upsert());
|
||||
|
||||
assertThat(nativeConnection.exists(KEY_1_BYTES), is(true));
|
||||
assertThat(nativeConnection.ttl(KEY_1_BYTES), is(1L));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
public void setWithExpirationInMillisecondsShouldWorkCorrectly() {
|
||||
|
||||
clusterConnection.set(KEY_1_BYTES, VALUE_1_BYTES, Expiration.milliseconds(500), SetOption.upsert());
|
||||
|
||||
assertThat(nativeConnection.exists(KEY_1_BYTES), is(true));
|
||||
assertThat(nativeConnection.pttl(KEY_1).doubleValue(), is(closeTo(500d, 499d)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void setWithOptionIfPresentShouldWorkCorrectly() {
|
||||
|
||||
nativeConnection.set(KEY_1_BYTES, VALUE_1_BYTES);
|
||||
clusterConnection.set(KEY_1_BYTES, VALUE_2_BYTES, Expiration.persistent(), SetOption.ifPresent());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
public void setWithOptionIfAbsentShouldWorkCorrectly() {
|
||||
|
||||
clusterConnection.set(KEY_1_BYTES, VALUE_1_BYTES, Expiration.persistent(), SetOption.ifAbsent());
|
||||
|
||||
assertThat(nativeConnection.exists(KEY_1_BYTES), is(true));
|
||||
assertThat(nativeConnection.ttl(KEY_1_BYTES), is(-1L));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
public void setWithExpirationAndIfAbsentShouldWorkCorrectly() {
|
||||
|
||||
clusterConnection.set(KEY_1_BYTES, VALUE_1_BYTES, Expiration.seconds(1), SetOption.ifAbsent());
|
||||
|
||||
assertThat(nativeConnection.exists(KEY_1_BYTES), is(true));
|
||||
assertThat(nativeConnection.ttl(KEY_1_BYTES), is(1L));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
public void setWithExpirationAndIfAbsentShouldNotBeAppliedWhenKeyExists() {
|
||||
|
||||
nativeConnection.set(KEY_1_BYTES, VALUE_1_BYTES);
|
||||
|
||||
clusterConnection.set(KEY_1_BYTES, VALUE_2_BYTES, Expiration.seconds(1), SetOption.ifAbsent());
|
||||
|
||||
assertThat(nativeConnection.exists(KEY_1_BYTES), is(true));
|
||||
assertThat(nativeConnection.ttl(KEY_1_BYTES), is(-1L));
|
||||
assertThat(nativeConnection.get(KEY_1_BYTES), is(equalTo(VALUE_1_BYTES)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
public void setWithExpirationAndIfPresentShouldWorkCorrectly() {
|
||||
|
||||
nativeConnection.set(KEY_1_BYTES, VALUE_1_BYTES);
|
||||
|
||||
clusterConnection.set(KEY_1_BYTES, VALUE_2_BYTES, Expiration.seconds(1), SetOption.ifPresent());
|
||||
|
||||
assertThat(nativeConnection.exists(KEY_1_BYTES), is(true));
|
||||
assertThat(nativeConnection.ttl(KEY_1_BYTES), is(1L));
|
||||
assertThat(nativeConnection.get(KEY_1_BYTES), is(equalTo(VALUE_2_BYTES)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
public void setWithExpirationAndIfPresentShouldNotBeAppliedWhenKeyDoesNotExists() {
|
||||
|
||||
clusterConnection.set(KEY_1_BYTES, VALUE_1_BYTES, Expiration.seconds(1), SetOption.ifPresent());
|
||||
|
||||
assertThat(nativeConnection.exists(KEY_1_BYTES), is(false));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
* Copyright 2014-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.
|
||||
@@ -29,7 +29,9 @@ import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.redis.connection.RedisServer;
|
||||
import org.springframework.data.redis.connection.RedisStringCommands.SetOption;
|
||||
import org.springframework.data.redis.connection.RedisZSetCommands.Range;
|
||||
import org.springframework.data.redis.core.types.Expiration;
|
||||
import org.springframework.data.redis.core.types.RedisClientInfo;
|
||||
|
||||
/**
|
||||
@@ -257,6 +259,56 @@ public class JedisConvertersUnitTests {
|
||||
JedisConverters.boundaryToBytesForZRange(Range.range().gt(new Date()).getMin(), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
public void toSetCommandExPxOptionShouldReturnEXforSeconds() {
|
||||
assertThat(JedisConverters.toSetCommandExPxArgument(Expiration.seconds(100)), equalTo(JedisConverters.toBytes("EX")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
public void toSetCommandExPxOptionShouldReturnEXforMilliseconds() {
|
||||
|
||||
assertThat(JedisConverters.toSetCommandExPxArgument(Expiration.milliseconds(100)),
|
||||
equalTo(JedisConverters.toBytes("PX")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
public void toSetCommandExPxOptionShouldReturnEmptyArrayForNull() {
|
||||
assertThat(JedisConverters.toSetCommandExPxArgument(null), equalTo(new byte[] {}));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
public void toSetCommandNxXxOptionShouldReturnNXforAbsent() {
|
||||
assertThat(JedisConverters.toSetCommandNxXxArgument(SetOption.ifAbsent()), equalTo(JedisConverters.toBytes("NX")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
public void toSetCommandNxXxOptionShouldReturnXXforAbsent() {
|
||||
assertThat(JedisConverters.toSetCommandNxXxArgument(SetOption.ifPresent()), equalTo(JedisConverters.toBytes("XX")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
public void toSetCommandNxXxOptionShouldReturnEmptyArrayforUpsert() {
|
||||
assertThat(JedisConverters.toSetCommandNxXxArgument(SetOption.upsert()), equalTo(new byte[] {}));
|
||||
}
|
||||
|
||||
private void verifyRedisServerInfo(RedisServer server, Map<String, String> values) {
|
||||
|
||||
for (Map.Entry<String, String> entry : values.entrySet()) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
* Copyright 2015-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.
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.data.redis.connection.lettuce;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.hamcrest.number.IsCloseTo.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.*;
|
||||
|
||||
@@ -44,11 +45,13 @@ import org.springframework.data.redis.connection.RedisClusterNode;
|
||||
import org.springframework.data.redis.connection.RedisListCommands.Position;
|
||||
import org.springframework.data.redis.connection.RedisNode;
|
||||
import org.springframework.data.redis.connection.RedisStringCommands.BitOperation;
|
||||
import org.springframework.data.redis.connection.RedisStringCommands.SetOption;
|
||||
import org.springframework.data.redis.connection.RedisZSetCommands.Range;
|
||||
import org.springframework.data.redis.connection.RedisZSetCommands.Tuple;
|
||||
import org.springframework.data.redis.connection.jedis.JedisConverters;
|
||||
import org.springframework.data.redis.core.Cursor;
|
||||
import org.springframework.data.redis.core.ScanOptions;
|
||||
import org.springframework.data.redis.core.types.Expiration;
|
||||
import org.springframework.data.redis.test.util.RedisClusterRule;
|
||||
|
||||
import com.lambdaworks.redis.RedisURI.Builder;
|
||||
@@ -2298,4 +2301,105 @@ public class LettuceClusterConnectionTests implements ClusterConnectionTests {
|
||||
assertThat(masterSlaveMap.get(new RedisClusterNode(CLUSTER_HOST, MASTER_NODE_2_PORT)).isEmpty(), is(true));
|
||||
assertThat(masterSlaveMap.get(new RedisClusterNode(CLUSTER_HOST, MASTER_NODE_3_PORT)).isEmpty(), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
public void setWithExpirationInSecondsShouldWorkCorrectly() {
|
||||
|
||||
clusterConnection.set(KEY_1_BYTES, VALUE_1_BYTES, Expiration.seconds(1), SetOption.upsert());
|
||||
|
||||
assertThat(nativeConnection.exists(KEY_1), is(true));
|
||||
assertThat(nativeConnection.ttl(KEY_1), is(1L));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
public void setWithExpirationInMillisecondsShouldWorkCorrectly() {
|
||||
|
||||
clusterConnection.set(KEY_1_BYTES, VALUE_1_BYTES, Expiration.milliseconds(500), SetOption.upsert());
|
||||
|
||||
assertThat(nativeConnection.exists(KEY_1), is(true));
|
||||
assertThat(nativeConnection.pttl(KEY_1).doubleValue(), is(closeTo(500d, 499d)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
public void setWithOptionIfPresentShouldWorkCorrectly() {
|
||||
|
||||
nativeConnection.set(KEY_1, VALUE_1);
|
||||
clusterConnection.set(KEY_1_BYTES, VALUE_2_BYTES, Expiration.persistent(), SetOption.ifPresent());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
public void setWithOptionIfAbsentShouldWorkCorrectly() {
|
||||
|
||||
clusterConnection.set(KEY_1_BYTES, VALUE_1_BYTES, Expiration.persistent(), SetOption.ifAbsent());
|
||||
|
||||
assertThat(nativeConnection.exists(KEY_1), is(true));
|
||||
assertThat(nativeConnection.ttl(KEY_1), is(-1L));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
public void setWithExpirationAndIfAbsentShouldWorkCorrectly() {
|
||||
|
||||
clusterConnection.set(KEY_1_BYTES, VALUE_1_BYTES, Expiration.seconds(1), SetOption.ifAbsent());
|
||||
|
||||
assertThat(nativeConnection.exists(KEY_1), is(true));
|
||||
assertThat(nativeConnection.ttl(KEY_1), is(1L));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
public void setWithExpirationAndIfAbsentShouldNotBeAppliedWhenKeyExists() {
|
||||
|
||||
nativeConnection.set(KEY_1, VALUE_1);
|
||||
|
||||
clusterConnection.set(KEY_1_BYTES, VALUE_2_BYTES, Expiration.seconds(1), SetOption.ifAbsent());
|
||||
|
||||
assertThat(nativeConnection.exists(KEY_1), is(true));
|
||||
assertThat(nativeConnection.ttl(KEY_1), is(-1L));
|
||||
assertThat(nativeConnection.get(KEY_1), is(equalTo(VALUE_1)));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
public void setWithExpirationAndIfPresentShouldWorkCorrectly() {
|
||||
|
||||
nativeConnection.set(KEY_1, VALUE_1);
|
||||
|
||||
clusterConnection.set(KEY_1_BYTES, VALUE_2_BYTES, Expiration.seconds(1), SetOption.ifPresent());
|
||||
|
||||
assertThat(nativeConnection.exists(KEY_1), is(true));
|
||||
assertThat(nativeConnection.ttl(KEY_1), is(1L));
|
||||
assertThat(nativeConnection.get(KEY_1), is(equalTo(VALUE_2)));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
public void setWithExpirationAndIfPresentShouldNotBeAppliedWhenKeyDoesNotExists() {
|
||||
|
||||
clusterConnection.set(KEY_1_BYTES, VALUE_1_BYTES, Expiration.seconds(1), SetOption.ifPresent());
|
||||
|
||||
assertThat(nativeConnection.exists(KEY_1), is(false));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import static org.hamcrest.core.IsEqual.*;
|
||||
import static org.hamcrest.core.IsNull.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.*;
|
||||
import static org.springframework.test.util.ReflectionTestUtils.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@@ -31,11 +32,14 @@ import org.junit.Test;
|
||||
import org.springframework.data.redis.connection.RedisClusterNode;
|
||||
import org.springframework.data.redis.connection.RedisClusterNode.Flag;
|
||||
import org.springframework.data.redis.connection.RedisClusterNode.LinkState;
|
||||
import org.springframework.data.redis.connection.RedisStringCommands.SetOption;
|
||||
import org.springframework.data.redis.core.types.Expiration;
|
||||
import org.springframework.data.redis.core.types.RedisClientInfo;
|
||||
|
||||
import com.lambdaworks.redis.RedisURI;
|
||||
import com.lambdaworks.redis.cluster.models.partitions.Partitions;
|
||||
import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode.NodeFlag;
|
||||
import com.lambdaworks.redis.protocol.SetArgs;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
@@ -111,4 +115,102 @@ public class LettuceConvertersUnitTests {
|
||||
assertThat(node.getLinkState(), is(LinkState.CONNECTED));
|
||||
assertThat(node.getSlotRange().getSlots(), hasItems(1, 2, 3, 4, 5));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
public void toSetArgsShouldReturnEmptyArgsForNullValues() {
|
||||
|
||||
SetArgs args = LettuceConverters.toSetArgs(null, null);
|
||||
|
||||
assertThat(getField(args, "ex"), is(nullValue()));
|
||||
assertThat(getField(args, "px"), is(nullValue()));
|
||||
assertThat((Boolean) getField(args, "nx"), is(Boolean.FALSE));
|
||||
assertThat((Boolean) getField(args, "xx"), is(Boolean.FALSE));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
public void toSetArgsShouldNotSetExOrPxForPersistent() {
|
||||
|
||||
SetArgs args = LettuceConverters.toSetArgs(Expiration.persistent(), null);
|
||||
|
||||
assertThat(getField(args, "ex"), is(nullValue()));
|
||||
assertThat(getField(args, "px"), is(nullValue()));
|
||||
assertThat((Boolean) getField(args, "nx"), is(Boolean.FALSE));
|
||||
assertThat((Boolean) getField(args, "xx"), is(Boolean.FALSE));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
public void toSetArgsShouldSetExForSeconds() {
|
||||
|
||||
SetArgs args = LettuceConverters.toSetArgs(Expiration.seconds(10), null);
|
||||
|
||||
assertThat((Long) getField(args, "ex"), is(10L));
|
||||
assertThat(getField(args, "px"), is(nullValue()));
|
||||
assertThat((Boolean) getField(args, "nx"), is(Boolean.FALSE));
|
||||
assertThat((Boolean) getField(args, "xx"), is(Boolean.FALSE));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
public void toSetArgsShouldSetPxForMilliseconds() {
|
||||
|
||||
SetArgs args = LettuceConverters.toSetArgs(Expiration.milliseconds(100), null);
|
||||
|
||||
assertThat(getField(args, "ex"), is(nullValue()));
|
||||
assertThat((Long) getField(args, "px"), is(100L));
|
||||
assertThat((Boolean) getField(args, "nx"), is(Boolean.FALSE));
|
||||
assertThat((Boolean) getField(args, "xx"), is(Boolean.FALSE));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
public void toSetArgsShouldSetNxForAbsent() {
|
||||
|
||||
SetArgs args = LettuceConverters.toSetArgs(null, SetOption.ifAbsent());
|
||||
|
||||
assertThat(getField(args, "ex"), is(nullValue()));
|
||||
assertThat(getField(args, "px"), is(nullValue()));
|
||||
assertThat((Boolean) getField(args, "nx"), is(Boolean.TRUE));
|
||||
assertThat((Boolean) getField(args, "xx"), is(Boolean.FALSE));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
public void toSetArgsShouldSetXxForPresent() {
|
||||
|
||||
SetArgs args = LettuceConverters.toSetArgs(null, SetOption.ifPresent());
|
||||
|
||||
assertThat(getField(args, "ex"), is(nullValue()));
|
||||
assertThat(getField(args, "px"), is(nullValue()));
|
||||
assertThat((Boolean) getField(args, "nx"), is(Boolean.FALSE));
|
||||
assertThat((Boolean) getField(args, "xx"), is(Boolean.TRUE));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-316
|
||||
*/
|
||||
@Test
|
||||
public void toSetArgsShouldNotSetNxOrXxForUpsert() {
|
||||
|
||||
SetArgs args = LettuceConverters.toSetArgs(null, SetOption.upsert());
|
||||
|
||||
assertThat(getField(args, "ex"), is(nullValue()));
|
||||
assertThat(getField(args, "px"), is(nullValue()));
|
||||
assertThat((Boolean) getField(args, "nx"), is(Boolean.FALSE));
|
||||
assertThat((Boolean) getField(args, "xx"), is(Boolean.FALSE));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user