diff --git a/src/main/java/com/redislabs/redisgraph/exceptions/JRedisGraphCompileTimeException.java b/src/main/java/com/redislabs/redisgraph/exceptions/JRedisGraphCompileTimeException.java new file mode 100644 index 0000000..1574147 --- /dev/null +++ b/src/main/java/com/redislabs/redisgraph/exceptions/JRedisGraphCompileTimeException.java @@ -0,0 +1,21 @@ +package com.redislabs.redisgraph.exceptions; + +import redis.clients.jedis.exceptions.JedisDataException; + +/** + * RedisGraph query syntax evaluation exception. An instance of JRedisGraphRunTimeException is thrown when RedisGraph + * encounters an error during query syntax evaluation. + */ +public class JRedisGraphCompileTimeException extends JedisDataException { + public JRedisGraphCompileTimeException(String message) { + super(message); + } + + public JRedisGraphCompileTimeException(Throwable cause) { + super(cause); + } + + public JRedisGraphCompileTimeException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/com/redislabs/redisgraph/exceptions/JRedisGraphRunTimeException.java b/src/main/java/com/redislabs/redisgraph/exceptions/JRedisGraphRunTimeException.java new file mode 100644 index 0000000..62d083f --- /dev/null +++ b/src/main/java/com/redislabs/redisgraph/exceptions/JRedisGraphRunTimeException.java @@ -0,0 +1,21 @@ +package com.redislabs.redisgraph.exceptions; + +import redis.clients.jedis.exceptions.JedisDataException; + +/** + * RedisGraph runtime exception. An instance of JRedisGraphRunTimeException is thrown when RedisGraph + * encounters a runtime error during query execution. + */ +public class JRedisGraphRunTimeException extends JedisDataException { + public JRedisGraphRunTimeException(String message) { + super(message); + } + + public JRedisGraphRunTimeException(Throwable cause) { + super(cause); + } + + public JRedisGraphRunTimeException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/com/redislabs/redisgraph/impl/api/ContextedRedisGraph.java b/src/main/java/com/redislabs/redisgraph/impl/api/ContextedRedisGraph.java index b846925..ab92534 100644 --- a/src/main/java/com/redislabs/redisgraph/impl/api/ContextedRedisGraph.java +++ b/src/main/java/com/redislabs/redisgraph/impl/api/ContextedRedisGraph.java @@ -2,17 +2,19 @@ import com.redislabs.redisgraph.RedisGraphContext; import com.redislabs.redisgraph.ResultSet; +import com.redislabs.redisgraph.exceptions.JRedisGraphCompileTimeException; +import com.redislabs.redisgraph.exceptions.JRedisGraphRunTimeException; import com.redislabs.redisgraph.impl.Utils; import com.redislabs.redisgraph.impl.graph_cache.RedisGraphCaches; import com.redislabs.redisgraph.impl.resultset.ResultSetImpl; import redis.clients.jedis.Client; import redis.clients.jedis.Jedis; import redis.clients.jedis.util.SafeEncoder; - +import redis.clients.jedis.exceptions.JedisDataException; import java.util.List; /** - * An implementaion of RedisGraphContext. Allows sending RedisGraph and some Redis commands, + * An implementation of RedisGraphContext. Allows sending RedisGraph and some Redis commands, * within a specific connection context */ public class ContextedRedisGraph extends AbstractRedisGraph implements RedisGraphContext, RedisGraphCacheHolder { @@ -50,9 +52,11 @@ protected ResultSet sendQuery(String graphId, String preparedQuery) { List rawResponse = (List) conn.sendCommand(RedisGraphCommand.QUERY, graphId, preparedQuery, Utils.COMPACT_STRING); return new ResultSetImpl(rawResponse, this, caches.getGraphCache(graphId)); } - catch (Exception e) { - conn.close(); - throw e; + catch (JRedisGraphRunTimeException rt) { + throw rt; + } + catch (JedisDataException j) { + throw new JRedisGraphCompileTimeException(j); } } diff --git a/src/main/java/com/redislabs/redisgraph/impl/resultset/ResultSetImpl.java b/src/main/java/com/redislabs/redisgraph/impl/resultset/ResultSetImpl.java index 6fa57fb..fdcdf66 100644 --- a/src/main/java/com/redislabs/redisgraph/impl/resultset/ResultSetImpl.java +++ b/src/main/java/com/redislabs/redisgraph/impl/resultset/ResultSetImpl.java @@ -5,12 +5,14 @@ import com.redislabs.redisgraph.RedisGraph; import com.redislabs.redisgraph.ResultSet; import com.redislabs.redisgraph.Statistics; +import com.redislabs.redisgraph.exceptions.JRedisGraphRunTimeException; import com.redislabs.redisgraph.graph_entities.Edge; import com.redislabs.redisgraph.graph_entities.GraphEntity; import com.redislabs.redisgraph.graph_entities.Node; import com.redislabs.redisgraph.graph_entities.Property; import com.redislabs.redisgraph.impl.graph_cache.GraphCache; import redis.clients.jedis.util.SafeEncoder; +import redis.clients.jedis.exceptions.JedisDataException; import java.util.ArrayList; import java.util.List; @@ -35,6 +37,13 @@ public class ResultSetImpl implements ResultSet { public ResultSetImpl(List rawResponse, RedisGraph redisGraph, GraphCache cache) { this.redisGraph = redisGraph; this.cache = cache; + + // If a run-time error occured, the last member of the rawResponse will be a JedisDataException. + if (rawResponse.get(rawResponse.size()-1) instanceof JedisDataException) { + + throw new JRedisGraphRunTimeException((Throwable) rawResponse.get(rawResponse.size() - 1)); + } + if (rawResponse.size() != 3) { header = parseHeader(new ArrayList<>()); diff --git a/src/test/java/com/redislabs/redisgraph/RedisGraphAPITest.java b/src/test/java/com/redislabs/redisgraph/RedisGraphAPITest.java index e2be9e4..22cdf28 100644 --- a/src/test/java/com/redislabs/redisgraph/RedisGraphAPITest.java +++ b/src/test/java/com/redislabs/redisgraph/RedisGraphAPITest.java @@ -584,10 +584,6 @@ public void testMultiExec(){ Assert.assertEquals(Arrays.asList("n"), record.keys()); Assert.assertEquals(expectedNode, record.getValue("n")); - // Graph delete - Assert.assertTrue(((String)results.get(6)).startsWith("Graph removed")); - - Assert.assertEquals(ResultSetImpl.class, results.get(7).getClass()); resultSet = (ResultSet) results.get(7); @@ -881,4 +877,5 @@ record = resultSet.next(); } } + } diff --git a/src/test/java/com/redislabs/redisgraph/exceptions/JRedisGraphErrorTest.java b/src/test/java/com/redislabs/redisgraph/exceptions/JRedisGraphErrorTest.java new file mode 100644 index 0000000..5b0be9e --- /dev/null +++ b/src/test/java/com/redislabs/redisgraph/exceptions/JRedisGraphErrorTest.java @@ -0,0 +1,125 @@ +package com.redislabs.redisgraph.exceptions; + +import com.redislabs.redisgraph.RedisGraphContext; +import com.redislabs.redisgraph.RedisGraphContextGenerator; +import com.redislabs.redisgraph.impl.api.RedisGraph; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + + +public class JRedisGraphErrorTest { + + private RedisGraphContextGenerator api; + + @Before + public void createApi(){ + api = new RedisGraph(); + Assert.assertNotNull(api.query("social", "CREATE (:person{mixed_prop: 'strval'}), (:person{mixed_prop: 50})")); + } + @After + public void deleteGraph() { + + api.deleteGraph("social"); + api.close(); + } + + @Rule + public ExpectedException exceptionRule = ExpectedException.none(); + + @Test + public void testSyntaxErrorReporting() { + exceptionRule.expect(JRedisGraphCompileTimeException.class); + exceptionRule.expectMessage("Type mismatch: expected String but was Integer"); + + // Issue a query that causes a compile-time error + api.query("social", "RETURN toUpper(5)"); + + } + + @Test + public void testRuntimeErrorReporting() { + exceptionRule.expect(JRedisGraphRunTimeException.class); + exceptionRule.expectMessage("Type mismatch: expected String but was Integer"); + + // Issue a query that causes a run-time error + api.query("social", "MATCH (p:person) RETURN toUpper(p.mixed_prop)"); + } + + @Test + public void testExceptionFlow() { + + try { + // Issue a query that causes a compile-time error + api.query("social", "RETURN toUpper(5)"); + } + catch (Exception e) { + Assert.assertEquals(JRedisGraphCompileTimeException.class, e.getClass()); + Assert.assertTrue( e.getMessage().contains("Type mismatch: expected String but was Integer")); + } + + // On general api usage, user should get a new connection + + try { + // Issue a query that causes a compile-time error + api.query("social", "MATCH (p:person) RETURN toUpper(p.mixed_prop)"); + } + catch (Exception e) { + Assert.assertEquals(JRedisGraphRunTimeException.class, e.getClass()); + Assert.assertTrue( e.getMessage().contains("Type mismatch: expected String but was Integer")); + } + + } + + + @Test + public void testContextSyntaxErrorReporting() { + exceptionRule.expect(JRedisGraphCompileTimeException.class); + exceptionRule.expectMessage("Type mismatch: expected String but was Integer"); + RedisGraphContext c = api.getContext(); + + // Issue a query that causes a compile-time error + c.query("social", "RETURN toUpper(5)"); + + } + + @Test + public void testContextRuntimeErrorReporting() { + exceptionRule.expect(JRedisGraphRunTimeException.class); + exceptionRule.expectMessage("Type mismatch: expected String but was Integer"); + + RedisGraphContext c = api.getContext(); + // Issue a query that causes a run-time error + c.query("social", "MATCH (p:person) RETURN toUpper(p.mixed_prop)"); + } + + + @Test + public void testContextExceptionFlow() { + + RedisGraphContext c = api.getContext(); + try { + // Issue a query that causes a compile-time error + c.query("social", "RETURN toUpper(5)"); + } + catch (Exception e) { + Assert.assertEquals(JRedisGraphCompileTimeException.class, e.getClass()); + Assert.assertTrue( e.getMessage().contains("Type mismatch: expected String but was Integer")); + } + + // On contexted api usage, connection should stay open + + try { + // Issue a query that causes a compile-time error + c.query("social", "MATCH (p:person) RETURN toUpper(p.mixed_prop)"); + } + catch (Exception e) { + Assert.assertEquals(JRedisGraphRunTimeException.class, e.getClass()); + Assert.assertTrue( e.getMessage().contains("Type mismatch: expected String but was Integer")); + } + + } +}