From 1622da7d8d233ef949d82fce81249c2521affb6d Mon Sep 17 00:00:00 2001
From: haysch <36488481+haysch@users.noreply.github.com>
Date: Sat, 1 Jul 2023 14:22:43 +0200
Subject: [PATCH 1/3] Expose internals to NRedisStack test project
---
src/NRedisStack/NRedisStack.csproj | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/NRedisStack/NRedisStack.csproj b/src/NRedisStack/NRedisStack.csproj
index 6dd24984..13f99b67 100644
--- a/src/NRedisStack/NRedisStack.csproj
+++ b/src/NRedisStack/NRedisStack.csproj
@@ -20,4 +20,8 @@
+
+
+
+
From dd364e26f5256d57fa25501f8c1edb82b53765c3 Mon Sep 17 00:00:00 2001
From: haysch <36488481+haysch@users.noreply.github.com>
Date: Sat, 1 Jul 2023 14:27:03 +0200
Subject: [PATCH 2/3] Extend Graph query preparation.
* Escape backslashes in strings.
* Add test cases for PrepareQuery.
---
src/NRedisStack/Graph/RedisGraphUtilities.cs | 7 +-
tests/NRedisStack.Tests/Graph/GraphTests.cs | 80 ++++++++++++++++++--
2 files changed, 81 insertions(+), 6 deletions(-)
diff --git a/src/NRedisStack/Graph/RedisGraphUtilities.cs b/src/NRedisStack/Graph/RedisGraphUtilities.cs
index a13f1049..b0eae675 100644
--- a/src/NRedisStack/Graph/RedisGraphUtilities.cs
+++ b/src/NRedisStack/Graph/RedisGraphUtilities.cs
@@ -114,8 +114,13 @@ internal static string QuoteString(string unquotedString)
{
var quotedString = new StringBuilder(unquotedString.Length + 12);
+ // Replace order is important, otherwise too many backslashes will be added.
+ var sanitizedUnquotedString = unquotedString
+ .Replace("\\", "\\\\")
+ .Replace("\"", "\\\"");
+
quotedString.Append('"');
- quotedString.Append(unquotedString.Replace("\"", "\\\""));
+ quotedString.Append(sanitizedUnquotedString);
quotedString.Append('"');
return quotedString.ToString();
diff --git a/tests/NRedisStack.Tests/Graph/GraphTests.cs b/tests/NRedisStack.Tests/Graph/GraphTests.cs
index d6f6e170..32532de9 100644
--- a/tests/NRedisStack.Tests/Graph/GraphTests.cs
+++ b/tests/NRedisStack.Tests/Graph/GraphTests.cs
@@ -2003,12 +2003,82 @@ public void TestEqualsAndToString()
[Fact]
public void TestPrepareQuery()
{
+ const string return1Query = "RETURN 1";
+ const string return1QueryRecordString = "Record{values=1}";
+
var graph = redisFixture.Redis.GetDatabase().GRAPH();
- var res1 = graph.Query("graph", "RETURN 1", new Dictionary { { "a", (char)'c' } });
- var res2 = graph.Query("graph", "RETURN 1", new Dictionary { { "a", null } });
- var res3 = graph.Query("graph", "RETURN 1", new Dictionary { { "a", new string[]{"foo", "bar"} } });
- var res4 = graph.Query("graph", "RETURN 1", new Dictionary { { "a", new List{"foo2", "bar2"} } });
- // TODO: complete this test
+
+ // handle chars
+ var preparedQuery1 = RedisGraphUtilities.PrepareQuery(return1Query, new Dictionary { { "a", (char)'c' } });
+ var expectedPreparedQuery1 = $"CYPHER a=\"c\" {return1Query}";
+ Assert.Equal(expectedPreparedQuery1, preparedQuery1);
+ var res1 = graph.Query("graph", preparedQuery1);
+ Assert.Single(res1);
+ Assert.Equal(return1QueryRecordString, res1.Single().ToString());
+
+ // handle null
+ var preparedQuery2 = RedisGraphUtilities.PrepareQuery(return1Query, new Dictionary { { "a", null } });
+ var expectedPreparedQuery2 = $"CYPHER a=null {return1Query}";
+ Assert.Equal(expectedPreparedQuery2, preparedQuery2);
+ var res2 = graph.Query("graph", preparedQuery2);
+ Assert.Single(res2);
+ Assert.Equal(return1QueryRecordString, res2.Single().ToString());
+
+ // handle arrays
+ var preparedQuery3 = RedisGraphUtilities.PrepareQuery(return1Query, new Dictionary { { "a", new string[] { "foo", "bar" } } });
+ var expectedPreparedQuery3 = $"CYPHER a=[\"foo\", \"bar\"] {return1Query}";
+ Assert.Equal(expectedPreparedQuery3, preparedQuery3);
+ var res3 = graph.Query("graph", preparedQuery3);
+ Assert.Single(res3);
+ Assert.Equal(return1QueryRecordString, res3.Single().ToString());
+
+ // handle lists
+ var preparedQuery4 = RedisGraphUtilities.PrepareQuery(return1Query, new Dictionary { { "a", new List { "foo2", "bar2" } } });
+ var expectedPreparedQuery4 = $"CYPHER a=[\"foo2\", \"bar2\"] {return1Query}";
+ Assert.Equal(expectedPreparedQuery4, preparedQuery4);
+ var res4 = graph.Query("graph", preparedQuery4);
+ Assert.Single(res4);
+ Assert.Equal(return1QueryRecordString, res4.Single().ToString());
+
+ // handle bools
+ var preparedQuery5 = RedisGraphUtilities.PrepareQuery(return1Query, new Dictionary { { "a", true }, { "b", false } });
+ var expectedPreparedQuery5 = $"CYPHER a=true b=false {return1Query}";
+ Assert.Equal(expectedPreparedQuery5, preparedQuery5);
+ var res5 = graph.Query("graph", preparedQuery5);
+ Assert.Single(res5);
+ Assert.Equal(return1QueryRecordString, res4.Single().ToString());
+
+ // handle floats
+ var preparedQuery6 = RedisGraphUtilities.PrepareQuery(return1Query, new Dictionary { { "a", 1.4d } });
+ var expectedPreparedQuery6 = $"CYPHER a=1.4 {return1Query}";
+ Assert.Equal(expectedPreparedQuery6, preparedQuery6);
+ var res6 = graph.Query("graph", preparedQuery6);
+ Assert.Single(res6);
+ Assert.Equal(return1QueryRecordString, res4.Single().ToString());
+
+ // handle ints
+ var preparedQuery7 = RedisGraphUtilities.PrepareQuery(return1Query, new Dictionary { { "a", 5 } });
+ var expectedPreparedQuery7 = $"CYPHER a=5 {return1Query}";
+ Assert.Equal(expectedPreparedQuery7, preparedQuery7);
+ var res7 = graph.Query("graph", preparedQuery7);
+ Assert.Single(res7);
+ Assert.Equal(return1QueryRecordString, res4.Single().ToString());
+
+ // handle quotes
+ var preparedQuery8 = RedisGraphUtilities.PrepareQuery(return1Query, new Dictionary { { "a", "\"abc\"" } });
+ var expectedPreparedQuery8 = $"CYPHER a=\"\\\"abc\\\"\" {return1Query}";
+ Assert.Equal(expectedPreparedQuery8, preparedQuery8);
+ var res8 = graph.Query("graph", preparedQuery8);
+ Assert.Single(res8);
+ Assert.Equal(return1QueryRecordString, res5.Single().ToString());
+
+ // handle backslashes
+ var preparedQuery9 = RedisGraphUtilities.PrepareQuery(return1Query, new Dictionary { { "a", "abc\\" } });
+ var expectedPreparedQuery9 = $"CYPHER a=\"abc\\\\\" {return1Query}";
+ Assert.Equal(expectedPreparedQuery9, preparedQuery9);
+ var res9 = graph.Query("graph", preparedQuery9);
+ Assert.Single(res9);
+ Assert.Equal(return1QueryRecordString, res6.Single().ToString());
}
#endregion
From 9c14898b7bf4a658c26ffdbe6cffebe317e971ad Mon Sep 17 00:00:00 2001
From: shacharPash
Date: Sun, 2 Jul 2023 15:55:24 +0300
Subject: [PATCH 3/3] test without InternalsVisibleTo NRedisStack.Tests
---
src/NRedisStack/Graph/GraphCommandBuilder.cs | 8 +++
src/NRedisStack/NRedisStack.csproj | 4 --
tests/NRedisStack.Tests/Graph/GraphTests.cs | 54 ++++++++++----------
3 files changed, 35 insertions(+), 31 deletions(-)
diff --git a/src/NRedisStack/Graph/GraphCommandBuilder.cs b/src/NRedisStack/Graph/GraphCommandBuilder.cs
index acce0ac1..126ace15 100644
--- a/src/NRedisStack/Graph/GraphCommandBuilder.cs
+++ b/src/NRedisStack/Graph/GraphCommandBuilder.cs
@@ -1,3 +1,4 @@
+using NRedisStack.Graph;
using NRedisStack.Graph.Literals;
using NRedisStack.RedisStackCommands;
@@ -7,6 +8,13 @@ public static class GraphCommandBuilder
{
internal static readonly object CompactQueryFlag = "--COMPACT";
+ ///
+ public static SerializedCommand Query(string graphName, string query, Dictionary parameters, long? timeout = null)
+ {
+ var preparedQuery = RedisGraphUtilities.PrepareQuery(query, parameters);
+ return Query(graphName, preparedQuery, timeout);
+ }
+
///
public static SerializedCommand Query(string graphName, string query, long? timeout = null)
{
diff --git a/src/NRedisStack/NRedisStack.csproj b/src/NRedisStack/NRedisStack.csproj
index 13f99b67..6dd24984 100644
--- a/src/NRedisStack/NRedisStack.csproj
+++ b/src/NRedisStack/NRedisStack.csproj
@@ -20,8 +20,4 @@
-
-
-
-
diff --git a/tests/NRedisStack.Tests/Graph/GraphTests.cs b/tests/NRedisStack.Tests/Graph/GraphTests.cs
index 32532de9..c339ba4e 100644
--- a/tests/NRedisStack.Tests/Graph/GraphTests.cs
+++ b/tests/NRedisStack.Tests/Graph/GraphTests.cs
@@ -2009,74 +2009,74 @@ public void TestPrepareQuery()
var graph = redisFixture.Redis.GetDatabase().GRAPH();
// handle chars
- var preparedQuery1 = RedisGraphUtilities.PrepareQuery(return1Query, new Dictionary { { "a", (char)'c' } });
+ var buildCommand = GraphCommandBuilder.Query("graph", return1Query, new Dictionary { { "a", (char)'c' }} );
var expectedPreparedQuery1 = $"CYPHER a=\"c\" {return1Query}";
- Assert.Equal(expectedPreparedQuery1, preparedQuery1);
- var res1 = graph.Query("graph", preparedQuery1);
+ Assert.Equal(expectedPreparedQuery1, buildCommand.Args[1].ToString()!);
+ var res1 = graph.Query("graph", buildCommand.Args[1].ToString()!);
Assert.Single(res1);
Assert.Equal(return1QueryRecordString, res1.Single().ToString());
// handle null
- var preparedQuery2 = RedisGraphUtilities.PrepareQuery(return1Query, new Dictionary { { "a", null } });
+ var buildCommand2 = GraphCommandBuilder.Query("graph", return1Query, new Dictionary { { "a", null } });
var expectedPreparedQuery2 = $"CYPHER a=null {return1Query}";
- Assert.Equal(expectedPreparedQuery2, preparedQuery2);
- var res2 = graph.Query("graph", preparedQuery2);
+ Assert.Equal(expectedPreparedQuery2,buildCommand2.Args[1].ToString()!);
+ var res2 = graph.Query("graph",buildCommand2.Args[1].ToString()!);
Assert.Single(res2);
Assert.Equal(return1QueryRecordString, res2.Single().ToString());
// handle arrays
- var preparedQuery3 = RedisGraphUtilities.PrepareQuery(return1Query, new Dictionary { { "a", new string[] { "foo", "bar" } } });
+ var buildCommand3 = GraphCommandBuilder.Query("graph", return1Query, new Dictionary { { "a", new string[] { "foo", "bar" } } });
var expectedPreparedQuery3 = $"CYPHER a=[\"foo\", \"bar\"] {return1Query}";
- Assert.Equal(expectedPreparedQuery3, preparedQuery3);
- var res3 = graph.Query("graph", preparedQuery3);
+ Assert.Equal(expectedPreparedQuery3,buildCommand3.Args[1].ToString()!);
+ var res3 = graph.Query("graph",buildCommand3.Args[1].ToString()!);
Assert.Single(res3);
Assert.Equal(return1QueryRecordString, res3.Single().ToString());
// handle lists
- var preparedQuery4 = RedisGraphUtilities.PrepareQuery(return1Query, new Dictionary { { "a", new List { "foo2", "bar2" } } });
+ var buildCommand4 = GraphCommandBuilder.Query("graph", return1Query, new Dictionary { { "a", new List { "foo2", "bar2" } } });
var expectedPreparedQuery4 = $"CYPHER a=[\"foo2\", \"bar2\"] {return1Query}";
- Assert.Equal(expectedPreparedQuery4, preparedQuery4);
- var res4 = graph.Query("graph", preparedQuery4);
+ Assert.Equal(expectedPreparedQuery4,buildCommand4.Args[1].ToString()!);
+ var res4 = graph.Query("graph",buildCommand4.Args[1].ToString()!);
Assert.Single(res4);
Assert.Equal(return1QueryRecordString, res4.Single().ToString());
// handle bools
- var preparedQuery5 = RedisGraphUtilities.PrepareQuery(return1Query, new Dictionary { { "a", true }, { "b", false } });
+ var buildCommand5 = GraphCommandBuilder.Query("graph", return1Query, new Dictionary { { "a", true }, { "b", false } });
var expectedPreparedQuery5 = $"CYPHER a=true b=false {return1Query}";
- Assert.Equal(expectedPreparedQuery5, preparedQuery5);
- var res5 = graph.Query("graph", preparedQuery5);
+ Assert.Equal(expectedPreparedQuery5,buildCommand5.Args[1].ToString()!);
+ var res5 = graph.Query("graph",buildCommand5.Args[1].ToString()!);
Assert.Single(res5);
Assert.Equal(return1QueryRecordString, res4.Single().ToString());
// handle floats
- var preparedQuery6 = RedisGraphUtilities.PrepareQuery(return1Query, new Dictionary { { "a", 1.4d } });
+ var buildCommand6 = GraphCommandBuilder.Query("graph", return1Query, new Dictionary { { "a", 1.4d } });
var expectedPreparedQuery6 = $"CYPHER a=1.4 {return1Query}";
- Assert.Equal(expectedPreparedQuery6, preparedQuery6);
- var res6 = graph.Query("graph", preparedQuery6);
+ Assert.Equal(expectedPreparedQuery6,buildCommand6.Args[1].ToString()!);
+ var res6 = graph.Query("graph",buildCommand6.Args[1].ToString()!);
Assert.Single(res6);
Assert.Equal(return1QueryRecordString, res4.Single().ToString());
// handle ints
- var preparedQuery7 = RedisGraphUtilities.PrepareQuery(return1Query, new Dictionary { { "a", 5 } });
+ var buildCommand7 = GraphCommandBuilder.Query("graph", return1Query, new Dictionary { { "a", 5 } });
var expectedPreparedQuery7 = $"CYPHER a=5 {return1Query}";
- Assert.Equal(expectedPreparedQuery7, preparedQuery7);
- var res7 = graph.Query("graph", preparedQuery7);
+ Assert.Equal(expectedPreparedQuery7,buildCommand7.Args[1].ToString()!);
+ var res7 = graph.Query("graph",buildCommand7.Args[1].ToString()!);
Assert.Single(res7);
Assert.Equal(return1QueryRecordString, res4.Single().ToString());
// handle quotes
- var preparedQuery8 = RedisGraphUtilities.PrepareQuery(return1Query, new Dictionary { { "a", "\"abc\"" } });
+ var buildCommand8 = GraphCommandBuilder.Query("graph", return1Query, new Dictionary { { "a", "\"abc\"" } });
var expectedPreparedQuery8 = $"CYPHER a=\"\\\"abc\\\"\" {return1Query}";
- Assert.Equal(expectedPreparedQuery8, preparedQuery8);
- var res8 = graph.Query("graph", preparedQuery8);
+ Assert.Equal(expectedPreparedQuery8,buildCommand8.Args[1].ToString()!);
+ var res8 = graph.Query("graph",buildCommand8.Args[1].ToString()!);
Assert.Single(res8);
Assert.Equal(return1QueryRecordString, res5.Single().ToString());
// handle backslashes
- var preparedQuery9 = RedisGraphUtilities.PrepareQuery(return1Query, new Dictionary { { "a", "abc\\" } });
+ var buildCommand9 = GraphCommandBuilder.Query("graph", return1Query, new Dictionary { { "a", "abc\\" } });
var expectedPreparedQuery9 = $"CYPHER a=\"abc\\\\\" {return1Query}";
- Assert.Equal(expectedPreparedQuery9, preparedQuery9);
- var res9 = graph.Query("graph", preparedQuery9);
+ Assert.Equal(expectedPreparedQuery9,buildCommand9.Args[1].ToString()!);
+ var res9 = graph.Query("graph",buildCommand9.Args[1].ToString()!);
Assert.Single(res9);
Assert.Equal(return1QueryRecordString, res6.Single().ToString());
}