From 9dc89626acd935af65460c0ebd071c245e68328a Mon Sep 17 00:00:00 2001 From: Ivo Ramirez Date: Thu, 15 Dec 2011 15:51:45 +0100 Subject: [PATCH] Eval and Evalsha is now supported Conflicts: src/main/java/redis/clients/jedis/Client.java src/main/java/redis/clients/jedis/Jedis.java --- .../redis/clients/jedis/BinaryClient.java | 26 +++++++ .../java/redis/clients/jedis/BinaryJedis.java | 22 ++++++ .../clients/jedis/BinaryJedisCommands.java | 1 + .../clients/jedis/BinaryShardedJedis.java | 1 + src/main/java/redis/clients/jedis/Client.java | 26 +++++++ .../java/redis/clients/jedis/Connection.java | 2 +- src/main/java/redis/clients/jedis/Jedis.java | 55 +++++++++++++- .../java/redis/clients/jedis/Protocol.java | 2 +- .../tests/commands/EvalCommandsTest.java | 76 +++++++++++++++++++ 9 files changed, 207 insertions(+), 4 deletions(-) create mode 100644 src/test/java/redis/clients/jedis/tests/commands/EvalCommandsTest.java diff --git a/src/main/java/redis/clients/jedis/BinaryClient.java b/src/main/java/redis/clients/jedis/BinaryClient.java index 812defe..9292b21 100644 --- a/src/main/java/redis/clients/jedis/BinaryClient.java +++ b/src/main/java/redis/clients/jedis/BinaryClient.java @@ -718,4 +718,30 @@ public class BinaryClient extends Connection { db = 0; super.disconnect(); } + + private void sendEvalCommand(Command command, byte[] script, List keys, List args){ + int keysSize = keys.size(); + int argsSize = args.size(); + + final byte[][] allArgs = new byte[keysSize + argsSize + 2][]; + + allArgs[0] = script; + allArgs[1] =toByteArray(keysSize); + + for(int i=0;i keys, List args){ + sendEvalCommand(EVAL, script, keys, args ); + } + + public void evalsha(byte[] sha1, List keys, List args){ + sendEvalCommand(EVALSHA, sha1, keys, args); + } } diff --git a/src/main/java/redis/clients/jedis/BinaryJedis.java b/src/main/java/redis/clients/jedis/BinaryJedis.java index 7b4cd30..de27283 100644 --- a/src/main/java/redis/clients/jedis/BinaryJedis.java +++ b/src/main/java/redis/clients/jedis/BinaryJedis.java @@ -3006,4 +3006,26 @@ public class BinaryJedis implements BinaryJedisCommands { public Long getDB() { return client.getDB(); } + + /** + * Evaluates scripts using the Lua interpreter built into Redis starting from version 2.6.0. + *

+ * + * @return Script result + */ + public Object eval(byte[] script, List keys, List args) { + client.setTimeoutInfinite(); + client.eval(script, keys, args); + return client.getOne(); + } + + /** + * Evaluates scripts using the Lua interpreter built into Redis starting from version 2.6.0. + *

+ * + * @return Script result + */ + public Object eval(byte[] script, List keys) { + return eval(script,keys, new ArrayList()); + } } diff --git a/src/main/java/redis/clients/jedis/BinaryJedisCommands.java b/src/main/java/redis/clients/jedis/BinaryJedisCommands.java index ef8aebd..c8479df 100644 --- a/src/main/java/redis/clients/jedis/BinaryJedisCommands.java +++ b/src/main/java/redis/clients/jedis/BinaryJedisCommands.java @@ -154,4 +154,5 @@ public interface BinaryJedisCommands { Long zremrangeByScore(byte[] key, double start, double end); Long linsert(byte[] key, LIST_POSITION where, byte[] pivot, byte[] value); + } diff --git a/src/main/java/redis/clients/jedis/BinaryShardedJedis.java b/src/main/java/redis/clients/jedis/BinaryShardedJedis.java index 9c1abd2..41306c9 100644 --- a/src/main/java/redis/clients/jedis/BinaryShardedJedis.java +++ b/src/main/java/redis/clients/jedis/BinaryShardedJedis.java @@ -5,6 +5,7 @@ import redis.clients.util.Hashing; import redis.clients.util.Sharded; import java.io.IOException; +import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; diff --git a/src/main/java/redis/clients/jedis/Client.java b/src/main/java/redis/clients/jedis/Client.java index 1f493e0..c69f9a1 100644 --- a/src/main/java/redis/clients/jedis/Client.java +++ b/src/main/java/redis/clients/jedis/Client.java @@ -2,7 +2,9 @@ package redis.clients.jedis; import redis.clients.util.SafeEncoder; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -595,4 +597,28 @@ public class Client extends BinaryClient implements Commands { public void configGet(String pattern) { configGet(SafeEncoder.encode(pattern)); } + + public void eval(String script, List keys, String... args) { + List k = new ArrayList(); + for(String key:keys){ + k.add(SafeEncoder.encode(key)); + } + List a = new ArrayList(); + for(String arg:args){ + a.add(SafeEncoder.encode(arg)); + } + eval(SafeEncoder.encode(script),k,a); + } + + public void evalsha(String sha1, List keys, String... args) { + List k = new ArrayList(); + for(String key:keys){ + k.add(SafeEncoder.encode(key)); + } + List a = new ArrayList(); + for(String arg:args){ + a.add(SafeEncoder.encode(arg)); + } + evalsha(SafeEncoder.encode(sha1),k,a); + } } diff --git a/src/main/java/redis/clients/jedis/Connection.java b/src/main/java/redis/clients/jedis/Connection.java index 0ea973f..67a7dd6 100644 --- a/src/main/java/redis/clients/jedis/Connection.java +++ b/src/main/java/redis/clients/jedis/Connection.java @@ -82,7 +82,7 @@ public class Connection { pipelinedCommands++; return this; } - + protected Connection sendCommand(final Command cmd) { connect(); protocol.sendCommand(outputStream, cmd, new byte[0][]); diff --git a/src/main/java/redis/clients/jedis/Jedis.java b/src/main/java/redis/clients/jedis/Jedis.java index c71d9aa..9281ff3 100644 --- a/src/main/java/redis/clients/jedis/Jedis.java +++ b/src/main/java/redis/clients/jedis/Jedis.java @@ -8,7 +8,10 @@ import java.util.List; import java.util.Map; import java.util.Set; +import org.hamcrest.core.IsInstanceOf; + import redis.clients.jedis.BinaryClient.LIST_POSITION; +import redis.clients.util.SafeEncoder; public class Jedis extends BinaryJedis implements JedisCommands { public Jedis(final String host) { @@ -2688,5 +2691,53 @@ public class Jedis extends BinaryJedis implements JedisCommands { public String configSet(final String parameter, final String value) { client.configSet(parameter, value); return client.getStatusCodeReply(); - } -} + } + + public Object eval(String script, String... keys) { + List s = new ArrayList(keys.length); + for(String key : keys) + s.add(key); + + return eval(script, s); + } + + public Object eval(String script, List keys, String... args) { + client.setTimeoutInfinite(); + client.eval(script, keys, args); + + return getEvalResult(); + } + + private Object getEvalResult(){ + Object result = client.getOne(); + + if(result instanceof byte[]) + return SafeEncoder.encode((byte[])result); + + if(result instanceof List) { + List list = (List)result; + List listResult = new ArrayList(list.size()); + for(Object bin: list) + listResult.add(SafeEncoder.encode((byte[])bin)); + + return listResult; + } + + return result; + } + + public Object evalsha(String sha1, String... keys) { + List s = new ArrayList(keys.length); + for(String key : keys) + s.add(key); + + return evalsha(sha1, s); + } + + public Object evalsha(String sha1, List keys, String... args) { + checkIsInMulti(); + client.evalsha(sha1, keys, args); + + return getEvalResult(); + } +} \ No newline at end of file diff --git a/src/main/java/redis/clients/jedis/Protocol.java b/src/main/java/redis/clients/jedis/Protocol.java index a4f1c7e..dc43e16 100644 --- a/src/main/java/redis/clients/jedis/Protocol.java +++ b/src/main/java/redis/clients/jedis/Protocol.java @@ -140,7 +140,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; + 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; public final byte[] raw; diff --git a/src/test/java/redis/clients/jedis/tests/commands/EvalCommandsTest.java b/src/test/java/redis/clients/jedis/tests/commands/EvalCommandsTest.java new file mode 100644 index 0000000..adcccf9 --- /dev/null +++ b/src/test/java/redis/clients/jedis/tests/commands/EvalCommandsTest.java @@ -0,0 +1,76 @@ +package redis.clients.jedis.tests.commands; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; + +import redis.clients.jedis.exceptions.JedisDataException; +import redis.clients.jedis.exceptions.JedisException; + +public class EvalCommandsTest extends JedisCommandTestBase { + + @SuppressWarnings("unchecked") + @Test + public void evalMultiBulk() { + String script = "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}"; + List keys = new ArrayList(); + keys.add("key1"); + keys.add("key2"); + + List response = (List)jedis.eval(script, keys, "first", "second" ); + + assertEquals(4, response.size()); + assertEquals("key1", response.get(0)); + assertEquals("key2", response.get(1)); + assertEquals("first", response.get(2)); + assertEquals("second", response.get(3)); + } + + @Test + public void evalBulk() { + String script = "return KEYS[1]"; + List keys = new ArrayList(); + keys.add("key1"); + + String response = (String)jedis.eval(script, keys); + + assertEquals("key1", response); + } + + @Test + public void evalInt() { + String script = "return 2"; + List keys = new ArrayList(); + keys.add("key1"); + + Long response = (Long)jedis.eval(script, keys); + + assertEquals(new Long(2), response); + } + + @Test + public void evalNoArgs() { + String script = "return KEYS[1]"; + + String response = (String)jedis.eval(script, "key1"); + + assertEquals("key1", response); + } + + @SuppressWarnings("unchecked") + @Test + public void evalsha() { + jedis.set("foo", "bar"); + jedis.eval("return redis.call('get','foo')"); + String result = (String)jedis.evalsha("6b1bf486c81ceb7edf3c093f4c48582e38c0e791"); + + assertEquals("bar", result); + } + + @SuppressWarnings("unchecked") + @Test(expected=JedisDataException.class) + public void evalshaShaNotFound() { + Exception result = (Exception)jedis.evalsha("ffffffffffffffffffffffffffffffffffffffff"); + } +} \ No newline at end of file