Use non-dynamic traversal evaluation and support numeric conversion
Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/9672dd04 Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/9672dd04 Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/9672dd04 Branch: refs/heads/master Commit: 9672dd048b48a186df41b5f8309c95393f799c9e Parents: 5d15f2e Author: Jorge Bay Gondra <jorgebaygon...@gmail.com> Authored: Tue Nov 21 11:44:03 2017 +0100 Committer: Jorge Bay Gondra <jorgebaygon...@gmail.com> Committed: Thu Nov 30 10:01:21 2017 +0100 ---------------------------------------------------------------------- .../Gherkin/CommonSteps.cs | 52 +++++++++++++++----- .../Gherkin/GherkinTestRunner.cs | 33 +------------ .../Gherkin/ScenarioData.cs | 40 ++++++++++++--- .../ModernGraphTypeInformation.cs | 29 +++-------- .../TraversalEvaluationTests.cs | 10 ++-- .../TraversalEvaluation/TraversalParser.cs | 13 +++-- 6 files changed, 98 insertions(+), 79 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9672dd04/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs ---------------------------------------------------------------------- diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs index 9bc36a6..fda44b8 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs @@ -41,13 +41,13 @@ namespace Gremlin.Net.IntegrationTest.Gherkin private GraphTraversalSource _g; private string _graphName; private readonly IDictionary<string, object> _parameters = new Dictionary<string, object>(); - private dynamic _traversal; + private ITraversal _traversal; private object[] _result; private static readonly IDictionary<Regex, Func<string, string, object>> Parsers = new Dictionary<string, Func<string, string, object>> { - {@"d\[([\d.]+)\]\.([ilfd])", ToNumber}, + {@"d\[([\d.]+)\]\.([ilfdm])", ToNumber}, {@"v\[(.+)\]", ToVertex}, {@"v\[(.+)\]\.id", (x, graphName) => ToVertex(x, graphName).Id}, {@"v\[(.+)\]\.sid", (x, graphName) => ToVertex(x, graphName).Id.ToString()}, @@ -55,8 +55,8 @@ namespace Gremlin.Net.IntegrationTest.Gherkin {@"e\[(.+)\].id", (x, graphName) => ToEdge(x, graphName).Id}, {@"e\[(.+)\].sid", (x, graphName) => ToEdge(x, graphName).Id.ToString()}, {@"p\[(.+)\]", ToPath}, - {@"l\[(.+)\]", ToList}, - {@"s\[(.+)\]", ToSet}, + {@"l\[(.*)\]", ToList}, + {@"s\[(.*)\]", ToSet}, {@"m\[(.+)\]", ToMap}, {@"c\[(.+)\]", ToLambda} }.ToDictionary(kv => new Regex("^" + kv.Key + "$", RegexOptions.Compiled), kv => kv.Value); @@ -67,7 +67,8 @@ namespace Gremlin.Net.IntegrationTest.Gherkin { 'i', s => Convert.ToInt32(s) }, { 'l', s => Convert.ToInt64(s) }, { 'f', s => Convert.ToSingle(s) }, - { 'd', s => Convert.ToDouble(s) } + { 'd', s => Convert.ToDouble(s) }, + { 'm', s => Convert.ToDecimal(s)} }; [Given("the (\\w+) graph")] @@ -121,22 +122,41 @@ namespace Gremlin.Net.IntegrationTest.Gherkin [When("iterated to list")] public void IterateToList() { - if (!(_traversal is ITraversal)) + if (_traversal == null) { throw new InvalidOperationException("Traversal should be set before iterating"); } - IEnumerable enumerable = _traversal.ToList(); - _result = enumerable.Cast<object>().ToArray(); + ITraversal t = _traversal; + var list = new List<object>(); + while (t.MoveNext()) + { + list.Add(t.Current); + } + _result = list.ToArray(); } [When("iterated next")] public void IterateNext() { - if (!(_traversal is ITraversal)) + if (_traversal == null) { throw new InvalidOperationException("Traversal should be set before iterating"); } - _result = _traversal.Next(); + _traversal.MoveNext(); + var result = _traversal.Current; + switch (result) + { + case null: + _result = null; + return; + case object[] arrayResult: + _result = arrayResult; + return; + case IEnumerable enumerableResult: + _result = enumerableResult.Cast<object>().ToArray(); + return; + } + throw new InvalidCastException($"Can not convert instance of {result.GetType()} to object[]"); } [Then("the result should be (\\w+)")] @@ -150,6 +170,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin return; case "ordered": case "unordered": + case "of": Assert.NotNull(table); var rows = table.Rows.ToArray(); Assert.Equal("result", rows[0].Cells.First().Value); @@ -165,7 +186,10 @@ namespace Gremlin.Net.IntegrationTest.Gherkin { Assert.Contains(resultItem, expectedArray); } - Assert.Equal(expectedArray.Length, _result.Length); + if (characterizedAs != "of") + { + Assert.Equal(expectedArray.Length, _result.Length); + } } break; default: @@ -248,7 +272,11 @@ namespace Gremlin.Net.IntegrationTest.Gherkin private static IList<object> ToList(string stringList, string graphName) { - return stringList.Split(',').Select(x => ParseValue(x, graphName)).ToArray(); + if (stringList == "") + { + return new List<object>(0); + } + return stringList.Split(',').Select(x => ParseValue(x, graphName)).ToList(); } private static Vertex ToVertex(string name, string graphName) http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9672dd04/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/GherkinTestRunner.cs ---------------------------------------------------------------------- diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/GherkinTestRunner.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/GherkinTestRunner.cs index cd03eca..dd5fbca 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/GherkinTestRunner.cs +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/GherkinTestRunner.cs @@ -53,11 +53,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin { "g_V_outXcreatedX_groupCount_byXnameX", IgnoreReason.MapCoersionIssue}, { "g_V_chooseXlabel_is_person__unionX__out_lang__out_nameX__in_labelX_groupCount", IgnoreReason .MapCoersionIssue}, - { "g_V_coalesceXoutXlikesX_outXknowsX_inXcreatedXX_groupCount_byXnameX", IgnoreReason.MapCoersionIssue}, - - { "g_withSackX0X_V_outE_sackXsumX_byXweightX_inV_sack_sum", IgnoreReason.ScenarioDesignMapNumbers}, - { "g_V_hasLabelXsoftwareX_group_byXnameX_byXbothE_weight_meanX", IgnoreReason.ScenarioDesignMapNumbers}, - { "g_V_groupXaX_byXlabelX_byXoutE_weight_sumX_capXaX", IgnoreReason.ScenarioDesignMapNumbers} + { "g_V_coalesceXoutXlikesX_outXknowsX_inXcreatedXX_groupCount_byXnameX", IgnoreReason.MapCoersionIssue} }; private static class Keywords @@ -136,7 +132,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin } } OutputResults(results); - Console.WriteLine("Finished Gherkin-based tests"); + WriteOutput("Finished Gherkin-based tests"); ScenarioData.Shutdown(); } @@ -367,35 +363,10 @@ namespace Gremlin.Net.IntegrationTest.Gherkin { var rootPath = GetRootPath(); var path = Path.Combine(rootPath, "gremlin-test", "features"); - WriteOutput(path); - WriteOutput("------"); - -// var files = new [] -// { -// "/Users/jorge/workspace/tinkerpop/gremlin-test/features/map/Sum.feature", -//// "/Users/jorge/workspace/tinkerpop/gremlin-test/features/map/Coalesce.feature", -// "/Users/jorge/workspace/tinkerpop/gremlin-test/features/map/AddEdge.feature", -// "/Users/jorge/workspace/tinkerpop/gremlin-test/features/map/AddVertex.feature", -// "/Users/jorge/workspace/tinkerpop/gremlin-test/features/map/ValueMap.feature", -// "/Users/jorge/workspace/tinkerpop/gremlin-test/features/map/Select.feature", -// "/Users/jorge/workspace/tinkerpop/gremlin-test/features/map/Project.feature", -// "/Users/jorge/workspace/tinkerpop/gremlin-test/features/map/Path.feature", -// "/Users/jorge/workspace/tinkerpop/gremlin-test/features/map/Map.feature", -// "/Users/jorge/workspace/tinkerpop/gremlin-test/features/map/Match.feature", -// "/Users/jorge/workspace/tinkerpop/gremlin-test/features/map/Max.feature", -// "/Users/jorge/workspace/tinkerpop/gremlin-test/features/map/Mean.feature", -// -// "/Users/jorge/workspace/tinkerpop/gremlin-test/features/sideEffect/Sack.feature", -// "/Users/jorge/workspace/tinkerpop/gremlin-test/features/sideEffect/Group.feature", -//// "/Users/jorge/workspace/tinkerpop/gremlin-test/features/sideEffect/GroupCount.feature", -//// "/Users/jorge/workspace/tinkerpop/gremlin-test/features/sideEffect/Inject.feature", -// }; -// var files = new [] {"/Users/jorge/workspace/temp/count.feature"}; var files = Directory.GetFiles(path, "*.feature", SearchOption.AllDirectories); foreach (var gherkinFile in files) { var parser = new Parser(); - WriteOutput("Parsing " + gherkinFile); var doc = parser.Parse(gherkinFile); yield return doc.Feature; } http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9672dd04/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/ScenarioData.cs ---------------------------------------------------------------------- diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/ScenarioData.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/ScenarioData.cs index 919da0b..ed767d5 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/ScenarioData.cs +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/ScenarioData.cs @@ -23,8 +23,10 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Linq; using System.Text.RegularExpressions; +using Gremlin.Net.Driver.Exceptions; using Gremlin.Net.IntegrationTest.Process.Traversal.DriverRemoteConnection; using Gremlin.Net.Process.Remote; using Gremlin.Net.Process.Traversal; @@ -41,6 +43,12 @@ namespace Gremlin.Net.IntegrationTest.Gherkin private static readonly Regex EdgeIRegex = new Regex("i=(.+?)[,}]", RegexOptions.Compiled); private static readonly string[] GraphNames = {"modern", "classic", "crew", "grateful"}; + + private static readonly IDictionary<string, Vertex> EmptyVertices = + new ReadOnlyDictionary<string, Vertex>(new Dictionary<string, Vertex>()); + + private static readonly IDictionary<string, Edge> EmptyEdges = + new ReadOnlyDictionary<string, Edge>(new Dictionary<string, Edge>()); private static readonly RemoteConnectionFactory ConnectionFactory = new RemoteConnectionFactory(); @@ -99,18 +107,34 @@ namespace Gremlin.Net.IntegrationTest.Gherkin private static IDictionary<string, Vertex> GetVertices(GraphTraversalSource g) { - return g.V().Group<string, object>().By("name").By(__.Tail<Vertex>()).Next() - .ToDictionary(kv => kv.Key, kv => (Vertex)kv.Value); + try + { + return g.V().Group<string, object>().By("name").By(__.Tail<Vertex>()).Next() + .ToDictionary(kv => kv.Key, kv => (Vertex) kv.Value); + } + catch (ResponseException) + { + // Property name might not exist + return EmptyVertices; + } } private static IDictionary<string, Edge> GetEdges(GraphTraversalSource g) { - return g.E().Group<string, object>() - .By(__.Project<Edge>("o", "l", "i") - .By(__.OutV().Values<string>("name")).By(__.Label()).By(__.InV().Values<string>("name"))) - .By(__.Tail<object>()) - .Next() - .ToDictionary(kv => GetEdgeKey(kv.Key), kv => (Edge)kv.Value); + try + { + return g.E().Group<string, object>() + .By(__.Project<Edge>("o", "l", "i") + .By(__.OutV().Values<string>("name")).By(__.Label()).By(__.InV().Values<string>("name"))) + .By(__.Tail<object>()) + .Next() + .ToDictionary(kv => GetEdgeKey(kv.Key), kv => (Edge)kv.Value); + } + catch (ResponseException) + { + // Property name might not exist + return EmptyEdges; + } } private static string GetEdgeKey(string key) http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9672dd04/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/ModernGraphTypeInformation.cs ---------------------------------------------------------------------- diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/ModernGraphTypeInformation.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/ModernGraphTypeInformation.cs index 3125aab..aec3d3e 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/ModernGraphTypeInformation.cs +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/ModernGraphTypeInformation.cs @@ -45,6 +45,12 @@ namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation /// </summary>s public static Type GetTypeArguments(MethodInfo method, object[] parameterValues, int genericTypeIndex) { + var isGeneric = method.DeclaringType.GetTypeInfo().IsGenericType; + if (!isGeneric) + { + // Maintain object for anonymous traversal + return typeof(object); + } switch (method.Name) { case nameof(GraphTraversal<object,object>.Properties): @@ -68,31 +74,10 @@ namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation case nameof(GraphTraversal<object,object>.Match): // Maintain the same type return method.DeclaringType.GetGenericArguments()[1]; - case nameof(GraphTraversal<object,object>.ValueMap): - case nameof(GraphTraversal<object,object>.Select): - case nameof(GraphTraversal<object,object>.Group): - case nameof(GraphTraversal<object,object>.GroupCount): - case nameof(GraphTraversal<object,object>.Unfold): - case nameof(GraphTraversal<object,object>.Choose): - case nameof(GraphTraversal<object,object>.Union): - case nameof(GraphTraversal<object,object>.Project): - case nameof(GraphTraversal<object,object>.Sack): - case nameof(GraphTraversal<object,object>.Map): - case nameof(GraphTraversal<object,object>.Max): - case nameof(GraphTraversal<object,object>.Min): - case nameof(GraphTraversal<object,object>.Mean): - case nameof(GraphTraversal<object,object>.Cap): - case nameof(GraphTraversal<object,object>.Constant): - case nameof(GraphTraversal<object,object>.Branch): - case nameof(GraphTraversal<object,object>.Local): - case nameof(GraphTraversal<object,object>.Tail): - case nameof(GraphTraversal<object,object>.Range): - case nameof(GraphTraversal<object,object>.Value): - case nameof(GraphTraversal<object,object>.Fold): + default: // default to object for this methods return typeof(object); } - return null; } private static Type GetElementPropertyType(string name) http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9672dd04/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TraversalEvaluationTests.cs ---------------------------------------------------------------------- diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TraversalEvaluationTests.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TraversalEvaluationTests.cs index 3907dd2..94a8c99 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TraversalEvaluationTests.cs +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TraversalEvaluationTests.cs @@ -42,8 +42,8 @@ namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation new[] {new Token("constant", new[] {LiteralParameter.Create(123L)})}), Tuple.Create("g.V().constant(123)", new[] {new Token("constant", new[] {LiteralParameter.Create(123)})}), - Tuple.Create("g.V().constant(123.1)", - new[] {new Token("constant", new[] {LiteralParameter.Create(123.1)})}), + Tuple.Create("g.V().constant(123.50)", + new[] {new Token("constant", new[] {LiteralParameter.Create(123.50m)})}), Tuple.Create("g.V().constant(123.1f)", new[] {new Token("constant", new[] {LiteralParameter.Create(123.1f)})}), Tuple.Create("g.V().has(\"no\").count()", @@ -96,7 +96,11 @@ namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation Tuple.Create( "g.V().hasLabel(\"software\").group().by(\"name\").by(__.bothE().values(\"weight\").sum())", 5), Tuple.Create("g.V().choose(__.outE().count().is(0L),__.as(\"a\"),__.as(\"b\"))" + - "\n.choose(__.select(\"a\"),__.select(\"a\"),__.select(\"b\"))", 3) + "\n.choose(__.select(\"a\"),__.select(\"a\"),__.select(\"b\"))", 3), + Tuple.Create("g.V().repeat(__.out()).times(2) ", 3), + Tuple.Create("g.V().local(__.match(\n __.as(\"project\").in(\"created\").as(\"person\"),\n__.as(\"person\").values(\"name\").as(\"name\"))).select(\"name\", \"project\").by().by(\"name\")", 5), + Tuple.Create("g.V().as(\"a\").out().as(\"a\").out().as(\"a\").select(\"a\").by(__.unfold().values(\"name\").fold()).tail(Scope.local, 2)", 9), + Tuple.Create("g.V().coin(1.0)", 2) }; var g = new Graph().Traversal(); foreach (var tuple in traversalTexts) http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9672dd04/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TraversalParser.cs ---------------------------------------------------------------------- diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TraversalParser.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TraversalParser.cs index 66aae70..827960d 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TraversalParser.cs +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TraversalParser.cs @@ -244,6 +244,12 @@ namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation // if we have the type of value we have the type of E2. genericParameterTypes.Add(info.ParameterType.Name, tokenParameter.GetParameterType()); } + if (info.ParameterType != tokenParameter.GetParameterType() && IsNumeric(info.ParameterType) && + IsNumeric(tokenParameter.GetParameterType())) + { + // Numeric conversion + value = Convert.ChangeType(value, info.ParameterType); + } } if (IsParamsArray(info)) { @@ -332,8 +338,9 @@ namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation parameters.Add(param); break; } - case ',' when text[i+1] != ' ' && parsing == ParsingPart.StartParameters: - case ' ' when text[i+1] != ' ' && text[i+1] != ')' && parsing == ParsingPart.StartParameters: + case ',' when parsing == ParsingPart.StartParameters && text.Length > i + 1 && text[i+1] != ' ': + case ' ' when parsing == ParsingPart.StartParameters && text.Length > i + 1 && text[i+1] != ' ' && + text[i+1] != ')': { i++; var param = ParseParameter(text, ref i); @@ -450,7 +457,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation if (match.Groups[1].Value != "") { // Captured text with the decimal separator - return LiteralParameter.Create(Convert.ToDouble(match.Value)); + return LiteralParameter.Create(Convert.ToDecimal(match.Value)); } return LiteralParameter.Create(Convert.ToInt32(match.Value)); }