Skip to content

Commit 50a0740

Browse files
hayschshacharPash
andauthored
Escape backslashes in RedisGraphUtilities.PrepareQuery (#155)
* Expose internals to NRedisStack test project * Extend Graph query preparation. * Escape backslashes in strings. * Add test cases for PrepareQuery. * test without InternalsVisibleTo NRedisStack.Tests --------- Co-authored-by: shacharPash <[email protected]>
1 parent 0b6abaf commit 50a0740

File tree

3 files changed

+89
-6
lines changed

3 files changed

+89
-6
lines changed

src/NRedisStack/Graph/GraphCommandBuilder.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using NRedisStack.Graph;
12
using NRedisStack.Graph.Literals;
23
using NRedisStack.RedisStackCommands;
34

@@ -7,6 +8,13 @@ public static class GraphCommandBuilder
78
{
89
internal static readonly object CompactQueryFlag = "--COMPACT";
910

11+
/// <inheritdoc/>
12+
public static SerializedCommand Query(string graphName, string query, Dictionary<string, object> parameters, long? timeout = null)
13+
{
14+
var preparedQuery = RedisGraphUtilities.PrepareQuery(query, parameters);
15+
return Query(graphName, preparedQuery, timeout);
16+
}
17+
1018
/// <inheritdoc/>
1119
public static SerializedCommand Query(string graphName, string query, long? timeout = null)
1220
{

src/NRedisStack/Graph/RedisGraphUtilities.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,13 @@ internal static string QuoteString(string unquotedString)
114114
{
115115
var quotedString = new StringBuilder(unquotedString.Length + 12);
116116

117+
// Replace order is important, otherwise too many backslashes will be added.
118+
var sanitizedUnquotedString = unquotedString
119+
.Replace("\\", "\\\\")
120+
.Replace("\"", "\\\"");
121+
117122
quotedString.Append('"');
118-
quotedString.Append(unquotedString.Replace("\"", "\\\""));
123+
quotedString.Append(sanitizedUnquotedString);
119124
quotedString.Append('"');
120125

121126
return quotedString.ToString();

tests/NRedisStack.Tests/Graph/GraphTests.cs

Lines changed: 75 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2003,12 +2003,82 @@ public void TestEqualsAndToString()
20032003
[Fact]
20042004
public void TestPrepareQuery()
20052005
{
2006+
const string return1Query = "RETURN 1";
2007+
const string return1QueryRecordString = "Record{values=1}";
2008+
20062009
var graph = redisFixture.Redis.GetDatabase().GRAPH();
2007-
var res1 = graph.Query("graph", "RETURN 1", new Dictionary<string, object> { { "a", (char)'c' } });
2008-
var res2 = graph.Query("graph", "RETURN 1", new Dictionary<string, object> { { "a", null } });
2009-
var res3 = graph.Query("graph", "RETURN 1", new Dictionary<string, object> { { "a", new string[]{"foo", "bar"} } });
2010-
var res4 = graph.Query("graph", "RETURN 1", new Dictionary<string, object> { { "a", new List<string>{"foo2", "bar2"} } });
2011-
// TODO: complete this test
2010+
2011+
// handle chars
2012+
var buildCommand = GraphCommandBuilder.Query("graph", return1Query, new Dictionary<string, object> { { "a", (char)'c' }} );
2013+
var expectedPreparedQuery1 = $"CYPHER a=\"c\" {return1Query}";
2014+
Assert.Equal(expectedPreparedQuery1, buildCommand.Args[1].ToString()!);
2015+
var res1 = graph.Query("graph", buildCommand.Args[1].ToString()!);
2016+
Assert.Single(res1);
2017+
Assert.Equal(return1QueryRecordString, res1.Single().ToString());
2018+
2019+
// handle null
2020+
var buildCommand2 = GraphCommandBuilder.Query("graph", return1Query, new Dictionary<string, object> { { "a", null } });
2021+
var expectedPreparedQuery2 = $"CYPHER a=null {return1Query}";
2022+
Assert.Equal(expectedPreparedQuery2,buildCommand2.Args[1].ToString()!);
2023+
var res2 = graph.Query("graph",buildCommand2.Args[1].ToString()!);
2024+
Assert.Single(res2);
2025+
Assert.Equal(return1QueryRecordString, res2.Single().ToString());
2026+
2027+
// handle arrays
2028+
var buildCommand3 = GraphCommandBuilder.Query("graph", return1Query, new Dictionary<string, object> { { "a", new string[] { "foo", "bar" } } });
2029+
var expectedPreparedQuery3 = $"CYPHER a=[\"foo\", \"bar\"] {return1Query}";
2030+
Assert.Equal(expectedPreparedQuery3,buildCommand3.Args[1].ToString()!);
2031+
var res3 = graph.Query("graph",buildCommand3.Args[1].ToString()!);
2032+
Assert.Single(res3);
2033+
Assert.Equal(return1QueryRecordString, res3.Single().ToString());
2034+
2035+
// handle lists
2036+
var buildCommand4 = GraphCommandBuilder.Query("graph", return1Query, new Dictionary<string, object> { { "a", new List<string> { "foo2", "bar2" } } });
2037+
var expectedPreparedQuery4 = $"CYPHER a=[\"foo2\", \"bar2\"] {return1Query}";
2038+
Assert.Equal(expectedPreparedQuery4,buildCommand4.Args[1].ToString()!);
2039+
var res4 = graph.Query("graph",buildCommand4.Args[1].ToString()!);
2040+
Assert.Single(res4);
2041+
Assert.Equal(return1QueryRecordString, res4.Single().ToString());
2042+
2043+
// handle bools
2044+
var buildCommand5 = GraphCommandBuilder.Query("graph", return1Query, new Dictionary<string, object> { { "a", true }, { "b", false } });
2045+
var expectedPreparedQuery5 = $"CYPHER a=true b=false {return1Query}";
2046+
Assert.Equal(expectedPreparedQuery5,buildCommand5.Args[1].ToString()!);
2047+
var res5 = graph.Query("graph",buildCommand5.Args[1].ToString()!);
2048+
Assert.Single(res5);
2049+
Assert.Equal(return1QueryRecordString, res4.Single().ToString());
2050+
2051+
// handle floats
2052+
var buildCommand6 = GraphCommandBuilder.Query("graph", return1Query, new Dictionary<string, object> { { "a", 1.4d } });
2053+
var expectedPreparedQuery6 = $"CYPHER a=1.4 {return1Query}";
2054+
Assert.Equal(expectedPreparedQuery6,buildCommand6.Args[1].ToString()!);
2055+
var res6 = graph.Query("graph",buildCommand6.Args[1].ToString()!);
2056+
Assert.Single(res6);
2057+
Assert.Equal(return1QueryRecordString, res4.Single().ToString());
2058+
2059+
// handle ints
2060+
var buildCommand7 = GraphCommandBuilder.Query("graph", return1Query, new Dictionary<string, object> { { "a", 5 } });
2061+
var expectedPreparedQuery7 = $"CYPHER a=5 {return1Query}";
2062+
Assert.Equal(expectedPreparedQuery7,buildCommand7.Args[1].ToString()!);
2063+
var res7 = graph.Query("graph",buildCommand7.Args[1].ToString()!);
2064+
Assert.Single(res7);
2065+
Assert.Equal(return1QueryRecordString, res4.Single().ToString());
2066+
2067+
// handle quotes
2068+
var buildCommand8 = GraphCommandBuilder.Query("graph", return1Query, new Dictionary<string, object> { { "a", "\"abc\"" } });
2069+
var expectedPreparedQuery8 = $"CYPHER a=\"\\\"abc\\\"\" {return1Query}";
2070+
Assert.Equal(expectedPreparedQuery8,buildCommand8.Args[1].ToString()!);
2071+
var res8 = graph.Query("graph",buildCommand8.Args[1].ToString()!);
2072+
Assert.Single(res8);
2073+
Assert.Equal(return1QueryRecordString, res5.Single().ToString());
2074+
2075+
// handle backslashes
2076+
var buildCommand9 = GraphCommandBuilder.Query("graph", return1Query, new Dictionary<string, object> { { "a", "abc\\" } });
2077+
var expectedPreparedQuery9 = $"CYPHER a=\"abc\\\\\" {return1Query}";
2078+
Assert.Equal(expectedPreparedQuery9,buildCommand9.Args[1].ToString()!);
2079+
var res9 = graph.Query("graph",buildCommand9.Args[1].ToString()!);
2080+
Assert.Single(res9);
2081+
Assert.Equal(return1QueryRecordString, res6.Single().ToString());
20122082
}
20132083
#endregion
20142084

0 commit comments

Comments
 (0)