diff --git a/src/main/java/redis/clients/jedis/BinaryClient.java b/src/main/java/redis/clients/jedis/BinaryClient.java index a5323d2..56be470 100644 --- a/src/main/java/redis/clients/jedis/BinaryClient.java +++ b/src/main/java/redis/clients/jedis/BinaryClient.java @@ -192,6 +192,10 @@ public class BinaryClient extends Connection { sendCommand(INCRBY, key, toByteArray(integer)); } + public void incrByFloat(final byte[] key, final double value) { + sendCommand(INCRBYFLOAT, key, toByteArray(value)); + } + public void incr(final byte[] key) { sendCommand(INCR, key); } @@ -238,6 +242,10 @@ public class BinaryClient extends Connection { sendCommand(HINCRBY, key, field, toByteArray(value)); } + public void hincrByFloat(final byte[] key, final byte[] field, final double value) { + sendCommand(HINCRBYFLOAT, key, field, toByteArray(value)); + } + public void hexists(final byte[] key, final byte[] field) { sendCommand(HEXISTS, key, field); } diff --git a/src/main/java/redis/clients/jedis/BinaryJedis.java b/src/main/java/redis/clients/jedis/BinaryJedis.java index 5403e70..c959f47 100644 --- a/src/main/java/redis/clients/jedis/BinaryJedis.java +++ b/src/main/java/redis/clients/jedis/BinaryJedis.java @@ -602,6 +602,36 @@ public class BinaryJedis implements BinaryJedisCommands { return client.getIntegerReply(); } + /** + * INCRBYFLOAT work just like {@link #incrBy(byte[]) INCRBY} but increments + * by floats instead of integers. + *

+ * INCRBYFLOAT commands are limited to double precision floating point values. + *

+ * Note: this is actually a string operation, that is, in Redis there are + * not "double" types. Simply the string stored at the key is parsed as a + * base double precision floating point value, incremented, and then converted + * back as a string. There is no DECRYBYFLOAT but providing a negative + * value will work as expected. + *

+ * Time complexity: O(1) + * + * @see #incr(byte[]) + * @see #decr(byte[]) + * @see #decrBy(byte[], long) + * + * @param key + * @param integer + * @return Integer reply, this commands will reply with the new value of key + * after the increment. + */ + public Double incrByFloat(final byte[] key, final double integer) { + checkIsInMulti(); + client.incrByFloat(key, integer); + String dval = client.getBulkReply(); + return (dval != null ? new Double(dval) : null); + } + /** * Increment the number stored at key by one. If the key does not exist or * contains a value of a wrong type, set the key to the value of "0" before @@ -794,6 +824,32 @@ public class BinaryJedis implements BinaryJedisCommands { return client.getIntegerReply(); } + /** + * Increment the number stored at field in the hash at key by a double + * precision floating point value. If key does not exist, + * a new key holding a hash is created. If field does not + * exist or holds a string, the value is set to 0 before applying the + * operation. Since the value argument is signed you can use this command to + * perform both increments and decrements. + *

+ * The range of values supported by HINCRBYFLOAT is limited to + * double precision floating point values. + *

+ * Time complexity: O(1) + * + * @param key + * @param field + * @param value + * @return Double precision floating point reply The new value at field after the increment + * operation. + */ + public Double hincrByFloat(final byte[] key, final byte[] field, final double value) { + checkIsInMulti(); + client.hincrByFloat(key, field, value); + final String dval = client.getBulkReply(); + return (dval != null ? new Double(dval) : null); + } + /** * Test for existence of a specified field in a hash. * diff --git a/src/main/java/redis/clients/jedis/BinaryJedisCommands.java b/src/main/java/redis/clients/jedis/BinaryJedisCommands.java index 77189f7..1a5f079 100644 --- a/src/main/java/redis/clients/jedis/BinaryJedisCommands.java +++ b/src/main/java/redis/clients/jedis/BinaryJedisCommands.java @@ -37,6 +37,8 @@ public interface BinaryJedisCommands { Long incrBy(byte[] key, long integer); + Double incrByFloat(byte[] key, double value); + Long incr(byte[] key); Long append(byte[] key, byte[] value); @@ -55,6 +57,8 @@ public interface BinaryJedisCommands { Long hincrBy(byte[] key, byte[] field, long value); + Double hincrByFloat(byte[] key, byte[] field, double value); + Boolean hexists(byte[] key, byte[] field); Long hdel(byte[] key, byte[]... field); diff --git a/src/main/java/redis/clients/jedis/BinaryShardedJedis.java b/src/main/java/redis/clients/jedis/BinaryShardedJedis.java index 23fd6d6..1b6ad9a 100644 --- a/src/main/java/redis/clients/jedis/BinaryShardedJedis.java +++ b/src/main/java/redis/clients/jedis/BinaryShardedJedis.java @@ -110,6 +110,11 @@ public class BinaryShardedJedis extends Sharded return j.incrBy(key, integer); } + public Double incrByFloat(byte[] key, double integer) { + Jedis j = getShard(key); + return j.incrByFloat(key, integer); + } + public Long incr(byte[] key) { Jedis j = getShard(key); return j.incr(key); @@ -155,6 +160,11 @@ public class BinaryShardedJedis extends Sharded return j.hincrBy(key, field, value); } + public Double hincrByFloat(byte[] key, byte[] field, double value) { + Jedis j = getShard(key); + return j.hincrByFloat(key, field, value); + } + public Boolean hexists(byte[] key, byte[] field) { Jedis j = getShard(key); return j.hexists(key, field); diff --git a/src/main/java/redis/clients/jedis/Client.java b/src/main/java/redis/clients/jedis/Client.java index 39aae12..992d10d 100644 --- a/src/main/java/redis/clients/jedis/Client.java +++ b/src/main/java/redis/clients/jedis/Client.java @@ -117,6 +117,10 @@ public class Client extends BinaryClient implements Commands { incrBy(SafeEncoder.encode(key), integer); } + public void incrByFloat(final String key, final double value) { + incrByFloat(SafeEncoder.encode(key), value); + } + public void incr(final String key) { incr(SafeEncoder.encode(key)); } @@ -165,6 +169,10 @@ public class Client extends BinaryClient implements Commands { hincrBy(SafeEncoder.encode(key), SafeEncoder.encode(field), value); } + public void hincrByFloat(final String key, final String field, final double value) { + hincrByFloat(SafeEncoder.encode(key), SafeEncoder.encode(field), value); + } + public void hexists(final String key, final String field) { hexists(SafeEncoder.encode(key), SafeEncoder.encode(field)); } diff --git a/src/main/java/redis/clients/jedis/Commands.java b/src/main/java/redis/clients/jedis/Commands.java index 7881909..3776342 100644 --- a/src/main/java/redis/clients/jedis/Commands.java +++ b/src/main/java/redis/clients/jedis/Commands.java @@ -56,6 +56,8 @@ public interface Commands { public void incrBy(final String key, final long integer); + public void incrByFloat(final String key, final double value); + public void incr(final String key); public void append(final String key, final String value); @@ -74,6 +76,8 @@ public interface Commands { public void hincrBy(final String key, final String field, final long value); + public void hincrByFloat(final String key, final String field, final double value); + public void hexists(final String key, final String field); public void hdel(final String key, final String... fields); diff --git a/src/main/java/redis/clients/jedis/Jedis.java b/src/main/java/redis/clients/jedis/Jedis.java index f27c2bc..62040f9 100644 --- a/src/main/java/redis/clients/jedis/Jedis.java +++ b/src/main/java/redis/clients/jedis/Jedis.java @@ -572,6 +572,31 @@ public class Jedis extends BinaryJedis implements JedisCommands { return client.getIntegerReply(); } + /** + * INCRBYFLOAT + *

+ * INCRBYFLOAT commands are limited to double precision floating point values. + *

+ * Note: this is actually a string operation, that is, in Redis there are + * not "double" types. Simply the string stored at the key is parsed as a + * base double precision floating point value, incremented, and then + * converted back as a string. There is no DECRYBYFLOAT but providing a + * negative value will work as expected. + *

+ * Time complexity: O(1) + * + * @param key + * @param value + * @return Double reply, this commands will reply with the new value of key + * after the increment. + */ + public Double incrByFloat(final String key, final double value) { + checkIsInMulti(); + client.incrByFloat(key, value); + String dval = client.getBulkReply(); + return (dval != null ? new Double(dval) : null); + } + /** * Increment the number stored at key by one. If the key does not exist or * contains a value of a wrong type, set the key to the value of "0" before @@ -764,6 +789,32 @@ public class Jedis extends BinaryJedis implements JedisCommands { return client.getIntegerReply(); } + /** + * Increment the number stored at field in the hash at key by a double + * precision floating point value. If key does not exist, + * a new key holding a hash is created. If field does not + * exist or holds a string, the value is set to 0 before applying the + * operation. Since the value argument is signed you can use this command to + * perform both increments and decrements. + *

+ * The range of values supported by HINCRBYFLOAT is limited to + * double precision floating point values. + *

+ * Time complexity: O(1) + * + * @param key + * @param field + * @param value + * @return Double precision floating point reply The new value at field after the increment + * operation. + */ + public Double hincrByFloat(final String key, final String field, final double value) { + checkIsInMulti(); + client.hincrByFloat(key, field, value); + final String dval = client.getBulkReply(); + return (dval != null ? new Double(dval) : null); + } + /** * Test for existence of a specified field in a hash. * diff --git a/src/main/java/redis/clients/jedis/Pipeline.java b/src/main/java/redis/clients/jedis/Pipeline.java index d89efea..cd1ecaa 100644 --- a/src/main/java/redis/clients/jedis/Pipeline.java +++ b/src/main/java/redis/clients/jedis/Pipeline.java @@ -275,6 +275,16 @@ public class Pipeline extends Queable { return getResponse(BuilderFactory.LONG); } + public Response hincrByFloat(String key, String field, double value) { + client.hincrByFloat(key, field, value); + return getResponse(BuilderFactory.DOUBLE); + } + + public Response hincrByFloat(byte[] key, byte[] field, double value) { + client.hincrByFloat(key, field, value); + return getResponse(BuilderFactory.DOUBLE); + } + public Response> hkeys(String key) { client.hkeys(key); return getResponse(BuilderFactory.STRING_SET); @@ -365,6 +375,16 @@ public class Pipeline extends Queable { return getResponse(BuilderFactory.LONG); } + public Response incrByFloat(String key, double value) { + client.incrByFloat(key, value); + return getResponse(BuilderFactory.DOUBLE); + } + + public Response incrByFloat(byte[] key, double value) { + client.incrByFloat(key, value); + return getResponse(BuilderFactory.DOUBLE); + } + public Response> keys(String pattern) { client.keys(pattern); return getResponse(BuilderFactory.STRING_SET); diff --git a/src/main/java/redis/clients/jedis/Protocol.java b/src/main/java/redis/clients/jedis/Protocol.java index b1e391d..e061ae5 100644 --- a/src/main/java/redis/clients/jedis/Protocol.java +++ b/src/main/java/redis/clients/jedis/Protocol.java @@ -144,7 +144,7 @@ public final class Protocol { } public static enum Command { - PING, SET, GET, QUIT, EXISTS, DEL, TYPE, FLUSHDB, KEYS, RANDOMKEY, RENAME, RENAMENX, RENAMEX, DBSIZE, EXPIRE, EXPIREAT, TTL, SELECT, MOVE, FLUSHALL, GETSET, MGET, SETNX, SETEX, MSET, MSETNX, DECRBY, DECR, INCRBY, INCR, APPEND, SUBSTR, HSET, HGET, HSETNX, HMSET, HMGET, HINCRBY, HEXISTS, HDEL, HLEN, HKEYS, HVALS, HGETALL, RPUSH, LPUSH, LLEN, LRANGE, LTRIM, LINDEX, LSET, LREM, LPOP, RPOP, RPOPLPUSH, SADD, SMEMBERS, SREM, SPOP, SMOVE, SCARD, SISMEMBER, SINTER, SINTERSTORE, SUNION, SUNIONSTORE, SDIFF, SDIFFSTORE, SRANDMEMBER, ZADD, ZRANGE, ZREM, ZINCRBY, ZRANK, ZREVRANK, ZREVRANGE, ZCARD, ZSCORE, MULTI, DISCARD, EXEC, WATCH, UNWATCH, SORT, BLPOP, BRPOP, AUTH, SUBSCRIBE, PUBLISH, UNSUBSCRIBE, PSUBSCRIBE, PUNSUBSCRIBE, ZCOUNT, ZRANGEBYSCORE, ZREVRANGEBYSCORE, ZREMRANGEBYRANK, ZREMRANGEBYSCORE, ZUNIONSTORE, ZINTERSTORE, SAVE, BGSAVE, BGREWRITEAOF, LASTSAVE, SHUTDOWN, INFO, MONITOR, SLAVEOF, CONFIG, STRLEN, SYNC, LPUSHX, PERSIST, RPUSHX, ECHO, LINSERT, DEBUG, BRPOPLPUSH, SETBIT, GETBIT, SETRANGE, GETRANGE, EVAL, EVALSHA, SCRIPT, SLOWLOG, OBJECT; + PING, SET, GET, QUIT, EXISTS, DEL, TYPE, FLUSHDB, KEYS, RANDOMKEY, RENAME, RENAMENX, RENAMEX, DBSIZE, EXPIRE, EXPIREAT, TTL, SELECT, MOVE, FLUSHALL, GETSET, MGET, SETNX, SETEX, MSET, MSETNX, DECRBY, DECR, INCRBY, INCRBYFLOAT, INCR, APPEND, SUBSTR, HSET, HGET, HSETNX, HMSET, HMGET, HINCRBY, HINCRBYFLOAT, HEXISTS, HDEL, HLEN, HKEYS, HVALS, HGETALL, RPUSH, LPUSH, LLEN, LRANGE, LTRIM, LINDEX, LSET, LREM, LPOP, RPOP, RPOPLPUSH, SADD, SMEMBERS, SREM, SPOP, SMOVE, SCARD, SISMEMBER, SINTER, SINTERSTORE, SUNION, SUNIONSTORE, SDIFF, SDIFFSTORE, SRANDMEMBER, ZADD, ZRANGE, ZREM, ZINCRBY, ZRANK, ZREVRANK, ZREVRANGE, ZCARD, ZSCORE, MULTI, DISCARD, EXEC, WATCH, UNWATCH, SORT, BLPOP, BRPOP, AUTH, SUBSCRIBE, PUBLISH, UNSUBSCRIBE, PSUBSCRIBE, PUNSUBSCRIBE, ZCOUNT, ZRANGEBYSCORE, ZREVRANGEBYSCORE, ZREMRANGEBYRANK, ZREMRANGEBYSCORE, ZUNIONSTORE, ZINTERSTORE, SAVE, BGSAVE, BGREWRITEAOF, LASTSAVE, SHUTDOWN, INFO, MONITOR, SLAVEOF, CONFIG, STRLEN, SYNC, LPUSHX, PERSIST, RPUSHX, ECHO, LINSERT, DEBUG, BRPOPLPUSH, SETBIT, GETBIT, SETRANGE, GETRANGE, EVAL, EVALSHA, SCRIPT, SLOWLOG, OBJECT; public final byte[] raw; diff --git a/src/main/java/redis/clients/jedis/ShardedJedis.java b/src/main/java/redis/clients/jedis/ShardedJedis.java index ea2f11e..6e45e26 100644 --- a/src/main/java/redis/clients/jedis/ShardedJedis.java +++ b/src/main/java/redis/clients/jedis/ShardedJedis.java @@ -118,6 +118,11 @@ public class ShardedJedis extends BinaryShardedJedis implements JedisCommands { return j.incrBy(key, integer); } + public Double incrByFloat(String key, double integer) { + Jedis j = getShard(key); + return j.incrByFloat(key, integer); + } + public Long incr(String key) { Jedis j = getShard(key); return j.incr(key); @@ -163,6 +168,11 @@ public class ShardedJedis extends BinaryShardedJedis implements JedisCommands { return j.hincrBy(key, field, value); } + public Double hincrByFloat(String key, String field, double value) { + Jedis j = getShard(key); + return j.hincrByFloat(key, field, value); + } + public Boolean hexists(String key, String field) { Jedis j = getShard(key); return j.hexists(key, field); diff --git a/src/main/java/redis/clients/jedis/ShardedJedisPipeline.java b/src/main/java/redis/clients/jedis/ShardedJedisPipeline.java index af416c0..e8eeed7 100644 --- a/src/main/java/redis/clients/jedis/ShardedJedisPipeline.java +++ b/src/main/java/redis/clients/jedis/ShardedJedisPipeline.java @@ -123,6 +123,13 @@ public class ShardedJedisPipeline extends Queable { return getResponse(BuilderFactory.LONG); } + public Response incrByFloat(String key, double value) { + Client c = getClient(key); + c.incrByFloat(key, value); + results.add(new FutureResult(c)); + return getResponse(BuilderFactory.DOUBLE); + } + public Response incr(String key) { Client c = getClient(key); c.incr(key); @@ -186,6 +193,13 @@ public class ShardedJedisPipeline extends Queable { return getResponse(BuilderFactory.LONG); } + public Response hincrByFloat(String key, String field, double value) { + Client c = getClient(key); + c.hincrByFloat(key, field, value); + results.add(new FutureResult(c)); + return getResponse(BuilderFactory.DOUBLE); + } + public Response hexists(String key, String field) { Client c = getClient(key); c.hexists(key, field); diff --git a/src/test/java/redis/clients/jedis/tests/commands/HashesCommandsTest.java b/src/test/java/redis/clients/jedis/tests/commands/HashesCommandsTest.java index fbcbca3..aa303dd 100644 --- a/src/test/java/redis/clients/jedis/tests/commands/HashesCommandsTest.java +++ b/src/test/java/redis/clients/jedis/tests/commands/HashesCommandsTest.java @@ -143,6 +143,25 @@ public class HashesCommandsTest extends JedisCommandTestBase { } + @Test + public void hincrByFloat() { + Double value = jedis.hincrByFloat("foo", "bar", 1.5d); + assertEquals((Double) 1.5d, value); + value = jedis.hincrByFloat("foo", "bar", -1.5d); + assertEquals((Double) 0d, value); + value = jedis.hincrByFloat("foo", "bar", -10.7d); + assertEquals(Double.compare(-10.7d, value), 0); + + // Binary + double bvalue = jedis.hincrByFloat(bfoo, bbar, 1.5d); + assertEquals(Double.compare(1.5d, bvalue), 0); + bvalue = jedis.hincrByFloat(bfoo, bbar, -1.5d); + assertEquals(Double.compare(0d, bvalue), 0); + bvalue = jedis.hincrByFloat(bfoo, bbar, -10.7d); + assertEquals(Double.compare(-10.7d, value), 0); + + } + @Test public void hexists() { Map hash = new HashMap(); diff --git a/src/test/java/redis/clients/jedis/tests/commands/ScriptingCommandsTest.java b/src/test/java/redis/clients/jedis/tests/commands/ScriptingCommandsTest.java index acee2cf..0a059cd 100644 --- a/src/test/java/redis/clients/jedis/tests/commands/ScriptingCommandsTest.java +++ b/src/test/java/redis/clients/jedis/tests/commands/ScriptingCommandsTest.java @@ -132,7 +132,7 @@ public class ScriptingCommandsTest extends JedisCommandTestBase { jedis.scriptKill(); } catch(JedisDataException e) { - assertEquals("ERR No scripts in execution right now.", e.getMessage()); + assertTrue(e.getMessage().contains("No scripts in execution right now.")); } } } \ No newline at end of file diff --git a/src/test/java/redis/clients/jedis/tests/commands/StringValuesCommandsTest.java b/src/test/java/redis/clients/jedis/tests/commands/StringValuesCommandsTest.java index fcf9f99..6b19d32 100644 --- a/src/test/java/redis/clients/jedis/tests/commands/StringValuesCommandsTest.java +++ b/src/test/java/redis/clients/jedis/tests/commands/StringValuesCommandsTest.java @@ -123,6 +123,22 @@ public class StringValuesCommandsTest extends JedisCommandTestBase { assertEquals(4, value); } + @Test(expected = JedisDataException.class) + public void incrByFloatWrongValue() { + jedis.set("foo", "bar"); + jedis.incrByFloat("foo", 2d); + } + + @Test + public void incrByFloat() { + Double value = jedis.incrByFloat("foo", 2d); + assertEquals((Double)2d, value); + value = jedis.incrByFloat("foo", 2.5d); + assertEquals((Double)4.5d, value); + value = jedis.incrByFloat("foo", -6.5d); + assertEquals(Double.compare(-2d, value), 0); + } + @Test(expected = JedisDataException.class) public void decrWrongValue() { jedis.set("foo", "bar");