Fix Bindings for type-safe GraphTraversal interface

Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/30232822
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/30232822
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/30232822

Branch: refs/heads/TINKERPOP-1752
Commit: 30232822db5d718e26459e49f74ffc5e502d84b0
Parents: deb030c
Author: florianhockmann <[email protected]>
Authored: Tue Sep 12 16:38:51 2017 +0200
Committer: florianhockmann <[email protected]>
Committed: Tue Sep 12 16:39:38 2017 +0200

----------------------------------------------------------------------
 .../Gremlin.Net/Process/Traversal/Bindings.cs   |   5 +-
 .../Gremlin.Net/Process/Traversal/Bytecode.cs   |  80 ++++++++++-
 .../GraphTraversalTests.cs                      |  24 ++--
 .../Process/Traversal/BytecodeTests.cs          | 142 ++++++++++++++++++-
 4 files changed, 231 insertions(+), 20 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/30232822/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Bindings.cs
----------------------------------------------------------------------
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Bindings.cs 
b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Bindings.cs
index e15a202..2aa532b 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Bindings.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Bindings.cs
@@ -59,7 +59,10 @@ namespace Gremlin.Net.Process.Traversal
 
         internal static string GetBoundVariable<TV>(TV value)
         {
-            return BoundVariableByValue.Value?[value];
+            var dict = BoundVariableByValue.Value;
+            if (dict == null)
+                return null;
+            return !dict.ContainsKey(value) ? null : dict[value];
         }
 
         internal static void Clear()

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/30232822/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Bytecode.cs
----------------------------------------------------------------------
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Bytecode.cs 
b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Bytecode.cs
index b76f395..e09c533 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Bytecode.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Bytecode.cs
@@ -21,7 +21,10 @@
 
 #endregion
 
+using System;
+using System.Collections;
 using System.Collections.Generic;
