diff --git a/README.md b/README.md index 62fb650..53847c5 100644 --- a/README.md +++ b/README.md @@ -61,24 +61,24 @@ import redis.clients.jedis.Jedis; import com.redislabs.modules.rejson.JReJSON; // First get a connection -Jedis jedis = new Jedis("localhost", 6379); +JReJSON client = new JReJSON("localhost", 6379); // Setting a Redis key name _foo_ to the string _"bar"_, and reading it back -JReJSON.set(jedis,"foo", "bar"); -String s0 = (String) JReJSON.get(jedis,"foo"); +client.set("foo", "bar"); +String s0 = (String) client.get("foo"); // Omitting the path (usually) defaults to the root path, so the call above to // `get()` and the following ones // are basically interchangeable -String s1 = (String) JReJSON.get(jedis,"foo", new Path(".")); -String s2 = (String) JReJSON.get(jedis, "foo", Path.RootPath()); +String s1 = (String) client.get("foo", new Path(".")); +String s2 = (String) client.get("foo", Path.ROOT_PATH); // Any Gson-able object can be set and updated -JReJSON.set(jedis,"obj", new Object()); // just an empty object -JReJSON.set(jedis,"obj", null, new Path(".zilch")); +client.set("obj", new Object()); // just an empty object +client.set("obj", null, new Path(".zilch")); Path p = new Path(".whatevs"); -JReJSON.set(jedis,"obj", true, p); -JReJSON.set(jedis,"obj", 42, p); -JReJSON.del(jedis,"obj", p); // back to almost nothing +client.set("obj", true, p); +client.set("obj", 42, p); +client.del("obj", p); // back to almost nothing ``` diff --git a/pom.xml b/pom.xml index 906d2a5..6c7d509 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.redislabs jrejson - 1.0.0 + 1.1.0-SNAPSHOT JReJSON Official client for ReJSON diff --git a/src/main/java/com/redislabs/modules/rejson/JReJSON.java b/src/main/java/com/redislabs/modules/rejson/JReJSON.java index c399ab9..72d6714 100644 --- a/src/main/java/com/redislabs/modules/rejson/JReJSON.java +++ b/src/main/java/com/redislabs/modules/rejson/JReJSON.java @@ -29,8 +29,11 @@ package com.redislabs.modules.rejson; import com.google.gson.Gson; + import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisPool; import redis.clients.jedis.commands.ProtocolCommand; +import redis.clients.jedis.util.Pool; import redis.clients.jedis.util.SafeEncoder; import java.util.ArrayList; @@ -41,7 +44,7 @@ */ public class JReJSON { - private static Gson gson = new Gson(); + private static final Gson gson = new Gson(); private enum Command implements ProtocolCommand { DEL("JSON.DEL"), @@ -77,6 +80,34 @@ public byte[] getRaw() { } } + private Pool client; + + /** + * Creates a client to the local machine + */ + public JReJSON() { + this("localhost", 6379); + } + + /** + * Creates a client to the specific host/post + * + * @param host Redis host + * @param port Redis port + */ + public JReJSON(String host, int port) { + this(new JedisPool(host, port)); + } + + /** + * Creates a client using provided Jedis pool + * + * @param jedis bring your own Jedis pool + */ + public JReJSON(Pool jedis) { + this.client = jedis; + } + /** * Helper to check for errors and throw them as an exception * @param str the reply string to "analyze" @@ -103,16 +134,184 @@ private static void assertReplyOK(final String str) { */ private static Path getSingleOptionalPath(Path... path) { // check for 0, 1 or more paths - if (1 > path.length) - // default to root + if (1 > path.length) { // default to root return Path.RootPath(); - else if (1 == path.length) - // take 1 + } + if (1 == path.length) { // take 1 return path[0]; - else - // throw out the baby with the water - throw new RuntimeException("Only a single optional path is allowed"); + } + + // throw out the baby with the water + throw new RuntimeException("Only a single optional path is allowed"); + } + + /** + * Deletes the root path + * @param key the key name + * @return the number of paths deleted (0 or 1) + */ + public Long del(String key) { + return del(key, Path.ROOT_PATH); + } + + + /** + * Deletes a path + * @param key the key name + * @param path optional single path in the object, defaults to root + * @return path deleted + */ + public Long del(String key, Path path) { + byte[][] args = new byte[2][]; + args[0] = SafeEncoder.encode(key); + args[1] = SafeEncoder.encode(path.toString()); + + try (Jedis conn = getConnection()) { + conn.getClient().sendCommand(Command.DEL, args); + return conn.getClient().getIntegerReply(); + } + } + + /** + * Gets an object at the root path + * @param key the key name + * @return the requested object + */ + public Object get(String key) { + return get(key, Path.ROOT_PATH); + } + + /** + * Gets an object + * @param key the key name + * @param paths optional one ore more paths in the object + * @return the requested object + */ + public Object get(String key, Path... paths) { + byte[][] args = new byte[1 + paths.length][]; + int i=0; + args[i] = SafeEncoder.encode(key); + for (Path p :paths) { + args[++i] = SafeEncoder.encode(p.toString()); + } + + String rep; + try (Jedis conn = getConnection()) { + conn.getClient().sendCommand(Command.GET, args); + rep = conn.getClient().getBulkReply(); + } + assertReplyNotError(rep); + return gson.fromJson(rep, Object.class); + } + + /** + * Sets an object at the root path + * @param key the key name + * @param object the Java object to store + * @param flag an existential modifier + */ + public void set(String key, Object object, ExistenceModifier flag) { + set(key, object, flag, Path.ROOT_PATH); + } + + /** + * Sets an object in the root path + * @param key the key name + * @param object the Java object to store + * @param path in the object + */ + public void set(String key, Object object) { + set(key, object, ExistenceModifier.DEFAULT, Path.ROOT_PATH); + } + + /** + * Sets an object without caring about target path existing + * @param key the key name + * @param object the Java object to store + * @param path in the object + */ + public void set(String key, Object object, Path path) { + set(key, object, ExistenceModifier.DEFAULT, path); + } + + /** + * Sets an object + * @param key the key name + * @param object the Java object to store + * @param flag an existential modifier + * @param path in the object + */ + public void set(String key, Object object, ExistenceModifier flag, Path path) { + + List args = new ArrayList<>(4); + + args.add(SafeEncoder.encode(key)); + args.add(SafeEncoder.encode(path.toString())); + args.add(SafeEncoder.encode(gson.toJson(object))); + if (ExistenceModifier.DEFAULT != flag) { + args.add(flag.getRaw()); + } + + String status; + try (Jedis conn = getConnection()) { + conn.getClient() + .sendCommand(Command.SET, args.toArray(new byte[args.size()][])); + status = conn.getClient().getStatusCodeReply(); + } + assertReplyOK(status); + } + + /** + * Gets the class of an object at the root path + * @param key the key name + * @return the Java class of the requested object + */ + public Class type(String key) { + return type(key); + } + + /** + * Gets the class of an object + * @param key the key name + * @param path a path in the object + * @return the Java class of the requested object + */ + public Class type(String key, Path path) { + + List args = new ArrayList<>(2); + + args.add(SafeEncoder.encode(key)); + args.add(SafeEncoder.encode(path.toString())); + + String rep; + try (Jedis conn = getConnection()) { + conn.getClient() + .sendCommand(Command.TYPE, args.toArray(new byte[args.size()][])); + rep = conn.getClient().getBulkReply(); + } + + assertReplyNotError(rep); + + switch (rep) { + case "null": + return null; + case "boolean": + return boolean.class; + case "integer": + return int.class; + case "number": + return float.class; + case "string": + return String.class; + case "object": + return Object.class; + case "array": + return List.class; + default: + throw new java.lang.RuntimeException(rep); + } } + /** * Deletes a path @@ -120,10 +319,12 @@ else if (1 == path.length) * @param key the key name * @param path optional single path in the object, defaults to root * @return the number of paths deleted (0 or 1) + * @deprecated use {@link #del(String, Path...)} instead */ + @Deprecated public static Long del(Jedis conn, String key, Path... path) { - List args = new ArrayList(2); + List args = new ArrayList<>(2); args.add(SafeEncoder.encode(key)); args.add(SafeEncoder.encode(getSingleOptionalPath(path).toString())); @@ -142,10 +343,12 @@ public static Long del(Jedis conn, String key, Path... path) { * @param key the key name * @param paths optional one ore more paths in the object, defaults to root * @return the requested object + * @deprecated use {@link #get(String, Path...)} instead */ + @Deprecated public static Object get(Jedis conn, String key, Path... paths) { - List args = new ArrayList(2); + List args = new ArrayList<>(2); args.add(SafeEncoder.encode(key)); for (Path p :paths) { @@ -168,10 +371,12 @@ public static Object get(Jedis conn, String key, Path... paths) { * @param object the Java object to store * @param flag an existential modifier * @param path optional single path in the object, defaults to root + * @deprecated use {@link #set(String, Object, ExistenceModifier, Path...)} instead */ + @Deprecated public static void set(Jedis conn, String key, Object object, ExistenceModifier flag, Path... path) { - List args = new ArrayList(4); + List args = new ArrayList<>(4); args.add(SafeEncoder.encode(key)); args.add(SafeEncoder.encode(getSingleOptionalPath(path).toString())); @@ -194,7 +399,9 @@ public static void set(Jedis conn, String key, Object object, ExistenceModifier * @param key the key name * @param object the Java object to store * @param path optional single path in the object, defaults to root + * @deprecated use {@link #set(String, Object, ExistenceModifier, Path...)} instead */ + @Deprecated public static void set(Jedis conn, String key, Object object, Path... path) { set(conn,key, object, ExistenceModifier.DEFAULT, path); } @@ -205,10 +412,12 @@ public static void set(Jedis conn, String key, Object object, Path... path) { * @param key the key name * @param path optional single path in the object, defaults to root * @return the Java class of the requested object + * @deprecated use {@link #type(String, Path...)} instead */ + @Deprecated public static Class type(Jedis conn, String key, Path... path) { - List args = new ArrayList(2); + List args = new ArrayList<>(2); args.add(SafeEncoder.encode(key)); args.add(SafeEncoder.encode(getSingleOptionalPath(path).toString())); @@ -239,4 +448,8 @@ public static Class type(Jedis conn, String key, Path... path) { throw new java.lang.RuntimeException(rep); } } + + private Jedis getConnection() { + return this.client.getResource(); + } } diff --git a/src/main/java/com/redislabs/modules/rejson/Path.java b/src/main/java/com/redislabs/modules/rejson/Path.java index bd04856..b6be6d2 100644 --- a/src/main/java/com/redislabs/modules/rejson/Path.java +++ b/src/main/java/com/redislabs/modules/rejson/Path.java @@ -30,10 +30,11 @@ /** * Path is a ReJSON path, representing a valid path into an object - * TODO: make path building even more fun */ - public class Path { + + public static final Path ROOT_PATH = new Path("."); + private final String strPath; public Path(final String strPath) { @@ -43,7 +44,9 @@ public Path(final String strPath) { /** * Makes a root path * @return the root path + * @deprecated use {@value #ROOT_PATH} instead */ + @Deprecated public static Path RootPath() { return new Path("."); } diff --git a/src/test/java/com/redislabs/modules/rejson/ClientTest.java b/src/test/java/com/redislabs/modules/rejson/ClientTest.java index 6ea98a5..7df7219 100644 --- a/src/test/java/com/redislabs/modules/rejson/ClientTest.java +++ b/src/test/java/com/redislabs/modules/rejson/ClientTest.java @@ -29,6 +29,7 @@ package com.redislabs.modules.rejson; import com.google.gson.Gson; + import org.junit.Before; import org.junit.Test; import redis.clients.jedis.Jedis; @@ -56,157 +57,124 @@ public FooBarObject() { } } - private Gson g; - private String host="localhost"; - private int port=6379; - Jedis jedis = new Jedis(host,port); - + private final Gson g = new Gson(); + private final JReJSON client = new JReJSON("localhost",6379); + private final Jedis jedis = new Jedis("localhost",6379); + @Before - public void initialize() { - g = new Gson(); + public void cleanup() { + jedis.flushDB(); } - + @Test public void basicSetGetShouldSucceed() throws Exception { // naive set with a path - JReJSON.set(jedis, "null", null, Path.RootPath()); - assertNull(JReJSON.get(jedis, "null", Path.RootPath())); + client.set("null", null, Path.ROOT_PATH); + assertNull(client.get("null", Path.ROOT_PATH)); // real scalar value and no path - JReJSON.set(jedis, "str", "strong"); - assertEquals("strong", JReJSON.get(jedis, "str")); + client.set( "str", "strong"); + assertEquals("strong", client.get( "str")); // a slightly more complex object IRLObject obj = new IRLObject(); - JReJSON.set(jedis, "obj", obj); + client.set( "obj", obj); Object expected = g.fromJson(g.toJson(obj), Object.class); - assertTrue(expected.equals(JReJSON.get(jedis, "obj"))); + assertTrue(expected.equals(client.get( "obj"))); // check an update Path p = new Path(".str"); - JReJSON.set(jedis, "obj", "strung", p); - assertEquals("strung", JReJSON.get(jedis, "obj", p)); + client.set( "obj", "strung", p); + assertEquals("strung", client.get( "obj", p)); } @Test public void setExistingPathOnlyIfExistsShouldSucceed() throws Exception { - jedis.flushDB(); - - JReJSON.set(jedis, "obj", new IRLObject()); + client.set( "obj", new IRLObject()); Path p = new Path(".str"); - JReJSON.set(jedis, "obj", "strangle", JReJSON.ExistenceModifier.MUST_EXIST, p); - assertEquals("strangle", JReJSON.get(jedis, "obj", p)); + client.set( "obj", "strangle", JReJSON.ExistenceModifier.MUST_EXIST, p); + assertEquals("strangle", client.get( "obj", p)); } @Test public void setNonExistingOnlyIfNotExistsShouldSucceed() throws Exception { - jedis.flushDB(); - - JReJSON.set(jedis, "obj", new IRLObject()); + client.set( "obj", new IRLObject()); Path p = new Path(".none"); - JReJSON.set(jedis, "obj", "strangle", JReJSON.ExistenceModifier.NOT_EXISTS, p); - assertEquals("strangle", JReJSON.get(jedis, "obj", p)); + client.set( "obj", "strangle", JReJSON.ExistenceModifier.NOT_EXISTS, p); + assertEquals("strangle", client.get( "obj", p)); } @Test(expected = Exception.class) public void setExistingPathOnlyIfNotExistsShouldFail() throws Exception { - jedis.flushDB(); - - JReJSON.set(jedis, "obj", new IRLObject()); + client.set( "obj", new IRLObject()); Path p = new Path(".str"); - JReJSON.set(jedis, "obj", "strangle", JReJSON.ExistenceModifier.NOT_EXISTS, p); + client.set( "obj", "strangle", JReJSON.ExistenceModifier.NOT_EXISTS, p); } @Test(expected = Exception.class) public void setNonExistingPathOnlyIfExistsShouldFail() throws Exception { - jedis.flushDB(); - - JReJSON.set(jedis, "obj", new IRLObject()); + client.set( "obj", new IRLObject()); Path p = new Path(".none"); - JReJSON.set(jedis, "obj", "strangle", JReJSON.ExistenceModifier.MUST_EXIST, p); + client.set( "obj", "strangle", JReJSON.ExistenceModifier.MUST_EXIST, p); } @Test(expected = Exception.class) public void setException() throws Exception { - jedis.flushDB(); - // should error on non root path for new key - JReJSON.set(jedis, "test", "bar", new Path(".foo")); - } - - @Test(expected = Exception.class) - public void setMultiplePathsShouldFail() throws Exception { - jedis.flushDB(); - JReJSON.set(jedis, "obj", new IRLObject()); - JReJSON.set(jedis, "obj", "strange", new Path(".str"), new Path(".str")); + client.set( "test", "bar", new Path(".foo")); } @Test public void getMultiplePathsShouldSucceed() throws Exception { - jedis.flushDB(); - // check multiple paths IRLObject obj = new IRLObject(); - JReJSON.set(jedis, "obj", obj); + client.set( "obj", obj); Object expected = g.fromJson(g.toJson(obj), Object.class); - assertTrue(expected.equals(JReJSON.get(jedis, "obj", new Path("bTrue"), new Path("str")))); + assertTrue(expected.equals(client.get( "obj", new Path("bTrue"), new Path("str")))); } @Test(expected = Exception.class) public void getException() throws Exception { - jedis.flushDB(); - JReJSON.set(jedis, "test", "foo", Path.RootPath()); - JReJSON.get(jedis, "test", new Path(".bar")); + client.set( "test", "foo", Path.ROOT_PATH); + client.get( "test", new Path(".bar")); } @Test public void delValidShouldSucceed() throws Exception { - jedis.flushDB(); - // check deletion of a single path - JReJSON.set(jedis, "obj", new IRLObject(), Path.RootPath()); - JReJSON.del(jedis, "obj", new Path(".str")); + client.set( "obj", new IRLObject(), Path.ROOT_PATH); + client.del( "obj", new Path(".str")); assertTrue(jedis.exists("obj")); // check deletion root using default root -> key is removed - JReJSON.del(jedis, "obj"); + client.del( "obj"); assertFalse(jedis.exists("obj")); } @Test(expected = Exception.class) public void delException() throws Exception { - jedis.flushDB(); - JReJSON.set(jedis, "foobar", new FooBarObject(), Path.RootPath()); - JReJSON.del(jedis, "foobar", new Path(".foo[1]")); - } - - @Test(expected = Exception.class) - public void delMultiplePathsShoudFail() throws Exception { - jedis.flushDB(); - JReJSON.del(jedis, "foobar", new Path(".foo"), new Path(".bar")); + client.set( "foobar", new FooBarObject(), Path.ROOT_PATH); + client.del( "foobar", new Path(".foo[1]")); } @Test public void typeChecksShouldSucceed() throws Exception { - jedis.flushDB(); - JReJSON.set(jedis, "foobar", new FooBarObject(), Path.RootPath()); - assertSame(Object.class, JReJSON.type(jedis, "foobar", Path.RootPath())); - assertSame(String.class, JReJSON.type(jedis, "foobar", new Path(".foo"))); + client.set( "foobar", new FooBarObject(), Path.ROOT_PATH); + assertSame(Object.class, client.type( "foobar", Path.ROOT_PATH)); + assertSame(String.class, client.type( "foobar", new Path(".foo"))); } @Test(expected = Exception.class) public void typeException() throws Exception { - jedis.flushDB(); - JReJSON.set(jedis, "foobar", new FooBarObject(), Path.RootPath()); - JReJSON.type(jedis, "foobar", new Path(".foo[1]")); + client.set( "foobar", new FooBarObject(), Path.ROOT_PATH); + client.type( "foobar", new Path(".foo[1]")); } @Test(expected = Exception.class) public void type1Exception() throws Exception { - jedis.flushDB(); - JReJSON.set(jedis, "foobar", new FooBarObject(), Path.RootPath()); - JReJSON.type(jedis, "foobar", new Path(".foo[1]")); + client.set( "foobar", new FooBarObject(), Path.ROOT_PATH); + client.type( "foobar", new Path(".foo[1]")); } } \ No newline at end of file diff --git a/src/test/java/com/redislabs/modules/rejson/StaticClientTest.java b/src/test/java/com/redislabs/modules/rejson/StaticClientTest.java new file mode 100644 index 0000000..dfb6c2e --- /dev/null +++ b/src/test/java/com/redislabs/modules/rejson/StaticClientTest.java @@ -0,0 +1,212 @@ +/* + * BSD 2-Clause License + * + * Copyright (c) 2017, Redis Labs + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.redislabs.modules.rejson; + +import com.google.gson.Gson; +import org.junit.Before; +import org.junit.Test; +import redis.clients.jedis.Jedis; + +import static junit.framework.TestCase.*; + +public class StaticClientTest { + + /* A simple class that represents an object in real life */ + private static class IRLObject { + public String str; + public boolean bTrue; + + public IRLObject() { + this.str = "string"; + this.bTrue = true; + } + } + + private static class FooBarObject { + public String foo; + + public FooBarObject() { + this.foo = "bar"; + } + } + + private Gson g; + private String host="localhost"; + private int port=6379; + Jedis jedis = new Jedis(host,port); + + @Before + public void initialize() { + g = new Gson(); + } + + @Test + public void basicSetGetShouldSucceed() throws Exception { + + // naive set with a path + JReJSON.set(jedis, "null", null, Path.RootPath()); + assertNull(JReJSON.get(jedis, "null", Path.RootPath())); + + // real scalar value and no path + JReJSON.set(jedis, "str", "strong"); + assertEquals("strong", JReJSON.get(jedis, "str")); + + // a slightly more complex object + IRLObject obj = new IRLObject(); + JReJSON.set(jedis, "obj", obj); + Object expected = g.fromJson(g.toJson(obj), Object.class); + assertTrue(expected.equals(JReJSON.get(jedis, "obj"))); + + // check an update + Path p = new Path(".str"); + JReJSON.set(jedis, "obj", "strung", p); + assertEquals("strung", JReJSON.get(jedis, "obj", p)); + } + + @Test + public void setExistingPathOnlyIfExistsShouldSucceed() throws Exception { + jedis.flushDB(); + + JReJSON.set(jedis, "obj", new IRLObject()); + Path p = new Path(".str"); + JReJSON.set(jedis, "obj", "strangle", JReJSON.ExistenceModifier.MUST_EXIST, p); + assertEquals("strangle", JReJSON.get(jedis, "obj", p)); + } + + @Test + public void setNonExistingOnlyIfNotExistsShouldSucceed() throws Exception { + jedis.flushDB(); + + JReJSON.set(jedis, "obj", new IRLObject()); + Path p = new Path(".none"); + JReJSON.set(jedis, "obj", "strangle", JReJSON.ExistenceModifier.NOT_EXISTS, p); + assertEquals("strangle", JReJSON.get(jedis, "obj", p)); + } + + @Test(expected = Exception.class) + public void setExistingPathOnlyIfNotExistsShouldFail() throws Exception { + jedis.flushDB(); + + JReJSON.set(jedis, "obj", new IRLObject()); + Path p = new Path(".str"); + JReJSON.set(jedis, "obj", "strangle", JReJSON.ExistenceModifier.NOT_EXISTS, p); + } + + @Test(expected = Exception.class) + public void setNonExistingPathOnlyIfExistsShouldFail() throws Exception { + jedis.flushDB(); + + JReJSON.set(jedis, "obj", new IRLObject()); + Path p = new Path(".none"); + JReJSON.set(jedis, "obj", "strangle", JReJSON.ExistenceModifier.MUST_EXIST, p); + } + + @Test(expected = Exception.class) + public void setException() throws Exception { + jedis.flushDB(); + + // should error on non root path for new key + JReJSON.set(jedis, "test", "bar", new Path(".foo")); + } + + @Test(expected = Exception.class) + public void setMultiplePathsShouldFail() throws Exception { + jedis.flushDB(); + JReJSON.set(jedis, "obj", new IRLObject()); + JReJSON.set(jedis, "obj", "strange", new Path(".str"), new Path(".str")); + } + + @Test + public void getMultiplePathsShouldSucceed() throws Exception { + jedis.flushDB(); + + // check multiple paths + IRLObject obj = new IRLObject(); + JReJSON.set(jedis, "obj", obj); + Object expected = g.fromJson(g.toJson(obj), Object.class); + assertTrue(expected.equals(JReJSON.get(jedis, "obj", new Path("bTrue"), new Path("str")))); + + } + + @Test(expected = Exception.class) + public void getException() throws Exception { + jedis.flushDB(); + JReJSON.set(jedis, "test", "foo", Path.RootPath()); + JReJSON.get(jedis, "test", new Path(".bar")); + } + + @Test + public void delValidShouldSucceed() throws Exception { + jedis.flushDB(); + + // check deletion of a single path + JReJSON.set(jedis, "obj", new IRLObject(), Path.RootPath()); + JReJSON.del(jedis, "obj", new Path(".str")); + assertTrue(jedis.exists("obj")); + + // check deletion root using default root -> key is removed + JReJSON.del(jedis, "obj"); + assertFalse(jedis.exists("obj")); + } + + @Test(expected = Exception.class) + public void delException() throws Exception { + jedis.flushDB(); + JReJSON.set(jedis, "foobar", new FooBarObject(), Path.RootPath()); + JReJSON.del(jedis, "foobar", new Path(".foo[1]")); + } + + @Test(expected = Exception.class) + public void delMultiplePathsShoudFail() throws Exception { + jedis.flushDB(); + JReJSON.del(jedis, "foobar", new Path(".foo"), new Path(".bar")); + } + + @Test + public void typeChecksShouldSucceed() throws Exception { + jedis.flushDB(); + JReJSON.set(jedis, "foobar", new FooBarObject(), Path.RootPath()); + assertSame(Object.class, JReJSON.type(jedis, "foobar", Path.RootPath())); + assertSame(String.class, JReJSON.type(jedis, "foobar", new Path(".foo"))); + } + + @Test(expected = Exception.class) + public void typeException() throws Exception { + jedis.flushDB(); + JReJSON.set(jedis, "foobar", new FooBarObject(), Path.RootPath()); + JReJSON.type(jedis, "foobar", new Path(".foo[1]")); + } + + @Test(expected = Exception.class) + public void type1Exception() throws Exception { + jedis.flushDB(); + JReJSON.set(jedis, "foobar", new FooBarObject(), Path.RootPath()); + JReJSON.type(jedis, "foobar", new Path(".foo[1]")); + } +} \ No newline at end of file