Skip to content

Commit a2b4202

Browse files
author
DvirDukhan
authored
added params support (#54)
1 parent 5ef0b2c commit a2b4202

File tree

7 files changed

+177
-16
lines changed

7 files changed

+177
-16
lines changed

README.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,13 @@ public class RedisGraphExample {
100100
// general context api. Not bound to graph key or connection
101101
RedisGraph graph = new RedisGraph();
102102

103-
// send queries to a specific graph called "social"
104-
graph.query("social","CREATE (:person{name:'roi',age:32})");
105-
graph.query("social","CREATE (:person{name:%s,age:%d})", "amit", 30);
103+
Map<String, Object> params = new HashMap<>();
104+
params.put("age", 30);
105+
params.put("name", "amit");
106+
107+
// send queries to a specific graph called "social"
108+
graph.query("social","CREATE (:person{name:'roi',age:32})");
109+
graph.query("social","CREATE (:person{name:$name,age:$age})", params);
106110
graph.query("social","MATCH (a:person), (b:person) WHERE (a.name = 'roi' AND b.name='amit') CREATE (a)-[:knows]->(b)");
107111

108112
ResultSet resultSet = graph.query("social", "MATCH (a:person)-[r:knows]->(b:person) RETURN a, r, b");
@@ -131,7 +135,7 @@ public class RedisGraphExample {
131135
// get connection context - closable object
132136
try(RedisGraphContext context = graph.getContext()) {
133137
context.query("contextSocial","CREATE (:person{name:'roi',age:32})");
134-
context.query("contextSocial","CREATE (:person{name:%s,age:%d})", "amit", 30);
138+
context.query("social","CREATE (:person{name:$name,age:$age})", params);
135139
context.query("contextSocial", "MATCH (a:person), (b:person) WHERE (a.name = 'roi' AND b.name='amit') CREATE (a)-[:knows]->(b)");
136140
// WATCH/MULTI/EXEC
137141
context.watch("contextSocial");

src/main/java/com/redislabs/redisgraph/RedisGraph.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,35 @@
66

77
public interface RedisGraph extends Closeable {
88

9+
/**
10+
* Execute a Cypher query.
11+
* @param graphId a graph to perform the query on
12+
* @param query Cypher query
13+
* @return a result set
14+
*/
15+
ResultSet query(String graphId, String query);
16+
17+
918
/**
1019
* Execute a Cypher query with arguments
1120
* @param graphId a graph to perform the query on
1221
* @param query Cypher query
1322
* @param args
1423
* @return a result set
24+
* @deprecated use {@link #query(String, String, Map)} instead.
1525
*/
26+
@Deprecated
1627
ResultSet query(String graphId, String query, Object ...args);
1728

29+
/**
30+
* Executes a cypher query with parameters.
31+
* @param graphId a graph to perform the query on.
32+
* @param query Cypher query.
33+
* @param params parameters map.
34+
* @return a result set.
35+
*/
36+
ResultSet query(String graphId, String query, Map<String, Object> params);
37+
1838
/**
1939
* Invokes stored procedures without arguments
2040
* @param graphId a graph to perform the query on

src/main/java/com/redislabs/redisgraph/impl/Utils.java

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,7 @@
44
import org.apache.commons.text.translate.CharSequenceTranslator;
55
import org.apache.commons.text.translate.LookupTranslator;
66

7-
import java.util.ArrayList;
8-
import java.util.Collections;
9-
import java.util.HashMap;
10-
import java.util.List;
11-
import java.util.Map;
7+
import java.util.*;
128
import java.util.stream.Collectors;
139

1410
/**
@@ -50,12 +46,15 @@ private static String quoteString(String str){
5046
return sb.toString();
5147
}
5248

49+
5350
/**
5451
* Prepare and formats a query and query arguments
5552
* @param query - query
5653
* @param args - query arguments
5754
* @return formatted query
55+
* @deprecated use {@link #prepareQuery(String, Map)} instead.
5856
*/
57+
@Deprecated
5958
public static String prepareQuery(String query, Object ...args){
6059
if(args.length > 0) {
6160
for(int i=0; i<args.length; ++i) {
@@ -68,6 +67,50 @@ public static String prepareQuery(String query, Object ...args){
6867
return query;
6968
}
7069

70+
/**
71+
* Prepare and formats a query and query arguments
72+
* @param query - query
73+
* @param params - query parameters
74+
* @return query with parameters header
75+
*/
76+
public static String prepareQuery(String query, Map<String, Object> params){
77+
StringBuilder sb = new StringBuilder("CYPHER ");
78+
for(Map.Entry<String, Object> entry : params.entrySet()) {
79+
String key = entry.getKey();
80+
Object value = entry.getValue();
81+
sb.append(key).append('=');
82+
sb.append(valueToString(value));
83+
sb.append(' ');
84+
}
85+
sb.append(query);
86+
return sb.toString();
87+
}
88+
89+
private static String arrayToString(Object[] arr) {
90+
StringBuilder sb = new StringBuilder().append('[');
91+
sb.append(String.join(", ", Arrays.stream(arr).map(obj->valueToString(obj)).collect(Collectors.toList())));
92+
sb.append(']');
93+
return sb.toString();
94+
}
95+
96+
private static String valueToString(Object value) {
97+
if(value == null)
98+
return "null";
99+
if(String.class.isInstance(value)){
100+
return quoteString((String) value);
101+
}
102+
103+
if(value.getClass().isArray()){
104+
return arrayToString((Object[]) value);
105+
106+
}
107+
if(List.class.isInstance(value)){
108+
List<Object> list = (List<Object>)value;
109+
return arrayToString(list.toArray());
110+
}
111+
return value.toString();
112+
}
113+
71114
/**
72115
* Prepare and format a procedure call and its arguments
73116
* @param procedure - procedure to invoke

src/main/java/com/redislabs/redisgraph/impl/api/AbstractRedisGraph.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,42 @@ public abstract class AbstractRedisGraph implements RedisGraph {
2929
*/
3030
protected abstract ResultSet sendQuery(String graphId, String preparedQuery);
3131

32+
/**
33+
* Execute a Cypher query.
34+
* @param graphId a graph to perform the query on
35+
* @param query Cypher query
36+
* @return a result set
37+
*/
38+
public ResultSet query(String graphId, String query) {
39+
return sendQuery(graphId, query);
40+
}
41+
3242
/**
3343
* Execute a Cypher query with arguments
3444
* @param graphId a graph to perform the query on
3545
* @param query Cypher query
3646
* @param args
3747
* @return a result set
48+
* @deprecated use {@link #query(String, String, Map)} instead.
3849
*/
50+
@Deprecated
3951
public ResultSet query(String graphId, String query, Object ...args) {
4052
String preparedQuery = Utils.prepareQuery(query, args);
4153
return sendQuery(graphId, preparedQuery);
4254
}
4355

56+
/**
57+
* Executes a cypher query with parameters.
58+
* @param graphId a graph to perform the query on.
59+
* @param query Cypher query.
60+
* @param params parameters map.
61+
* @return a result set.
62+
*/
63+
public ResultSet query(String graphId, String query, Map<String, Object> params) {
64+
String preparedQuery = Utils.prepareQuery(query, params);
65+
return sendQuery(graphId, preparedQuery);
66+
}
67+
4468

4569
public ResultSet callProcedure(String graphId, String procedure){
4670
return callProcedure(graphId, procedure, Utils.DUMMY_LIST, Utils.DUMMY_MAP);

src/test/java/com/redislabs/redisgraph/RedisGraphAPITest.java

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,13 @@ public void testRecord(){
245245
+ "nullValue=Property{name='nullValue', value=null}, "
246246
+ "since=Property{name='since', value=2000}}}", expectedEdge.toString());
247247

248-
Assert.assertNotNull(api.query("social", "CREATE (:person{name:%s,age:%d, doubleValue:%f, boolValue:%b, nullValue:null})", name, age, doubleValue, boolValue));
248+
Map<String, Object> params = new HashMap<>();
249+
params.put("name", name);
250+
params.put("age", age);
251+
params.put("boolValue", boolValue);
252+
params.put("doubleValue", doubleValue);
253+
254+
Assert.assertNotNull(api.query("social", "CREATE (:person{name:$name,age:$age, doubleValue:$doubleValue, boolValue:$boolValue, nullValue:null})", params));
249255
Assert.assertNotNull(api.query("social", "CREATE (:person{name:'amit',age:30})"));
250256
Assert.assertNotNull(api.query("social", "MATCH (a:person), (b:person) WHERE (a.name = 'roi' AND b.name='amit') " +
251257
"CREATE (a)-[:knows{place:'TLV', since:2000,doubleValue:3.14, boolValue:false, nullValue:null}]->(b)"));
@@ -654,8 +660,13 @@ public void testContextedAPI() {
654660
expectedEdge.addProperty(falseBooleanProperty);
655661
expectedEdge.addProperty(nullProperty);
656662

663+
Map<String, Object> params = new HashMap<>();
664+
params.put("name", name);
665+
params.put("age", age);
666+
params.put("boolValue", boolValue);
667+
params.put("doubleValue", doubleValue);
657668
try (RedisGraphContext c = api.getContext()) {
658-
Assert.assertNotNull(c.query("social", "CREATE (:person{name:%s,age:%d, doubleValue:%f, boolValue:%b, nullValue:null})", name, age, doubleValue, boolValue));
669+
Assert.assertNotNull(c.query("social", "CREATE (:person{name:$name, age:$age, doubleValue:$doubleValue, boolValue:$boolValue, nullValue:null})", params));
659670
Assert.assertNotNull(c.query("social", "CREATE (:person{name:'amit',age:30})"));
660671
Assert.assertNotNull(c.query("social", "MATCH (a:person), (b:person) WHERE (a.name = 'roi' AND b.name='amit') " +
661672
"CREATE (a)-[:knows{place:'TLV', since:2000,doubleValue:3.14, boolValue:false, nullValue:null}]->(b)"));
@@ -920,4 +931,22 @@ public void testPath(){
920931

921932
}
922933

934+
@Test
935+
public void testParameters(){
936+
Object[] parameters = {1, 2.3, true, false, null, "str", Arrays.asList(1,2,3), new Integer[]{1,2,3}};
937+
Map<String, Object> param = new HashMap<>();
938+
for (int i=0; i < parameters.length; i++) {
939+
Object expected = parameters[i];
940+
param.put("param", expected);
941+
ResultSet resultSet = api.query("social", "RETURN $param", param);
942+
Assert.assertEquals(1, resultSet.size());
943+
Record r = resultSet.next();
944+
Object o = r.getValue(0);
945+
if(i == parameters.length-1) {
946+
expected = Arrays.asList((Object[])expected);
947+
}
948+
Assert.assertEquals(expected, o);
949+
}
950+
}
951+
923952
}

src/test/java/com/redislabs/redisgraph/exceptions/JRedisGraphErrorTest.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
import org.junit.Test;
1111
import org.junit.rules.ExpectedException;
1212

13+
import java.util.HashMap;
14+
1315

1416
public class JRedisGraphErrorTest {
1517

@@ -86,6 +88,20 @@ public void testContextSyntaxErrorReporting() {
8688

8789
}
8890

91+
@Test
92+
public void testMissingParametersSyntaxErrorReporting(){
93+
exceptionRule.expect(JRedisGraphCompileTimeException.class);
94+
exceptionRule.expectMessage("Missing parameters");
95+
api.query("social","RETURN $param");
96+
}
97+
98+
@Test
99+
public void testMissingParametersSyntaxErrorReporting2(){
100+
exceptionRule.expect(JRedisGraphCompileTimeException.class);
101+
exceptionRule.expectMessage("Missing parameters");
102+
api.query("social","RETURN $param", new HashMap<>());
103+
}
104+
89105
@Test
90106
public void testContextRuntimeErrorReporting() {
91107
exceptionRule.expect(JRedisGraphRunTimeException.class);

src/test/java/com/redislabs/redisgraph/impl/UtilsTest.java

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
package com.redislabs.redisgraph.impl;
22

3-
import java.util.Arrays;
4-
import java.util.HashMap;
5-
import java.util.IllegalFormatConversionException;
6-
import java.util.List;
7-
import java.util.Map;
3+
import java.util.*;
84

95
import org.junit.Assert;
106
import org.junit.Rule;
@@ -41,4 +37,33 @@ public void prepareQuery() {
4137
Assert.assertEquals("CAL prc(\"a\",\"b\")ka,kb", Utils.prepareQuery("query %s %d end of query", "a", "b"));
4238
}
4339

40+
@Test
41+
public void testParamsPrep(){
42+
Map<String, Object> params = new HashMap<>();
43+
params.put("param", 1);
44+
Assert.assertEquals("CYPHER param=1 RETURN $param", Utils.prepareQuery("RETURN $param", params));
45+
params.put("param", 2.3);
46+
Assert.assertEquals("CYPHER param=2.3 RETURN $param", Utils.prepareQuery("RETURN $param", params));
47+
params.put("param", true);
48+
Assert.assertEquals("CYPHER param=true RETURN $param", Utils.prepareQuery("RETURN $param", params));
49+
params.put("param", false);
50+
Assert.assertEquals("CYPHER param=false RETURN $param", Utils.prepareQuery("RETURN $param", params));
51+
params.put("param", null);
52+
Assert.assertEquals("CYPHER param=null RETURN $param", Utils.prepareQuery("RETURN $param", params));
53+
params.put("param", "str");
54+
Assert.assertEquals("CYPHER param=\"str\" RETURN $param", Utils.prepareQuery("RETURN $param", params));
55+
Integer arr[] = {1,2,3};
56+
params.put("param", arr);
57+
Assert.assertEquals("CYPHER param=[1, 2, 3] RETURN $param", Utils.prepareQuery("RETURN $param", params));
58+
List<Integer> list = Arrays.asList(1,2,3);
59+
params.put("param", list);
60+
Assert.assertEquals("CYPHER param=[1, 2, 3] RETURN $param", Utils.prepareQuery("RETURN $param", params));
61+
String strArr[] = {"1", "2", "3"};
62+
params.put("param", strArr);
63+
Assert.assertEquals("CYPHER param=[\"1\", \"2\", \"3\"] RETURN $param", Utils.prepareQuery("RETURN $param", params));
64+
List<String> stringList = Arrays.asList("1", "2", "3");
65+
params.put("param", stringList);
66+
Assert.assertEquals("CYPHER param=[\"1\", \"2\", \"3\"] RETURN $param", Utils.prepareQuery("RETURN $param", params));
67+
}
68+
4469
}

0 commit comments

Comments
 (0)