+using System.Linq;
 
 namespace Gremlin.Net.Process.Traversal
 {
@@ -35,6 +38,8 @@ namespace Gremlin.Net.Process.Traversal
     /// </remarks>
     public class Bytecode
     {
+        private static readonly object[] EmptyArray = new object[0];
+
         /// <summary>
         ///     Initializes a new instance of the <see cref="Bytecode" /> 
class.
         /// </summary>
@@ -69,7 +74,8 @@ namespace Gremlin.Net.Process.Traversal
         /// <param name="args">The traversal source method arguments.</param>
         public void AddSource(string sourceName, params object[] args)
         {
-            SourceInstructions.Add(new Instruction(sourceName, args));
+            SourceInstructions.Add(new Instruction(sourceName, 
FlattenArguments(args)));
+            Bindings.Clear();
         }
 
         /// <summary>
@@ -79,7 +85,77 @@ namespace Gremlin.Net.Process.Traversal
         /// <param name="args">The traversal method arguments.</param>
         public void AddStep(string stepName, params object[] args)
         {
-            StepInstructions.Add(new Instruction(stepName, args));
+            StepInstructions.Add(new Instruction(stepName, 
FlattenArguments(args)));
+            Bindings.Clear();
+        }
+
+        private object[] FlattenArguments(object[] arguments)
+        {
+            if (arguments.Length == 0)
+                return EmptyArray;
+            var flatArguments = new List<object>();
+            foreach (var arg in arguments)
+            {
+                if (arg is object[] objects)
+                {
+                    flatArguments.AddRange(objects.Select(nestObject => 
ConvertArgument(nestObject, true)));
+                }
+                else
+                {
+                    flatArguments.Add(ConvertArgument(arg, true));
+                }
+            }
+            return flatArguments.ToArray();
+        }
+
+        private object ConvertArgument(object argument, bool searchBindings)
+        {
+            if (searchBindings)
+            {
+                var variable = Bindings.GetBoundVariable(argument);
+                if (variable != null)
+                    return new Binding(variable, ConvertArgument(argument, 
false));
+            }
+            if (IsDictionaryType(argument.GetType()))
+            {
+                var dict = new Dictionary<object, object>();
+                foreach (DictionaryEntry item in (IDictionary)argument)
+                {
+                    dict[ConvertArgument(item.Key, true)] = 
ConvertArgument(item.Value, true);
+                }
+                return dict;
+            }
+            if (IsListType(argument.GetType()))
+            {
+                var list = new List<object>(((IList) argument).Count);
+                list.AddRange(from object item in (IList) argument select 
ConvertArgument(item, true));
+                return list;
+            }
+            if (IsHashSetType(argument.GetType()))
+            {
+                var set = new HashSet<object>();
+                foreach (var item in (IEnumerable)argument)
+                {
+                    set.Add(ConvertArgument(item, true));
+                }
+                return set;
+            }
+            return argument;
+        }
+
+        private bool IsDictionaryType(Type type)
+        {
+            return type.IsConstructedGenericType && 
type.GetGenericTypeDefinition() == typeof(Dictionary<,>);
+        }
+
+        private bool IsListType(Type type)
+        {
+            return type.IsConstructedGenericType && 
type.GetGenericTypeDefinition() == typeof(List<>);
+        }
+
+        private bool IsHashSetType(Type type)
+        {
+            return type.IsConstructedGenericType && 
type.GetGenericTypeDefinition() == typeof(HashSet<>);
         }
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/30232822/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/GraphTraversalTests.cs
----------------------------------------------------------------------
diff --git 
a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/GraphTraversalTests.cs
 
b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/GraphTraversalTests.cs
index 3c98904..84a44a7 100644
--- 
a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/GraphTraversalTests.cs
+++ 
b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/GraphTraversalTests.cs
@@ -141,18 +141,18 @@ namespace 
Gremlin.Net.IntegrationTest.Process.Traversal.DriverRemoteConnection
             Assert.Equal(new Vertex((long) 6), shortestPath[3]);
         }
 
-        //[Fact]
-        //public void ShouldUseBindingsInTraversal()
-        //{
-        //    var graph = new Graph();
-        //    var connection = _connectionFactory.CreateRemoteConnection();
-        //    var g = graph.Traversal().WithRemote(connection);
-
-        //    var b = new Bindings();
-        //    var count = g.V().Has(b.Of("propertyKey", "name"), 
b.Of("propertyValue", "marko")).OutE().Count().Next();
-
-        //    Assert.Equal(3, count);
-        //}
+        [Fact]
+        public void ShouldUseBindingsInTraversal()
+        {
+            var graph = new Graph();
+            var connection = _connectionFactory.CreateRemoteConnection();
+            var g = graph.Traversal().WithRemote(connection);
+
+            var b = new Bindings();
+            var count = g.V().Has(b.Of("propertyKey", "name"), 
b.Of("propertyValue", "marko")).OutE().Count().Next();
+
+            Assert.Equal(3, count);
+        }
 
         [Fact]
         public async Task ShouldExecuteAsynchronouslyWhenPromiseIsCalled()

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/30232822/gremlin-dotnet/test/Gremlin.Net.UnitTest/Process/Traversal/BytecodeTests.cs
----------------------------------------------------------------------
diff --git 
a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Process/Traversal/BytecodeTests.cs 
b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Process/Traversal/BytecodeTests.cs
index da77223..64f2f87 100644
--- 
a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Process/Traversal/BytecodeTests.cs
+++ 
b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Process/Traversal/BytecodeTests.cs
@@ -21,6 +21,9 @@
 
 #endregion
 
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
 using Gremlin.Net.Process.Traversal;
 using Xunit;
 
