Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

```

Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.redislabs</groupId>
<artifactId>jrejson</artifactId>
<version>1.0.0</version>
<version>1.1.0-SNAPSHOT</version>

<name>JReJSON</name>
<description>Official client for ReJSON</description>
Expand Down
237 changes: 225 additions & 12 deletions src/main/java/com/redislabs/modules/rejson/JReJSON.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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"),
Expand Down Expand Up @@ -77,6 +80,34 @@ public byte[] getRaw() {
}
}

private Pool<Jedis> 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> jedis) {
this.client = jedis;
}

/**
* Helper to check for errors and throw them as an exception
* @param str the reply string to "analyze"
Expand All @@ -103,27 +134,197 @@ 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<byte[]> 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<byte[]> 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
* @param conn the Jedis connection
* @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<byte[]> args = new ArrayList(2);
List<byte[]> args = new ArrayList<>(2);

args.add(SafeEncoder.encode(key));
args.add(SafeEncoder.encode(getSingleOptionalPath(path).toString()));
Expand All @@ -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<byte[]> args = new ArrayList(2);
List<byte[]> args = new ArrayList<>(2);

args.add(SafeEncoder.encode(key));
for (Path p :paths) {
Expand All @@ -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<byte[]> args = new ArrayList(4);
List<byte[]> args = new ArrayList<>(4);

args.add(SafeEncoder.encode(key));
args.add(SafeEncoder.encode(getSingleOptionalPath(path).toString()));
Expand All @@ -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);
}
Expand All @@ -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<byte[]> args = new ArrayList(2);
List<byte[]> args = new ArrayList<>(2);

args.add(SafeEncoder.encode(key));
args.add(SafeEncoder.encode(getSingleOptionalPath(path).toString()));
Expand Down Expand Up @@ -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();
}
}
7 changes: 5 additions & 2 deletions src/main/java/com/redislabs/modules/rejson/Path.java
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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(".");
}
Expand Down
Loading