@@ -29,16 +32,145 @@ namespace Gremlin.Net.UnitTest.Process.Traversal
     public class BytecodeTests
     {
         [Fact]
-        public void ShouldUseBingings()
+        public void ShouldUseBingingsForSimpleValueInStepArgument()
         {
             var bytecode = new Bytecode();
-            var bindings = new Bindings();
+            var bindings = Bindings.Instance;
 
-            bytecode.AddStep("hasLabel", bindings.Of("label", "testLabel"));
+            bytecode.AddStep("hasLabel", bindings.Of("label", "testvalue"));
+
+            Assert.Equal(new Binding("label", "testvalue"), 
bytecode.StepInstructions[0].Arguments[0]);
+        }
+
+        [Fact]
+        public void ShouldUseBindingsInsideArrayInStepArgument()
+        {
+            var bytecode = new Bytecode();
+            var b = Bindings.Instance;
+
+            bytecode.AddStep("someStep", "test", new[] {b.Of("arrayVariable", 
"arrayValue")});
+
+            Assert.Equal(new Binding("arrayVariable", "arrayValue"), 
bytecode.StepInstructions[0].Arguments[1]);
+        }
+
+        [Fact]
+        public void ShouldUseBindingsInsideDictionaryValuesInStepArgument()
+        {
+            var bytecode = new Bytecode();
+            var b = Bindings.Instance;
+
+            bytecode.AddStep("someStep", new Dictionary<string, object> 
{{"someKey", b.Of("valVariable", "valValue")}});
+
+            var arg = bytecode.StepInstructions[0].Arguments[0] as IDictionary;
+            Assert.Equal(new Binding("valVariable", "valValue"), 
arg["someKey"]);
+        }
+
+        [Fact]
+        public void ShouldUseBindingsInsideDictionaryKeysInStepArgument()
+        {
+            var bytecode = new Bytecode();
+            var b = Bindings.Instance;
+
+            bytecode.AddStep("someStep", new Dictionary<string, object> 
{{b.Of("keyVariable", "keyValue"), 1234}});
 
             var arg = bytecode.StepInstructions[0].Arguments[0];
-            var binding = arg as Binding;
-            Assert.Equal(new Binding("label", "testLabel"), binding);
+            var binding = ((Dictionary<object, object>) arg).Keys.First() as 
Binding;
+            Assert.Equal(new Binding("keyVariable", "keyValue"), binding);
+        }
+
+        [Fact]
+        public void ShouldUseBindingsInsideListInStepArgument()
+        {
+            var bytecode = new Bytecode();
+            var b = Bindings.Instance;
+
+            bytecode.AddStep("someStep", new List<string> {"test", 
b.Of("listVariable", "listValue")});
+
+            var arg = bytecode.StepInstructions[0].Arguments[0] as IList;
+            Assert.Equal(new Binding("listVariable", "listValue"), arg[1]);
+        }
+
+        [Fact]
+        public void ShouldUseBindingsInsideHashSetInStepArgument()
+        {
+            var bytecode = new Bytecode();
+            var b = Bindings.Instance;
+
+            bytecode.AddStep("someStep", new HashSet<string> { "test", 
b.Of("setVariable", "setValue") });
+
+            var arg = bytecode.StepInstructions[0].Arguments[0] as 
ISet<object>;
+            Assert.Equal(new Binding("setVariable", "setValue"), 
arg.ToList()[1]);
+        }
+
+        [Fact]
+        public void ShouldUseBingingsForSimpleValueInSourceArgument()
+        {
+            var bytecode = new Bytecode();
+            var bindings = Bindings.Instance;
+
+            bytecode.AddSource("hasLabel", bindings.Of("label", "testvalue"));
+
+            Assert.Equal(new Binding("label", "testvalue"), 
bytecode.SourceInstructions[0].Arguments[0]);
+        }
+
+        [Fact]
+        public void ShouldUseBindingsInsideArrayInSourceArgument()
+        {
+            var bytecode = new Bytecode();
+            var b = Bindings.Instance;
+
+            bytecode.AddSource("someSource", "test", new[] { 
b.Of("arrayVariable", "arrayValue") });
+
+            Assert.Equal(new Binding("arrayVariable", "arrayValue"), 
bytecode.SourceInstructions[0].Arguments[1]);
+        }
+
+        [Fact]
+        public void ShouldUseBindingsInsideDictionaryValuesInSourceArgument()
+        {
+            var bytecode = new Bytecode();
+            var b = Bindings.Instance;
+
+            bytecode.AddSource("someSource", new Dictionary<string, object> { 
{ "someKey", b.Of("valVariable", "valValue") } });
+
+            var arg = bytecode.SourceInstructions[0].Arguments[0] as 
IDictionary;
+            Assert.Equal(new Binding("valVariable", "valValue"), 
arg["someKey"]);
+        }
+
+        [Fact]
+        public void ShouldUseBindingsInsideDictionaryKeysInSourceArgument()
+        {
+            var bytecode = new Bytecode();
+            var b = Bindings.Instance;
+
+            bytecode.AddSource("someSource", new Dictionary<string, object> { 
{ b.Of("keyVariable", "keyValue"), 1234 } });
+
+            var arg = bytecode.SourceInstructions[0].Arguments[0];
+            var binding = ((Dictionary<object, object>)arg).Keys.First() as 
Binding;
+            Assert.Equal(new Binding("keyVariable", "keyValue"), binding);
+        }
+
+        [Fact]
+        public void ShouldUseBindingsInsideListInSourceArgument()
+        {
+            var bytecode = new Bytecode();
+            var b = Bindings.Instance;
+
+            bytecode.AddSource("someSource", new List<string> { "test", 
b.Of("listVariable", "listValue") });
+
+            var arg = bytecode.SourceInstructions[0].Arguments[0] as IList;
+            Assert.Equal(new Binding("listVariable", "listValue"), arg[1]);
+        }
+
+        [Fact]
+        public void ShouldUseBindingsInsideHashSetInSourceArgument()
+        {
+            var bytecode = new Bytecode();
+            var b = Bindings.Instance;
+
+            bytecode.AddSource("someSource", new HashSet<string> { "test", 
b.Of("setVariable", "setValue") });
+
+            var arg = bytecode.SourceInstructions[0].Arguments[0] as 
ISet<object>;
+            Assert.Equal(new Binding("setVariable", "setValue"), 
arg.ToList()[1]);
         }
     }
 }
\ No newline at end of file

Reply via email to