This is an automated email from the ASF dual-hosted git repository. spmallette pushed a commit to branch TINKERPOP-2681 in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit 780e720c6e4854e74f096b1973d3692efdfac499 Author: Stephen Mallette <[email protected]> AuthorDate: Fri Jan 21 16:19:29 2022 -0500 wip --- docs/src/dev/io/graphbinary.asciidoc | 5 ++ .../traversal/step/map/MergeVertexStep.java | 2 +- .../traversal/translator/DotNetTranslator.java | 29 ++++++++++ .../traversal/translator/GroovyTranslator.java | 2 +- .../gremlin/structure/io/binary/DataType.java | 1 + .../io/binary/TypeSerializerRegistry.java | 2 + .../structure/io/binary/types/EnumSerializer.java | 2 + .../structure/io/graphson/GraphSONModule.java | 7 +++ .../Process/Traversal/GraphTraversal.cs | 46 ++++++++++++++++ .../Process/Traversal/GraphTraversalSource.cs | 54 +++++++++++++++++-- .../src/Gremlin.Net/Process/Traversal/Merge.cs | 63 ++++++++++++++++++++++ .../Structure/IO/GraphBinary/DataType.cs | 1 + .../IO/GraphBinary/TypeSerializerRegistry.cs | 2 + .../IO/GraphBinary/Types/EnumSerializer.cs | 6 +++ .../Structure/IO/GraphSON/GraphSONReader.cs | 1 + .../Structure/IO/GraphSON/MergeDeserializer.cs | 36 +++++++++++++ .../Gherkin/CommonSteps.cs | 9 +++- .../Gherkin/GherkinTestRunner.cs | 5 ++ .../Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs | 51 +++++++++--------- .../Gherkin/IgnoreException.cs | 9 +++- .../Structure/IO/GraphBinary/GraphBinaryTests.cs | 15 ++++++ .../Structure/IO/GraphSON/GraphSONReaderTests.cs | 12 +++++ .../Structure/IO/GraphSON/GraphSONWriterTests.cs | 13 ++++- .../gremlin/driver/message/RequestMessage.java | 3 +- .../lib/process/graph-traversal.js | 20 +++++++ .../test/cucumber/feature-steps.js | 8 ++- .../gremlin-javascript/test/cucumber/gremlin.js | 3 +- .../language/grammar/ReferenceGrammarTest.java | 2 +- gremlin-python/build/generate.groovy | 2 +- .../gremlin_python/process/graph_traversal.py | 38 +++++++++++++ .../python/gremlin_python/process/traversal.py | 5 ++ .../gremlin_python/structure/io/graphbinaryV1.py | 10 +++- .../src/main/python/radish/feature_steps.py | 8 ++- gremlin-python/src/main/python/radish/gremlin.py | 5 +- .../tests/driver/test_driver_remote_connection.py | 1 + .../tests/structure/io/test_graphbinaryV1.py | 7 ++- .../handler/WsGremlinBinaryRequestDecoder.java | 1 + .../handler/WsGremlinTextRequestDecoder.java | 1 + gremlin-test/features/sideEffect/Group.feature | 22 ++++---- gremlin-test/features/sideEffect/Inject.feature | 7 ++- .../tinkerpop/gremlin/features/StepDefinition.java | 5 +- .../traversal/step/map/TinkerMergeVertexStep.java | 1 + .../gremlin/tinkergraph/TinkerGraphWorld.java | 1 + 43 files changed, 454 insertions(+), 69 deletions(-) diff --git a/docs/src/dev/io/graphbinary.asciidoc b/docs/src/dev/io/graphbinary.asciidoc index 065370a..f3b0a82 100644 --- a/docs/src/dev/io/graphbinary.asciidoc +++ b/docs/src/dev/io/graphbinary.asciidoc @@ -107,6 +107,7 @@ Changes to existing types require new revision. - `0x2b`: Tree - `0x2c`: Metrics - `0x2d`: TraversalMetrics +- `0x2e`: Merge - `0xfe`: Unspecified null object - `0x00`: Custom @@ -567,6 +568,10 @@ Where: - `{duration}` is a `Long` describing the duration in nanoseconds. - `{metrics}` is a `List` composed by `Metrics` items. +==== Merge + +Format: a single `String` representing the enum value. + ==== Custom A custom type, represented as a blob value. diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeVertexStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeVertexStep.java index 319db5d..365d83a 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeVertexStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeVertexStep.java @@ -60,7 +60,7 @@ public class MergeVertexStep<S> extends FlatMapStep<S, Vertex> implements Mutati private Traversal.Admin<S, Map<Object, Object>> onCreateTraversal = null; private Traversal.Admin<S, Map<String, Object>> onMatchTraversal = null; - private CallbackRegistry<Event> callbackRegistry; + protected CallbackRegistry<Event> callbackRegistry; public MergeVertexStep(final Traversal.Admin traversal, final boolean isStart, final Map<Object, Object> searchCreate) { this(traversal, isStart, new ConstantTraversal<>(searchCreate)); diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/DotNetTranslator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/DotNetTranslator.java index 5f3ae25..6bd3442 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/DotNetTranslator.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/DotNetTranslator.java @@ -21,12 +21,14 @@ package org.apache.tinkerpop.gremlin.process.traversal.translator; import org.apache.commons.text.StringEscapeUtils; import org.apache.tinkerpop.gremlin.process.traversal.Bytecode; +import org.apache.tinkerpop.gremlin.process.traversal.Merge; import org.apache.tinkerpop.gremlin.process.traversal.P; import org.apache.tinkerpop.gremlin.process.traversal.Pick; import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions; import org.apache.tinkerpop.gremlin.process.traversal.Script; import org.apache.tinkerpop.gremlin.process.traversal.TextP; import org.apache.tinkerpop.gremlin.process.traversal.Translator; +import org.apache.tinkerpop.gremlin.process.traversal.Traversal; import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource; import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; @@ -345,6 +347,33 @@ public final class DotNetTranslator implements Translator.ScriptTranslator { script.append(", (").append(castSecondArgTo).append(") "); convertToScript(instruction.getArguments()[1]); script.append(","); + } else if (methodName.equals(GraphTraversal.Symbols.mergeE) || methodName.equals(GraphTraversal.Symbols.mergeV)) { + // there must be at least one argument - if null go with Map + final Object instArg = instruction.getArguments()[0]; + if (null == instArg) { + script.append("(IDictionary<object,object>) null"); + } else { + if (instArg instanceof Traversal) { + script.append("(ITraversal) "); + } else { + script.append("(IDictionary<object,object>) "); + } + convertToScript(instArg); + script.append(")"); + } + } else if (methodName.equals(GraphTraversal.Symbols.option) && + instruction.getArguments().length == 2 && instruction.getArguments()[0] instanceof Merge) { + final Object[] instArgs = instruction.getArguments(); + // trying to catch option(Merge,Traversal|Map) + convertToScript(instArgs[0]); + script.append(", "); + if (instArgs[1] instanceof Traversal) { + script.append("(ITraversal) "); + } else { + script.append("(IDictionary<object,object>) "); + } + convertToScript(instArgs[1]); + script.append(")"); } else { final Object[] instArgs = instruction.getArguments(); for (int idx = 0; idx < instArgs.length; idx++) { diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslator.java index bfa3065..0143c27 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslator.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslator.java @@ -174,7 +174,7 @@ public final class GroovyTranslator implements Translator.ScriptTranslator { @Override protected String getSyntax(final Pick o) { - return "TraversalOptionParent.Pick." + o.toString(); + return "Pick." + o.toString(); } @Override diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/DataType.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/DataType.java index 0159d4f..75b8060 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/DataType.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/DataType.java @@ -70,6 +70,7 @@ public enum DataType { TREE(0X2B), METRICS(0x2C), TRAVERSALMETRICS(0x2D), + MERGE(0x2E), CHAR(0X80), DURATION(0X81), diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/TypeSerializerRegistry.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/TypeSerializerRegistry.java index 0c4b913..4edcad2 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/TypeSerializerRegistry.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/TypeSerializerRegistry.java @@ -18,6 +18,7 @@ */ package org.apache.tinkerpop.gremlin.structure.io.binary; +import org.apache.tinkerpop.gremlin.process.traversal.Merge; import org.apache.tinkerpop.gremlin.process.traversal.Pick; import org.apache.tinkerpop.gremlin.structure.io.binary.types.*; import org.apache.tinkerpop.gremlin.process.traversal.Bytecode; @@ -117,6 +118,7 @@ public class TypeSerializerRegistry { new RegistryEntry<>(VertexProperty.Cardinality.class, EnumSerializer.CardinalitySerializer), new RegistryEntry<>(Column.class, EnumSerializer.ColumnSerializer), new RegistryEntry<>(Direction.class, EnumSerializer.DirectionSerializer), + new RegistryEntry<>(Merge.class, EnumSerializer.MergeSerializer), new RegistryEntry<>(Operator.class, EnumSerializer.OperatorSerializer), new RegistryEntry<>(Order.class, EnumSerializer.OrderSerializer), new RegistryEntry<>(Pick.class, EnumSerializer.PickSerializer), diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/EnumSerializer.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/EnumSerializer.java index 52b4c08..41cf7fc 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/EnumSerializer.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/EnumSerializer.java @@ -18,6 +18,7 @@ */ package org.apache.tinkerpop.gremlin.structure.io.binary.types; +import org.apache.tinkerpop.gremlin.process.traversal.Merge; import org.apache.tinkerpop.gremlin.process.traversal.Pick; import org.apache.tinkerpop.gremlin.structure.io.binary.DataType; import org.apache.tinkerpop.gremlin.structure.io.binary.GraphBinaryReader; @@ -47,6 +48,7 @@ public class EnumSerializer<E extends Enum> extends SimpleTypeSerializer<E> { public static final EnumSerializer<VertexProperty.Cardinality> CardinalitySerializer = new EnumSerializer<>(DataType.CARDINALITY, VertexProperty.Cardinality::valueOf); public static final EnumSerializer<Column> ColumnSerializer = new EnumSerializer<>(DataType.COLUMN, Column::valueOf); public static final EnumSerializer<Direction> DirectionSerializer = new EnumSerializer<>(DataType.DIRECTION, Direction::valueOf); + public static final EnumSerializer<Merge> MergeSerializer = new EnumSerializer<>(DataType.MERGE, Merge::valueOf); public static final EnumSerializer<Operator> OperatorSerializer = new EnumSerializer<>(DataType.OPERATOR, Operator::valueOf); public static final EnumSerializer<Order> OrderSerializer = new EnumSerializer<>(DataType.ORDER, Order::valueOf); public static final EnumSerializer<Pick> PickSerializer = new EnumSerializer<>(DataType.PICK, Pick::valueOf); diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java index fccab3f..82d818f 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java @@ -21,6 +21,7 @@ package org.apache.tinkerpop.gremlin.structure.io.graphson; import org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy; import org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.optimization.GraphFilterStrategy; import org.apache.tinkerpop.gremlin.process.traversal.Bytecode; +import org.apache.tinkerpop.gremlin.process.traversal.Merge; import org.apache.tinkerpop.gremlin.process.traversal.Operator; import org.apache.tinkerpop.gremlin.process.traversal.Order; import org.apache.tinkerpop.gremlin.process.traversal.P; @@ -174,6 +175,7 @@ abstract class GraphSONModule extends TinkerPopJacksonModule { VertexProperty.Cardinality.class, Column.class, Direction.class, + Merge.class, Operator.class, Order.class, Pop.class, @@ -257,6 +259,7 @@ abstract class GraphSONModule extends TinkerPopJacksonModule { Stream.of(VertexProperty.Cardinality.class, Column.class, Direction.class, + Merge.class, Operator.class, Order.class, Pop.class, @@ -299,6 +302,7 @@ abstract class GraphSONModule extends TinkerPopJacksonModule { Stream.of(VertexProperty.Cardinality.values(), Column.values(), Direction.values(), + Merge.values(), Operator.values(), Order.values(), Pop.values(), @@ -412,6 +416,7 @@ abstract class GraphSONModule extends TinkerPopJacksonModule { VertexProperty.Cardinality.class, Column.class, Direction.class, + Merge.class, Operator.class, Order.class, Pop.class, @@ -491,6 +496,7 @@ abstract class GraphSONModule extends TinkerPopJacksonModule { Stream.of(VertexProperty.Cardinality.class, Column.class, Direction.class, + Merge.class, Operator.class, Order.class, Pop.class, @@ -527,6 +533,7 @@ abstract class GraphSONModule extends TinkerPopJacksonModule { Stream.of(VertexProperty.Cardinality.values(), Column.values(), Direction.values(), + Merge.values(), Operator.values(), Order.values(), Pop.values(), diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs index ebd1cdf..59ecb1a 100644 --- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs +++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs @@ -1090,6 +1090,43 @@ namespace Gremlin.Net.Process.Traversal } /// <summary> + /// Adds the mergeE step to this <see cref="GraphTraversal{SType, EType}" />. + /// </summary> + public GraphTraversal<S, Edge> MergeE (IDictionary<object,object> m) + { + Bytecode.AddStep("mergeE", m); + return Wrap<S, Edge>(this); + } + + /// <summary> + /// Adds the mergeE step to this <see cref="GraphTraversal{SType, EType}" />. + /// </summary> + public GraphTraversal<S, Edge> MergeE (ITraversal t) + { + Bytecode.AddStep("mergeE", t); + return Wrap<S, Edge>(this); + } + + /// <summary> + /// Adds the mergeV step to this <see cref="GraphTraversal{SType, EType}" />. + /// </summary> + public GraphTraversal<S, Vertex> MergeV (IDictionary<object,object> m) + { + Bytecode.AddStep("mergeV", m); + return Wrap<S, Vertex>(this); + } + + /// <summary> + /// Adds the mergeV step to this <see cref="GraphTraversal{SType, EType}" />. + /// </summary> + public GraphTraversal<S, Vertex> MergeV (ITraversal t) + { + Bytecode.AddStep("mergeV", t); + return Wrap<S, Vertex>(this); + } + + + /// <summary> /// Adds the min step to this <see cref="GraphTraversal{SType, EType}" />. /// </summary> public GraphTraversal<S, E2> Min<E2> () @@ -1137,6 +1174,15 @@ namespace Gremlin.Net.Process.Traversal /// <summary> /// Adds the option step to this <see cref="GraphTraversal{SType, EType}" />. /// </summary> + public GraphTraversal<S, E> Option (object pickToken, IDictionary<object,object> traversalOption) + { + Bytecode.AddStep("option", pickToken, traversalOption); + return Wrap<S, E>(this); + } + + /// <summary> + /// Adds the option step to this <see cref="GraphTraversal{SType, EType}" />. + /// </summary> public GraphTraversal<S, E> Option (ITraversal traversalOption) { Bytecode.AddStep("option", traversalOption); diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversalSource.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversalSource.cs index ae5b1d9..5ad2f7d 100644 --- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversalSource.cs +++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversalSource.cs @@ -336,7 +336,7 @@ namespace Gremlin.Net.Process.Traversal public GraphTraversal<Edge, Edge> AddE(string label) { var traversal = new GraphTraversal<Edge, Edge>(TraversalStrategies, new Bytecode(Bytecode)); - traversal.Bytecode.AddStep("addE", label); + traversal.Bytecode.AddStep("addE", label); return traversal; } @@ -347,7 +347,29 @@ namespace Gremlin.Net.Process.Traversal public GraphTraversal<Edge, Edge> AddE(ITraversal edgeLabelTraversal) { var traversal = new GraphTraversal<Edge, Edge>(TraversalStrategies, new Bytecode(Bytecode)); - traversal.Bytecode.AddStep("addE", edgeLabelTraversal); + traversal.Bytecode.AddStep("addE", edgeLabelTraversal); + return traversal; + } + + /// <summary> + /// Spawns a <see cref="GraphTraversal{SType, EType}" /> off this graph traversal source and adds the mergeE step to that + /// traversal. + /// </summary> + public GraphTraversal<Edge, Edge> MergeE(IDictionary<object,object> m) + { + var traversal = new GraphTraversal<Edge, Edge>(TraversalStrategies, new Bytecode(Bytecode)); + traversal.Bytecode.AddStep("mergeE", m); + return traversal; + } + + /// <summary> + /// Spawns a <see cref="GraphTraversal{SType, EType}" /> off this graph traversal source and adds the mergeE step to that + /// traversal. + /// </summary> + public GraphTraversal<Edge, Edge> MergeE(ITraversal t) + { + var traversal = new GraphTraversal<Edge, Edge>(TraversalStrategies, new Bytecode(Bytecode)); + traversal.Bytecode.AddStep("mergeE", t); return traversal; } @@ -358,7 +380,7 @@ namespace Gremlin.Net.Process.Traversal public GraphTraversal<Vertex, Vertex> AddV() { var traversal = new GraphTraversal<Vertex, Vertex>(TraversalStrategies, new Bytecode(Bytecode)); - traversal.Bytecode.AddStep("addV"); + traversal.Bytecode.AddStep("addV"); return traversal; } @@ -369,7 +391,7 @@ namespace Gremlin.Net.Process.Traversal public GraphTraversal<Vertex, Vertex> AddV(string label) { var traversal = new GraphTraversal<Vertex, Vertex>(TraversalStrategies, new Bytecode(Bytecode)); - traversal.Bytecode.AddStep("addV", label); + traversal.Bytecode.AddStep("addV", label); return traversal; } @@ -380,7 +402,29 @@ namespace Gremlin.Net.Process.Traversal public GraphTraversal<Vertex, Vertex> AddV(ITraversal vertexLabelTraversal) { var traversal = new GraphTraversal<Vertex, Vertex>(TraversalStrategies, new Bytecode(Bytecode)); - traversal.Bytecode.AddStep("addV", vertexLabelTraversal); + traversal.Bytecode.AddStep("addV", vertexLabelTraversal); + return traversal; + } + + /// <summary> + /// Spawns a <see cref="GraphTraversal{SType, EType}" /> off this graph traversal source and adds the mergeV step to that + /// traversal. + /// </summary> + public GraphTraversal<Vertex, Vertex> MergeV(IDictionary<object,object> m) + { + var traversal = new GraphTraversal<Vertex, Vertex>(TraversalStrategies, new Bytecode(Bytecode)); + traversal.Bytecode.AddStep("mergeV", m); + return traversal; + } + + /// <summary> + /// Spawns a <see cref="GraphTraversal{SType, EType}" /> off this graph traversal source and adds the mergeV step to that + /// traversal. + /// </summary> + public GraphTraversal<Vertex, Vertex> MergeV(ITraversal t) + { + var traversal = new GraphTraversal<Vertex, Vertex>(TraversalStrategies, new Bytecode(Bytecode)); + traversal.Bytecode.AddStep("mergeV", t); return traversal; } diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Merge.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Merge.cs new file mode 100644 index 0000000..b62fc8f --- /dev/null +++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Merge.cs @@ -0,0 +1,63 @@ +#region License + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#endregion + +using System; +using System.Collections.Generic; + +namespace Gremlin.Net.Process.Traversal +{ +#pragma warning disable 1591 + + public class Merge : EnumWrapper, IFunction + { + private Merge(string enumValue) + : base("Merge", enumValue) + { + } + + public static Merge OnCreate => new Merge("onCreate"); + + public static Merge OnMatch => new Merge("onMatch"); + + private static readonly IDictionary<string, Merge> Properties = new Dictionary<string, Merge> + { + { "onCreate", OnCreate }, + { "onMatch", OnMatch }, + }; + + /// <summary> + /// Gets the Merge enumeration by value. + /// </summary> + public static Merge GetByValue(string value) + { + if (!Properties.TryGetValue(value, out var property)) + { + throw new ArgumentException($"No matching Merge for value '{value}'"); + } + return property; + } + } + + +#pragma warning restore 1591 +} \ No newline at end of file diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/DataType.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/DataType.cs index 3e65ad0..ee33cee 100644 --- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/DataType.cs +++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/DataType.cs @@ -55,6 +55,7 @@ namespace Gremlin.Net.Structure.IO.GraphBinary public static readonly DataType Cardinality = new DataType(0x16); public static readonly DataType Column = new DataType(0x17); public static readonly DataType Direction = new DataType(0x18); + public static readonly DataType Merge = new DataType(0x2E); public static readonly DataType Operator = new DataType(0x19); public static readonly DataType Order = new DataType(0x1A); public static readonly DataType Pick = new DataType(0x1B); diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/TypeSerializerRegistry.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/TypeSerializerRegistry.cs index 87c28e6..d30b5ca 100644 --- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/TypeSerializerRegistry.cs +++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/TypeSerializerRegistry.cs @@ -60,6 +60,7 @@ namespace Gremlin.Net.Structure.IO.GraphBinary {typeof(Cardinality), EnumSerializers.CardinalitySerializer}, {typeof(Column), EnumSerializers.ColumnSerializer}, {typeof(Direction), EnumSerializers.DirectionSerializer}, + {typeof(Merge), EnumSerializers.MergeSerializer}, {typeof(Operator), EnumSerializers.OperatorSerializer}, {typeof(Order), EnumSerializers.OrderSerializer}, {typeof(Pick), EnumSerializers.PickSerializer}, @@ -107,6 +108,7 @@ namespace Gremlin.Net.Structure.IO.GraphBinary {DataType.Cardinality, EnumSerializers.CardinalitySerializer}, {DataType.Column, EnumSerializers.ColumnSerializer}, {DataType.Direction, EnumSerializers.DirectionSerializer}, + {DataType.Merge, EnumSerializers.MergeSerializer}, {DataType.Operator, EnumSerializers.OperatorSerializer}, {DataType.Order, EnumSerializers.OrderSerializer}, {DataType.Pick, EnumSerializers.PickSerializer}, diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/EnumSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/EnumSerializer.cs index d561c2a..5bc6080 100644 --- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/EnumSerializer.cs +++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/EnumSerializer.cs @@ -58,6 +58,12 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types new EnumSerializer<Direction>(DataType.Direction, Direction.GetByValue); /// <summary> + /// A serializer for <see cref="Merge"/> values. + /// </summary> + public static readonly EnumSerializer<Merge> MergeSerializer = + new EnumSerializer<Merge>(DataType.Merge, Merge.GetByValue); + + /// <summary> /// A serializer for <see cref="Operator"/> values. /// </summary> public static readonly EnumSerializer<Operator> OperatorSerializer = diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSONReader.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSONReader.cs index 16901bd..3208966 100644 --- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSONReader.cs +++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSONReader.cs @@ -45,6 +45,7 @@ namespace Gremlin.Net.Structure.IO.GraphSON {"g:Float", new FloatConverter()}, {"g:Double", new DoubleConverter()}, {"g:Direction", new DirectionDeserializer()}, + {"g:Merge", new MergeDeserializer()}, {"g:UUID", new UuidDeserializer()}, {"g:Date", new DateDeserializer()}, {"g:Timestamp", new DateDeserializer()}, diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/MergeDeserializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/MergeDeserializer.cs new file mode 100644 index 0000000..26b6869 --- /dev/null +++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/MergeDeserializer.cs @@ -0,0 +1,36 @@ +#region License + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#endregion + +using System.Text.Json; +using Gremlin.Net.Process.Traversal; + +namespace Gremlin.Net.Structure.IO.GraphSON +{ + internal class MergeDeserializer : IGraphSONDeserializer + { + public dynamic Objectify(JsonElement graphsonObject, GraphSONReader reader) + { + return Merge.GetByValue(graphsonObject.GetString()); + } + } +} \ No newline at end of file diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs index 03b429a..fcac51a 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs @@ -379,7 +379,14 @@ namespace Gremlin.Net.IntegrationTest.Gherkin private static Vertex ToVertex(string name, string graphName) { - return ScenarioData.GetByGraphName(graphName).Vertices[name]; + if (ScenarioData.GetByGraphName(graphName).Vertices.ContainsKey(name)) + { + return ScenarioData.GetByGraphName(graphName).Vertices[name]; + } + else + { + return new Vertex(name); + } } private static Edge ToEdge(string name, string graphName) diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/GherkinTestRunner.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/GherkinTestRunner.cs index 0209c7b..365bedb 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/GherkinTestRunner.cs +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/GherkinTestRunner.cs @@ -87,6 +87,11 @@ namespace Gremlin.Net.IntegrationTest.Gherkin }, {"g_V_properties_order", IgnoreReason.VertexPropertyNotSupportedInGherkin}, {"g_V_properties_order_id", IgnoreReason.VertexPropertyNotSupportedInGherkin}, + {"g_withSideEffectXc_label_person_name_markoX_withSideEffectXm_age_19X_injectX0X_mergeVXselectXcXX_optionXonMatch_selectXmXX_option", IgnoreReason.MergeVEWithTraversalNotSupportedInTranslation}, + {"g_withSideEffectXc_label_person_name_markoX_withSideEffectXm_age_19X_mergeVXselectXcXX_optionXonMatch_selectXmXX_option", IgnoreReason.MergeVEWithTraversalNotSupportedInTranslation}, + {"g_withSideEffectXc_label_person_name_stephenX_withSideEffectXm_label_person_name_stephen_age_19X_injectX0X_mergeVXselectXcXX_optionXonCreate_selectXmXX_option", IgnoreReason.MergeVEWithTraversalNotSupportedInTranslation}, + {"g_injectXlabel_person_name_marko_label_person_name_stephenX_mergeVXidentityX", IgnoreReason.MergeVEWithTraversalNotSupportedInTranslation}, + {"g_withSideEffectXc_label_person_name_stephenX_withSideEffectXm_label_person_name_stephen_age_19X_mergeVXselectXcXX_optionXonCreate_selectXmXX_option", IgnoreReason.MergeVEWithTraversalNotSupportedInTranslation}, }; private static class Keywords diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs index f89e2a5..4ff7bbf 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs @@ -500,30 +500,30 @@ namespace Gremlin.Net.IntegrationTest.Gherkin {"g_withStrategiesXProductiveByStrategyX_V_aggregateXaX_byXfooX_capXaX_unfold_mean", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new ProductiveByStrategy(productiveKeys: new List<object> {})).V().Aggregate("a").By("foo").Cap<object>("a").Unfold<object>().Mean<object>()}}, {"g_injectXnull_10_20_nullX_mean", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(null,p["xx1"],p["xx2"],null).Mean<object>()}}, {"g_injectXlistXnull_10_20_nullXX_meanXlocalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(p["xx1"]).Mean<object>(Scope.Local)}}, - {"g_V_mergeEXlabel_self_weight_05X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29), (g,p) =>g.V().MergeE(p["xx1"]), (g,p) =>g.E().HasLabel("self").Has("weight",0.5)}}, - {"g_mergeEXlabel_knows_out_marko_in_vadasX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,100).Property("name","marko").AddV("person").Property(T.Id,101).Property("name","vadas"), (g,p) =>g.MergeE(p["xx1"]), (g,p) =>g.V().Has("person","name","marko").Out("knows").Has("person","name","vadas")}}, - {"g_mergeEXlabel_knows_out_marko_in_vadas_weight_05X_exists", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,100).Property("name","marko").As("a").AddV("person").Property(T.Id,101).Property("name","vadas").As("b").AddE("knows").From("a").To("b"), (g,p) =>g.MergeE(p["xx1"]), (g,p) =>g.V().Has("person","name","marko").OutE("knows").Has("weight",0.5).InV().Has("person","name","vadas"), (g,p) =>g.V().Has("p [...] - {"g_mergeEXlabel_knows_out_marko_in_vadas_weight_05X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.MergeE(p["xx1"]), (g,p) =>g.V(), (g,p) =>g.E().HasLabel("knows").Has("weight",0.5)}}, - {"g_mergeEXlabel_knows_out_marko_in_vadasX_optionXonCreate_created_YX_optionXonMatch_created_NX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.MergeE(p["xx1"]).Option(Merge.OnCreate,p["xx2"]).Option(Merge.OnMatch,p["xx3"]), (g,p) =>g.V(), (g,p) =>g.E().HasLabel("knows").Has("created","Y"), (g,p) =>g.E().HasLabel("knows").Has("created","N")}}, - {"g_mergeEXlabel_knows_out_marko_in_vadasX_optionXonCreate_created_YX_optionXonMatch_created_NX_exists", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,100).Property("name","marko").As("a").AddV("person").Property(T.Id,101).Property("name","vadas").As("b").AddE("knows").From("a").To("b"), (g,p) =>g.MergeE(p["xx1"]).Option(Merge.OnCreate,p["xx2"]).Option(Merge.OnMatch,p["xx3"]), (g,p) =>g.V(), (g,p) =>g. [...] - {"g_mergeEXlabel_knows_out_marko_in_vadasX_optionXonCreate_created_YX_optionXonMatch_created_NX_exists_updated", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,100).Property("name","marko").As("a").AddV("person").Property(T.Id,101).Property("name","vadas").As("b").AddE("knows").From("a").To("b").Property("created","Y"), (g,p) =>g.MergeE(p["xx1"]).Option(Merge.OnCreate,p["xx2"]).Option(Merge.OnMatch,p["x [...] - {"g_V_hasXperson_name_marko_X_mergeEXlabel_knowsX_optionXonCreate_created_YX_optionXonMatch_created_NX_exists_updated", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,100).Property("name","marko").As("a").AddV("person").Property(T.Id,101).Property("name","vadas").As("b").AddE("knows").From("a").To("b").Property("created","Y").AddE("knows").From("a").To("b"), (g,p) =>g.V().Has("person","name","marko").Me [...] - {"g_VX100X_VX101X_mergeEXlabel_knows_out_marko_in_vadasX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,100).Property("name","marko"), (g,p) =>g.V(100).V(101).MergeE(p["xx1"]), (g,p) =>g.V(), (g,p) =>g.E()}}, - {"g_mergeVXlabel_person_name_stephenX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29).As("marko"), (g,p) =>g.MergeV(p["xx1"]), (g,p) =>g.V().Has("person","name","stephen")}}, - {"g_mergeVXlabel_person_name_markoX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29).As("marko"), (g,p) =>g.MergeV(p["xx1"]), (g,p) =>g.V().Has("person","name","marko")}}, - {"g_mergeVXlabel_person_name_stephenX_optionXonCreate_label_person_name_stephen_age_19X_option", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29).As("marko"), (g,p) =>g.MergeV(p["xx1"]).Option(Merge.OnCreate,p["xx2"]), (g,p) =>g.V().Has("person","name","stephen").Has("age",19)}}, - {"g_mergeVXlabel_person_name_markoX_optionXonMatch_age_19X_option", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29).As("marko"), (g,p) =>g.MergeV(p["xx1"]).Option(Merge.OnMatch,p["xx2"]), (g,p) =>g.V().Has("person","name","marko").Has("age",19)}}, - {"g_withSideEffectXc_label_person_name_stephenX_withSideEffectXm_label_person_name_stephen_age_19X_mergeVXselectXcXX_optionXonCreate_selectXmXX_option", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29).As("marko"), (g,p) =>g.WithSideEffect("c",p["xx1"]).WithSideEffect("m",p["xx2"]).MergeV(__.Select<object>("c")).Option(Merge.OnCreate,__.Select<object>("m")), (g,p) =>g.V().Has [...] - {"g_withSideEffectXc_label_person_name_markoX_withSideEffectXm_age_19X_mergeVXselectXcXX_optionXonMatch_selectXmXX_option", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29).As("marko"), (g,p) =>g.WithSideEffect("c",p["xx1"]).WithSideEffect("m",p["xx2"]).MergeV(__.Select<object>("c")).Option(Merge.OnMatch,__.Select<object>("m")), (g,p) =>g.V().Has("person","name","marko").Has( [...] - {"g_mergeVXlabel_person_name_markoX_propertyXname_vadas_acl_publicX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29).As("marko"), (g,p) =>g.MergeV(p["xx1"]).Property("name","vadas","acl","public"), (g,p) =>g.V().Properties<object>("name").HasValue("vadas").Has("acl","public")}}, - {"g_injectX0X_mergeVXlabel_person_name_stephenX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29).As("marko"), (g,p) =>g.Inject(0).MergeV(p["xx1"]), (g,p) =>g.V().Has("person","name","stephen")}}, - {"g_injectX0X_mergeVXlabel_person_name_markoX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29).As("marko"), (g,p) =>g.Inject(0).MergeV(p["xx1"]), (g,p) =>g.V().Has("person","name","marko")}}, - {"g_injectX0X_mergeVXlabel_person_name_stephenX_optionXonCreate_label_person_name_stephen_age_19X_option", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29).As("marko"), (g,p) =>g.Inject(0).MergeV(p["xx1"]).Option(Merge.OnCreate,p["xx2"]), (g,p) =>g.V().Has("person","name","stephen").Has("age",19)}}, - {"g_injectX0X_mergeVXlabel_person_name_markoX_optionXonMatch_age_19X_option", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29).As("marko"), (g,p) =>g.Inject(0).MergeV(p["xx1"]).Option(Merge.OnMatch,p["xx2"]), (g,p) =>g.V().Has("person","name","marko").Has("age",19)}}, - {"g_withSideEffectXc_label_person_name_stephenX_withSideEffectXm_label_person_name_stephen_age_19X_injectX0X_mergeVXselectXcXX_optionXonCreate_selectXmXX_option", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29).As("marko"), (g,p) =>g.WithSideEffect("c",p["xx1"]).WithSideEffect("m",p["xx2"]).Inject(0).MergeV(__.Select<object>("c")).Option(Merge.OnCreate,__.Select<object>("m") [...] - {"g_withSideEffectXc_label_person_name_markoX_withSideEffectXm_age_19X_injectX0X_mergeVXselectXcXX_optionXonMatch_selectXmXX_option", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29).As("marko"), (g,p) =>g.WithSideEffect("c",p["xx1"]).WithSideEffect("m",p["xx2"]).Inject(0).MergeV(__.Select<object>("c")).Option(Merge.OnMatch,__.Select<object>("m")), (g,p) =>g.V().Has("person", [...] - {"g_injectX0X_mergeVXlabel_person_name_markoX_propertyXname_vadas_acl_publicX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29).As("marko"), (g,p) =>g.Inject(0).MergeV(p["xx1"]).Property("name","vadas","acl","public"), (g,p) =>g.V().Properties<object>("name").HasValue("vadas").Has("acl","public")}}, - {"g_injectXlabel_person_name_marko_label_person_name_stephenX_mergeVXidentityX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29).As("marko"), (g,p) =>g.Inject(p["xx1"],p["xx2"]).MergeV(__.Identity()), (g,p) =>g.V().Has("person","name","stephen"), (g,p) =>g.V().Has("person","name","marko"), (g,p) =>g.V()}}, + {"g_V_mergeEXlabel_self_weight_05X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29), (g,p) =>g.V().MergeE((IDictionary<object,object>) p["xx1"]), (g,p) =>g.E().HasLabel("self").Has("weight",0.5)}}, + {"g_mergeEXlabel_knows_out_marko_in_vadasX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,100).Property("name","marko").AddV("person").Property(T.Id,101).Property("name","vadas"), (g,p) =>g.MergeE((IDictionary<object,object>) p["xx1"]), (g,p) =>g.V().Has("person","name","marko").Out("knows").Has("person","name","vadas")}}, + {"g_mergeEXlabel_knows_out_marko_in_vadas_weight_05X_exists", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,100).Property("name","marko").As("a").AddV("person").Property(T.Id,101).Property("name","vadas").As("b").AddE("knows").From("a").To("b"), (g,p) =>g.MergeE((IDictionary<object,object>) p["xx1"]), (g,p) =>g.V().Has("person","name","marko").OutE("knows").Has("weight",0.5).InV().Has("person","name"," [...] + {"g_mergeEXlabel_knows_out_marko_in_vadas_weight_05X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.MergeE((IDictionary<object,object>) p["xx1"]), (g,p) =>g.V(), (g,p) =>g.E().HasLabel("knows").Has("weight",0.5)}}, + {"g_mergeEXlabel_knows_out_marko_in_vadasX_optionXonCreate_created_YX_optionXonMatch_created_NX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.MergeE((IDictionary<object,object>) p["xx1"]).Option(Merge.OnCreate, (IDictionary<object,object>) p["xx2"]).Option(Merge.OnMatch, (IDictionary<object,object>) p["xx3"]), (g,p) =>g.V(), (g,p) =>g.E().HasLabel("knows").Has("created","Y"), (g,p) =>g.E().HasLabel("knows").Has("created","N")}}, + {"g_mergeEXlabel_knows_out_marko_in_vadasX_optionXonCreate_created_YX_optionXonMatch_created_NX_exists", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,100).Property("name","marko").As("a").AddV("person").Property(T.Id,101).Property("name","vadas").As("b").AddE("knows").From("a").To("b"), (g,p) =>g.MergeE((IDictionary<object,object>) p["xx1"]).Option(Merge.OnCreate, (IDictionary<object,object>) p["xx2"] [...] + {"g_mergeEXlabel_knows_out_marko_in_vadasX_optionXonCreate_created_YX_optionXonMatch_created_NX_exists_updated", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,100).Property("name","marko").As("a").AddV("person").Property(T.Id,101).Property("name","vadas").As("b").AddE("knows").From("a").To("b").Property("created","Y"), (g,p) =>g.MergeE((IDictionary<object,object>) p["xx1"]).Option(Merge.OnCreate, (IDic [...] + {"g_V_hasXperson_name_marko_X_mergeEXlabel_knowsX_optionXonCreate_created_YX_optionXonMatch_created_NX_exists_updated", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,100).Property("name","marko").As("a").AddV("person").Property(T.Id,101).Property("name","vadas").As("b").AddE("knows").From("a").To("b").Property("created","Y").AddE("knows").From("a").To("b"), (g,p) =>g.V().Has("person","name","marko").Me [...] + {"g_VX100X_VX101X_mergeEXlabel_knows_out_marko_in_vadasX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,100).Property("name","marko"), (g,p) =>g.V(100).V(101).MergeE((IDictionary<object,object>) p["xx1"]), (g,p) =>g.V(), (g,p) =>g.E()}}, + {"g_mergeVXlabel_person_name_stephenX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29).As("marko"), (g,p) =>g.MergeV((IDictionary<object,object>) p["xx1"]), (g,p) =>g.V().Has("person","name","stephen")}}, + {"g_mergeVXlabel_person_name_markoX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29).As("marko"), (g,p) =>g.MergeV((IDictionary<object,object>) p["xx1"]), (g,p) =>g.V().Has("person","name","marko")}}, + {"g_mergeVXlabel_person_name_stephenX_optionXonCreate_label_person_name_stephen_age_19X_option", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29).As("marko"), (g,p) =>g.MergeV((IDictionary<object,object>) p["xx1"]).Option(Merge.OnCreate, (IDictionary<object,object>) p["xx2"]), (g,p) =>g.V().Has("person","name","stephen").Has("age",19)}}, + {"g_mergeVXlabel_person_name_markoX_optionXonMatch_age_19X_option", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29).As("marko"), (g,p) =>g.MergeV((IDictionary<object,object>) p["xx1"]).Option(Merge.OnMatch, (IDictionary<object,object>) p["xx2"]), (g,p) =>g.V().Has("person","name","marko").Has("age",19)}}, + {"g_withSideEffectXc_label_person_name_stephenX_withSideEffectXm_label_person_name_stephen_age_19X_mergeVXselectXcXX_optionXonCreate_selectXmXX_option", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29).As("marko"), (g,p) =>g.WithSideEffect("c",p["xx1"]).WithSideEffect("m",p["xx2"]).MergeV((IDictionary<object,object>) __.Select<object>("c")).Option(Merge.OnCreate, (IDictionary [...] + {"g_withSideEffectXc_label_person_name_markoX_withSideEffectXm_age_19X_mergeVXselectXcXX_optionXonMatch_selectXmXX_option", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29).As("marko"), (g,p) =>g.WithSideEffect("c",p["xx1"]).WithSideEffect("m",p["xx2"]).MergeV((IDictionary<object,object>) __.Select<object>("c")).Option(Merge.OnMatch, (IDictionary<object,object>) __.Select<obj [...] + {"g_mergeVXlabel_person_name_markoX_propertyXname_vadas_acl_publicX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29).As("marko"), (g,p) =>g.MergeV((IDictionary<object,object>) p["xx1"]).Property("name","vadas","acl","public"), (g,p) =>g.V().Properties<object>("name").HasValue("vadas").Has("acl","public")}}, + {"g_injectX0X_mergeVXlabel_person_name_stephenX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29).As("marko"), (g,p) =>g.Inject(0).MergeV((IDictionary<object,object>) p["xx1"]), (g,p) =>g.V().Has("person","name","stephen")}}, + {"g_injectX0X_mergeVXlabel_person_name_markoX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29).As("marko"), (g,p) =>g.Inject(0).MergeV((IDictionary<object,object>) p["xx1"]), (g,p) =>g.V().Has("person","name","marko")}}, + {"g_injectX0X_mergeVXlabel_person_name_stephenX_optionXonCreate_label_person_name_stephen_age_19X_option", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29).As("marko"), (g,p) =>g.Inject(0).MergeV((IDictionary<object,object>) p["xx1"]).Option(Merge.OnCreate, (IDictionary<object,object>) p["xx2"]), (g,p) =>g.V().Has("person","name","stephen").Has("age",19)}}, + {"g_injectX0X_mergeVXlabel_person_name_markoX_optionXonMatch_age_19X_option", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29).As("marko"), (g,p) =>g.Inject(0).MergeV((IDictionary<object,object>) p["xx1"]).Option(Merge.OnMatch, (IDictionary<object,object>) p["xx2"]), (g,p) =>g.V().Has("person","name","marko").Has("age",19)}}, + {"g_withSideEffectXc_label_person_name_stephenX_withSideEffectXm_label_person_name_stephen_age_19X_injectX0X_mergeVXselectXcXX_optionXonCreate_selectXmXX_option", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29).As("marko"), (g,p) =>g.WithSideEffect("c",p["xx1"]).WithSideEffect("m",p["xx2"]).Inject(0).MergeV((IDictionary<object,object>) __.Select<object>("c")).Option(Merge.On [...] + {"g_withSideEffectXc_label_person_name_markoX_withSideEffectXm_age_19X_injectX0X_mergeVXselectXcXX_optionXonMatch_selectXmXX_option", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29).As("marko"), (g,p) =>g.WithSideEffect("c",p["xx1"]).WithSideEffect("m",p["xx2"]).Inject(0).MergeV((IDictionary<object,object>) __.Select<object>("c")).Option(Merge.OnMatch, (IDictionary<object,ob [...] + {"g_injectX0X_mergeVXlabel_person_name_markoX_propertyXname_vadas_acl_publicX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29).As("marko"), (g,p) =>g.Inject(0).MergeV((IDictionary<object,object>) p["xx1"]).Property("name","vadas","acl","public"), (g,p) =>g.V().Properties<object>("name").HasValue("vadas").Has("acl","public")}}, + {"g_injectXlabel_person_name_marko_label_person_name_stephenX_mergeVXidentityX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29).As("marko"), (g,p) =>g.Inject(p["xx1"],p["xx2"]).MergeV((IDictionary<object,object>) __.Identity()), (g,p) =>g.V().Has("person","name","stephen"), (g,p) =>g.V().Has("person","name","marko"), (g,p) =>g.V()}}, {"g_V_age_min", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Min<object>()}}, {"g_V_foo_min", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("foo").Min<object>()}}, {"g_V_name_min", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name").Min<object>()}}, @@ -831,7 +831,6 @@ namespace Gremlin.Net.IntegrationTest.Gherkin {"g_V_outXfollowedByX_group_byXsongTypeX_byXbothE_group_byXlabelX_byXweight_sumXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Out("followedBy").Group<object,object>().By("songType").By(__.BothE().Group<object,object>().By(T.Label).By(__.Values<object>("weight").Sum<object>()))}}, {"g_V_groupXmX_byXnameX_byXinXknowsX_nameX_capXmX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Group("m").By("name").By(__.In("knows").Values<object>("name")).Cap<object>("m")}}, {"g_V_group_byXlabelX_byXbothE_groupXaX_byXlabelX_byXweight_sumX_weight_sumX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Group<object,object>().By(T.Label).By(__.BothE().Group("a").By(T.Label).By(__.Values<object>("weight").Sum<object>()).Values<object>("weight").Sum<object>())}}, - {"g_withSideEffectXa__marko_666_noone_blahX_V_groupXaX_byXnameX_byXoutE_label_foldX_capXaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithSideEffect("a",p["xx1"]).V().Group("a").By("name").By(__.OutE().Label().Fold()).Cap<object>("a").Unfold<object>().Group<object,object>().By(Column.Keys).By(__.Select<object>(Column.Values).Order(Scope.Local).By(Order.Asc))}}, {"g_V_hasLabelXpersonX_asXpX_outXcreatedX_group_byXnameX_byXselectXpX_valuesXageX_sumX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").As("p").Out("created").Group<object,object>().By("name").By(__.Select<object>("p").Values<object>("age").Sum<object>())}}, {"g_V_hasLabelXpersonX_asXpX_outXcreatedX_groupXaX_byXnameX_byXselectXpX_valuesXageX_sumX_capXaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").As("p").Out("created").Group("a").By("name").By(__.Select<object>("p").Values<object>("age").Sum<object>()).Cap<object>("a")}}, {"g_V_group_byXlabelX_byXlabel_countX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Group<object,object>().By(__.Label()).By(__.Label().Count())}}, @@ -854,7 +853,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin {"g_V_hasXperson_name_markoX_bothXknowsX_groupCount_byXvaluesXnameX_foldX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("person","name","marko").Both("knows").GroupCount<object>().By(__.Values<object>("name").Fold())}}, {"g_VX1X_out_injectXv2X_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out().Inject((Vertex) p["v2"]).Values<object>("name")}}, {"g_VX1X_out_name_injectXdanielX_asXaX_mapXlengthX_path", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out().Values<object>("name").Inject("daniel").As("a").Map<object>((IFunction) p["l1"]).Path()}}, - {"g_VX1X_injectXg_VX4XX_out_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Inject((Vertex) p["v4"]).Out().Values<object>("name")}}, + {"g_VX1X_injectXg_VX4XX_out_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Inject((Vertex) p["v2"]).Out().Values<object>("name")}}, {"g_injectXnull_1_3_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(null,1,3,null)}}, {"g_injectX10_20_null_20_10_10X_groupCountXxX_dedup_asXyX_projectXa_bX_by_byXselectXxX_selectXselectXyXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(10,20,null,20,10,10).GroupCount("x").Dedup().As("y").Project<object>("a","b").By().By(__.Select<object>("x").Select<object>(__.Select<object>("y")))}}, {"g_injectXname_marko_age_nullX_selectXname_ageX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(p["xx1"]).Select<object>("name","age")}}, diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/IgnoreException.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/IgnoreException.cs index 2fa881b..8f1bbac 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/IgnoreException.cs +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/IgnoreException.cs @@ -70,6 +70,13 @@ namespace Gremlin.Net.IntegrationTest.Gherkin /// <summary> /// Need a Gherkin parser for VertexProperty results: https://issues.apache.org/jira/browse/TINKERPOP-2686 /// </summary> - VertexPropertyNotSupportedInGherkin + VertexPropertyNotSupportedInGherkin, + + /// <summary> + /// VarAsBindingASTTransformation isn't capable of properly casting arguments so the DotNetTranslator can't + /// produce the right Gremlin. These tests could be static translated but there are a lot of them so it would + /// be better to solve this more directly. + /// </summary> + MergeVEWithTraversalNotSupportedInTranslation } } \ No newline at end of file diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphBinary/GraphBinaryTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphBinary/GraphBinaryTests.cs index 7978005..eecb385 100644 --- a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphBinary/GraphBinaryTests.cs +++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphBinary/GraphBinaryTests.cs @@ -535,6 +535,21 @@ namespace Gremlin.Net.UnitTest.Structure.IO.GraphBinary Assert.Equal(expected, actual); } + + [Fact] + public async Task TestMerge() + { + var expected = Merge.OnCreate; + var writer = CreateGraphBinaryWriter(); + var reader = CreateGraphBinaryReader(); + var serializationStream = new MemoryStream(); + + await writer.WriteAsync(expected, serializationStream); + serializationStream.Position = 0; + var actual = await reader.ReadAsync(serializationStream); + + Assert.Equal(expected, actual); + } [Fact] public async Task TestOperator() diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONReaderTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONReaderTests.cs index 5bc232b..2c33a1e 100644 --- a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONReaderTests.cs +++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONReaderTests.cs @@ -312,6 +312,18 @@ namespace Gremlin.Net.UnitTest.Structure.IO.GraphSON Assert.Equal(Direction.Out, deserializedValue); } + + [Theory, MemberData(nameof(Versions))] + public void ShouldDeserializeMerge(int version) + { + const string serializedValue = "{\"@type\":\"g:Merge\",\"@value\":\"onMatch\"}"; + var reader = CreateStandardGraphSONReader(version); + + var jsonElement = JsonSerializer.Deserialize<JsonElement>(serializedValue); + var deserializedValue = reader.ToObject(jsonElement); + + Assert.Equal(Merge.OnMatch, deserializedValue); + } [Fact] public void ShouldDeserializePathFromGraphSON2() diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONWriterTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONWriterTests.cs index ce593f7..9247831 100644 --- a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONWriterTests.cs +++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONWriterTests.cs @@ -258,7 +258,7 @@ namespace Gremlin.Net.UnitTest.Structure.IO.GraphSON } [Theory, MemberData(nameof(Versions))] - public void ShouldSerializeEnum(int version) + public void ShouldSerializeDirection(int version) { var writer = CreateGraphSONWriter(version); @@ -269,6 +269,17 @@ namespace Gremlin.Net.UnitTest.Structure.IO.GraphSON } [Theory, MemberData(nameof(Versions))] + public void ShouldSerializeMerge(int version) + { + var writer = CreateGraphSONWriter(version); + + var serializedEnum = writer.WriteObject(Merge.OnMatch); + + var expectedGraphSON = "{\"@type\":\"g:Merge\",\"@value\":\"onMatch\"}"; + Assert.Equal(expectedGraphSON, serializedEnum); + } + + [Theory, MemberData(nameof(Versions))] public void ShouldSerializeList(int version) { var writer = CreateGraphSONWriter(version); diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/message/RequestMessage.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/message/RequestMessage.java index dc10baf..aeebf35 100644 --- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/message/RequestMessage.java +++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/message/RequestMessage.java @@ -18,6 +18,7 @@ */ package org.apache.tinkerpop.gremlin.driver.message; +import org.apache.tinkerpop.gremlin.driver.Tokens; import org.apache.tinkerpop.gremlin.structure.util.ElementHelper; import java.util.HashMap; @@ -34,7 +35,7 @@ public final class RequestMessage { /** * An "invalid" message. Used internally only. */ - public static final RequestMessage INVALID = new RequestMessage("invalid"); + public static final RequestMessage INVALID = new RequestMessage(Tokens.OPS_INVALID); private final UUID requestId; private final String op; diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/graph-traversal.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/graph-traversal.js index c609ba0..ae3d7f3 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/graph-traversal.js +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/graph-traversal.js @@ -212,6 +212,16 @@ class GraphTraversalSource { const b = new Bytecode(this.bytecode).addStep('addE', args); return new this.graphTraversalClass(this.graph, new TraversalStrategies(this.traversalStrategies), b); } + + /** + * mergeV GraphTraversalSource step method. + * @param {...Object} args + * @returns {GraphTraversal} + */ + mergeE(...args) { + const b = new Bytecode(this.bytecode).addStep('mergeE', args); + return new this.graphTraversalClass(this.graph, new TraversalStrategies(this.traversalStrategies), b); + } /** * addV GraphTraversalSource step method. @@ -222,6 +232,16 @@ class GraphTraversalSource { const b = new Bytecode(this.bytecode).addStep('addV', args); return new this.graphTraversalClass(this.graph, new TraversalStrategies(this.traversalStrategies), b); } + + /** + * mergeV GraphTraversalSource step method. + * @param {...Object} args + * @returns {GraphTraversal} + */ + mergeV(...args) { + const b = new Bytecode(this.bytecode).addStep('mergeV', args); + return new this.graphTraversalClass(this.graph, new TraversalStrategies(this.traversalStrategies), b); + } /** * inject GraphTraversalSource step method. diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/feature-steps.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/feature-steps.js index d500feb..ba23650 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/feature-steps.js +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/feature-steps.js @@ -273,7 +273,13 @@ function toNumeric(stringValue) { } function toVertex(name) { - return this.getData().vertices.get(name); + // some vertices are cached, like those from toy graphs but some are just references. if they are + // not cached then they are meant to be references. + const vertices = this.getData().vertices; + if (vertices.has(name)) + return this.getData().vertices.get(name); + else + return new graphModule.Vertex(name, "vertex") } function toVertexId(name) { diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js index 6079579..6af6338 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js @@ -820,7 +820,6 @@ const gremlins = { g_V_outXfollowedByX_group_byXsongTypeX_byXbothE_group_byXlabelX_byXweight_sumXX: [function({g}) { return g.V().out("followedBy").group().by("songType").by(__.bothE().group().by(T.label).by(__.values("weight").sum())) }], g_V_groupXmX_byXnameX_byXinXknowsX_nameX_capXmX: [function({g}) { return g.V().group("m").by("name").by(__.in_("knows").values("name")).cap("m") }], g_V_group_byXlabelX_byXbothE_groupXaX_byXlabelX_byXweight_sumX_weight_sumX: [function({g}) { return g.V().group().by(T.label).by(__.bothE().group("a").by(T.label).by(__.values("weight").sum()).values("weight").sum()) }], - g_withSideEffectXa__marko_666_noone_blahX_V_groupXaX_byXnameX_byXoutE_label_foldX_capXaX: [function({g, xx1}) { return g.withSideEffect("a",xx1).V().group("a").by("name").by(__.outE().label().fold()).cap("a").unfold().group().by(Column.keys).by(__.select(Column.values).order(Scope.local).by(Order.asc)) }], g_V_hasLabelXpersonX_asXpX_outXcreatedX_group_byXnameX_byXselectXpX_valuesXageX_sumX: [function({g}) { return g.V().hasLabel("person").as("p").out("created").group().by("name").by(__.select("p").values("age").sum()) }], g_V_hasLabelXpersonX_asXpX_outXcreatedX_groupXaX_byXnameX_byXselectXpX_valuesXageX_sumX_capXaX: [function({g}) { return g.V().hasLabel("person").as("p").out("created").group("a").by("name").by(__.select("p").values("age").sum()).cap("a") }], g_V_group_byXlabelX_byXlabel_countX: [function({g}) { return g.V().group().by(__.label()).by(__.label().count()) }], @@ -843,7 +842,7 @@ const gremlins = { g_V_hasXperson_name_markoX_bothXknowsX_groupCount_byXvaluesXnameX_foldX: [function({g}) { return g.V().has("person","name","marko").both("knows").groupCount().by(__.values("name").fold()) }], g_VX1X_out_injectXv2X_name: [function({g, vid1, v2}) { return g.V(vid1).out().inject(v2).values("name") }], g_VX1X_out_name_injectXdanielX_asXaX_mapXlengthX_path: [function({g, l1, vid1}) { return g.V(vid1).out().values("name").inject("daniel").as("a").map(l1).path() }], - g_VX1X_injectXg_VX4XX_out_name: [function({g, vid1, v4}) { return g.V(vid1).inject(v4).out().values("name") }], + g_VX1X_injectXg_VX4XX_out_name: [function({g, vid1, v2}) { return g.V(vid1).inject(v2).out().values("name") }], g_injectXnull_1_3_nullX: [function({g}) { return g.inject(null,1,3,null) }], g_injectX10_20_null_20_10_10X_groupCountXxX_dedup_asXyX_projectXa_bX_by_byXselectXxX_selectXselectXyXXX: [function({g}) { return g.inject(10,20,null,20,10,10).groupCount("x").dedup().as("y").project("a","b").by().by(__.select("x").select(__.select("y"))) }], g_injectXname_marko_age_nullX_selectXname_ageX: [function({g, xx1}) { return g.inject(xx1).select("name","age") }], diff --git a/gremlin-language/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/ReferenceGrammarTest.java b/gremlin-language/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/ReferenceGrammarTest.java index a0e91fe..b241c59 100644 --- a/gremlin-language/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/ReferenceGrammarTest.java +++ b/gremlin-language/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/ReferenceGrammarTest.java @@ -70,7 +70,7 @@ public class ReferenceGrammarTest extends AbstractGrammarTest { return String.format("[%s]", listItems); })); add(Pair.with(Pattern.compile("v\\[(.+)\\]"), (k,v) -> "\"1\"")); - add(Pair.with(Pattern.compile("v(\\d)"), (k,v) -> String.format("new Vertex(%s)", v))); + add(Pair.with(Pattern.compile("v(\\d)"), (k,v) -> String.format("new Vertex(%s, \"vertex\")", v))); add(Pair.with(Pattern.compile("e\\[(.+)\\]"), (k,v) -> "\"1\"")); add(Pair.with(Pattern.compile("d\\[(.*)\\]\\.?.*"), (k,v) -> v)); add(Pair.with(Pattern.compile("m\\[(.*)\\]"), (k,v) -> v.replace('{','[').replace('}', ']'))); diff --git a/gremlin-python/build/generate.groovy b/gremlin-python/build/generate.groovy index a633cd7..0c6dd42 100644 --- a/gremlin-python/build/generate.groovy +++ b/gremlin-python/build/generate.groovy @@ -87,7 +87,7 @@ radishGremlinFile.withWriter('UTF-8') { Writer writer -> 'from gremlin_python.process.traversal import TraversalStrategy\n' + 'from gremlin_python.process.graph_traversal import __\n' + 'from gremlin_python.structure.graph import Graph\n' + - 'from gremlin_python.process.traversal import Barrier, Cardinality, P, TextP, Pop, Scope, Column, Order, Direction, T, Pick, Operator, IO, WithOptions\n') + 'from gremlin_python.process.traversal import Barrier, Cardinality, P, TextP, Pop, Scope, Column, Order, Direction, Merge, T, Pick, Operator, IO, WithOptions\n') // Groovy can't process certain null oriented calls because it gets confused with the right overload to call // at runtime. using this approach for now as these are the only such situations encountered so far. a better diff --git a/gremlin-python/src/main/python/gremlin_python/process/graph_traversal.py b/gremlin-python/src/main/python/gremlin_python/process/graph_traversal.py index 525bc9d..c8e8ae4 100644 --- a/gremlin-python/src/main/python/gremlin_python/process/graph_traversal.py +++ b/gremlin-python/src/main/python/gremlin_python/process/graph_traversal.py @@ -144,6 +144,16 @@ class GraphTraversalSource(object): traversal.bytecode.add_step("addV", *args) return traversal + def mergeV(self, *args): + traversal = self.get_graph_traversal() + traversal.bytecode.add_step("mergeV", *args) + return traversal + + def mergeE(self, *args): + traversal = self.get_graph_traversal() + traversal.bytecode.add_step("mergeE", *args) + return traversal + def inject(self, *args): traversal = self.get_graph_traversal() traversal.bytecode.add_step("inject", *args) @@ -401,6 +411,14 @@ class GraphTraversal(Traversal): self.bytecode.add_step("mean", *args) return self + def mergeE(self, *args): + self.bytecode.add_step("mergeE", *args) + return self + + def mergeV(self, *args): + self.bytecode.add_step("mergeV", *args) + return self + def min_(self, *args): self.bytecode.add_step("min", *args) return self @@ -827,6 +845,14 @@ class __(object, metaclass=MagicType): return cls.graph_traversal(None, None, Bytecode()).mean(*args) @classmethod + def mergeE(cls, *args): + return cls.graph_traversal(None, None, Bytecode()).mergeE(*args) + + @classmethod + def mergeV(cls, *args): + return cls.graph_traversal(None, None, Bytecode()).mergeV(*args) + + @classmethod def min_(cls, *args): return cls.graph_traversal(None, None, Bytecode()).min_(*args) @@ -1254,6 +1280,14 @@ def mean(*args): return __.mean(*args) +def mergeE(*args): + return __.mergeE(*args) + + +def mergeV(*args): + return __.mergeV(*args) + + def min_(*args): return __.min_(*args) @@ -1514,6 +1548,10 @@ statics.add_static('max_', max_) statics.add_static('mean', mean) +statics.add_static('mergeE', mergeE) + +statics.add_static('mergeV', mergeV) + statics.add_static('min_', min_) statics.add_static('not_', not_) diff --git a/gremlin-python/src/main/python/gremlin_python/process/traversal.py b/gremlin-python/src/main/python/gremlin_python/process/traversal.py index f7bd31d..e24948c 100644 --- a/gremlin-python/src/main/python/gremlin_python/process/traversal.py +++ b/gremlin-python/src/main/python/gremlin_python/process/traversal.py @@ -152,6 +152,11 @@ GryoVersion = Enum('GryoVersion', ' V1_0 V3_0') statics.add_static('V1_0', GryoVersion.V1_0) statics.add_static('V3_0', GryoVersion.V3_0) +Merge = Enum('Merge', ' onCreate onMatch') + +statics.add_static('onCreate', Merge.onCreate) +statics.add_static('onMatch', Merge.onMatch) + Order = Enum('Order', ' asc desc shuffle') statics.add_static('shuffle', Order.shuffle) diff --git a/gremlin-python/src/main/python/gremlin_python/structure/io/graphbinaryV1.py b/gremlin-python/src/main/python/gremlin_python/structure/io/graphbinaryV1.py index a5a258a..f39197a 100644 --- a/gremlin-python/src/main/python/gremlin_python/structure/io/graphbinaryV1.py +++ b/gremlin-python/src/main/python/gremlin_python/structure/io/graphbinaryV1.py @@ -33,8 +33,8 @@ from datetime import timedelta from gremlin_python import statics from gremlin_python.statics import FloatType, FunctionType, IntType, LongType, TypeType, DictType, ListType, SetType, \ SingleByte, ByteBufferType, GremlinType, SingleChar -from gremlin_python.process.traversal import Barrier, Binding, Bytecode, Cardinality, Column, Direction, Operator, \ - Order, Pick, Pop, P, Scope, TextP, Traversal, Traverser, \ +from gremlin_python.process.traversal import Barrier, Binding, Bytecode, Cardinality, Column, Direction, Merge, \ + Operator, Order, Pick, Pop, P, Scope, TextP, Traversal, Traverser, \ TraversalStrategy, T from gremlin_python.process.graph_traversal import GraphTraversal from gremlin_python.structure.graph import Graph, Edge, Property, Vertex, VertexProperty, Path @@ -96,6 +96,7 @@ class DataType(Enum): tree = 0x2b # not supported - no tree object in Python yet metrics = 0x2c traversalmetrics = 0x2d + merge = 0x2e char = 0x80 duration = 0x81 inetaddress = 0x82 # todo @@ -850,6 +851,11 @@ class PSerializer(_GraphBinaryTypeIO): return to_extend +class MergeIO(_EnumIO): + graphbinary_type = DataType.merge + python_type = Merge + + class ScopeIO(_EnumIO): graphbinary_type = DataType.scope python_type = Scope diff --git a/gremlin-python/src/main/python/radish/feature_steps.py b/gremlin-python/src/main/python/radish/feature_steps.py index 66bfc45..6d0a72d 100644 --- a/gremlin-python/src/main/python/radish/feature_steps.py +++ b/gremlin-python/src/main/python/radish/feature_steps.py @@ -20,7 +20,7 @@ import json import re from gremlin_python.statics import long -from gremlin_python.structure.graph import Path +from gremlin_python.structure.graph import Path, Vertex from gremlin_python.process.anonymous_traversal import traversal from gremlin_python.process.graph_traversal import __ from gremlin_python.process.traversal import Barrier, Cardinality, P, TextP, Pop, Scope, Column, Order, Direction, T, Pick, Operator, IO, WithOptions @@ -221,7 +221,11 @@ def __find_cached_element(ctx, graph_name, identifier, element_type): else: cache = ctx.lookup_v[graph_name] if element_type == "v" else ctx.lookup_e[graph_name] - return cache[identifier] + # try to lookup the element - if it can't be found then it must be a reference Vertex + if identifier in cache: + return cache[identifier] + else: + return Vertex(identifier) def _convert_results(val): diff --git a/gremlin-python/src/main/python/radish/gremlin.py b/gremlin-python/src/main/python/radish/gremlin.py index 7f4a084..8f9368d 100644 --- a/gremlin-python/src/main/python/radish/gremlin.py +++ b/gremlin-python/src/main/python/radish/gremlin.py @@ -29,7 +29,7 @@ from gremlin_python.process.anonymous_traversal import traversal from gremlin_python.process.traversal import TraversalStrategy from gremlin_python.process.graph_traversal import __ from gremlin_python.structure.graph import Graph -from gremlin_python.process.traversal import Barrier, Cardinality, P, TextP, Pop, Scope, Column, Order, Direction, T, Pick, Operator, IO, WithOptions +from gremlin_python.process.traversal import Barrier, Cardinality, P, TextP, Pop, Scope, Column, Order, Direction, Merge, T, Pick, Operator, IO, WithOptions world.gremlins = { 'g_V_branchXlabel_eq_person__a_bX_optionXa__ageX_optionXb__langX_optionXb__nameX': [(lambda g, l1=None:g.V().branch(l1).option('a',__.age).option('b',__.lang).option('b',__.name))], @@ -804,7 +804,6 @@ world.gremlins = { 'g_V_outXfollowedByX_group_byXsongTypeX_byXbothE_group_byXlabelX_byXweight_sumXX': [(lambda g:g.V().out('followedBy').group().by('songType').by(__.bothE().group().by(T.label).by(__.weight.sum_())))], 'g_V_groupXmX_byXnameX_byXinXknowsX_nameX_capXmX': [(lambda g:g.V().group('m').by('name').by(__.in_('knows').name).cap('m'))], 'g_V_group_byXlabelX_byXbothE_groupXaX_byXlabelX_byXweight_sumX_weight_sumX': [(lambda g:g.V().group().by(T.label).by(__.bothE().group('a').by(T.label).by(__.weight.sum_()).weight.sum_()))], - 'g_withSideEffectXa__marko_666_noone_blahX_V_groupXaX_byXnameX_byXoutE_label_foldX_capXaX': [(lambda g, xx1=None:g.withSideEffect('a',xx1).V().group('a').by('name').by(__.outE().label().fold()).cap('a').unfold().group().by(Column.keys).by(__.select(Column.values).order(Scope.local).by(Order.asc)))], 'g_V_hasLabelXpersonX_asXpX_outXcreatedX_group_byXnameX_byXselectXpX_valuesXageX_sumX': [(lambda g:g.V().hasLabel('person').as_('p').out('created').group().by('name').by(__.select('p').age.sum_()))], 'g_V_hasLabelXpersonX_asXpX_outXcreatedX_groupXaX_byXnameX_byXselectXpX_valuesXageX_sumX_capXaX': [(lambda g:g.V().hasLabel('person').as_('p').out('created').group('a').by('name').by(__.select('p').age.sum_()).cap('a'))], 'g_V_group_byXlabelX_byXlabel_countX': [(lambda g:g.V().group().by(__.label()).by(__.label().count()))], @@ -827,7 +826,7 @@ world.gremlins = { 'g_V_hasXperson_name_markoX_bothXknowsX_groupCount_byXvaluesXnameX_foldX': [(lambda g:g.V().has('person','name','marko').both('knows').groupCount().by(__.name.fold()))], 'g_VX1X_out_injectXv2X_name': [(lambda g, vid1=None,v2=None:g.V(vid1).out().inject(v2).name)], 'g_VX1X_out_name_injectXdanielX_asXaX_mapXlengthX_path': [(lambda g, l1=None,vid1=None:g.V(vid1).out().name.inject('daniel').as_('a').map(l1).path())], - 'g_VX1X_injectXg_VX4XX_out_name': [(lambda g, vid1=None,v4=None:g.V(vid1).inject(v4).out().name)], + 'g_VX1X_injectXg_VX4XX_out_name': [(lambda g, vid1=None,v2=None:g.V(vid1).inject(v2).out().name)], 'g_injectXnull_1_3_nullX': [(lambda g:g.inject(None,1,3,None))], 'g_injectX10_20_null_20_10_10X_groupCountXxX_dedup_asXyX_projectXa_bX_by_byXselectXxX_selectXselectXyXXX': [(lambda g:g.inject(10,20,None,20,10,10).groupCount('x').dedup().as_('y').project('a','b').by().by(__.select('x').select(__.select('y'))))], 'g_injectXname_marko_age_nullX_selectXname_ageX': [(lambda g, xx1=None:g.inject(xx1).select('name','age'))], diff --git a/gremlin-python/src/main/python/tests/driver/test_driver_remote_connection.py b/gremlin-python/src/main/python/tests/driver/test_driver_remote_connection.py index c931bc9..14b9577 100644 --- a/gremlin-python/src/main/python/tests/driver/test_driver_remote_connection.py +++ b/gremlin-python/src/main/python/tests/driver/test_driver_remote_connection.py @@ -44,6 +44,7 @@ class TestDriverRemoteConnection(object): assert long(6) == g.V().count().toList()[0] # # assert Vertex(1) == g.V(1).next() + assert Vertex(1) == g.V(Vertex(1)).next() assert 1 == g.V(1).id_().next() assert Traverser(Vertex(1)) == g.V(1).nextTraverser() assert 1 == len(g.V(1).toList()) diff --git a/gremlin-python/src/main/python/tests/structure/io/test_graphbinaryV1.py b/gremlin-python/src/main/python/tests/structure/io/test_graphbinaryV1.py index 2f2b211..b12c48a 100644 --- a/gremlin-python/src/main/python/tests/structure/io/test_graphbinaryV1.py +++ b/gremlin-python/src/main/python/tests/structure/io/test_graphbinaryV1.py @@ -24,7 +24,7 @@ import math from gremlin_python.statics import timestamp, long, SingleByte, SingleChar, ByteBufferType from gremlin_python.structure.graph import Vertex, Edge, Property, VertexProperty, Path from gremlin_python.structure.io.graphbinaryV1 import GraphBinaryWriter, GraphBinaryReader -from gremlin_python.process.traversal import Barrier, Binding, Bytecode +from gremlin_python.process.traversal import Barrier, Binding, Bytecode, Merge class TestGraphBinaryReader(object): @@ -166,6 +166,11 @@ class TestGraphSONWriter(object): output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x)) assert x == output + def test_merge(self): + x = Merge.onMatch + output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x)) + assert x == output + def test_binding(self): x = Binding("name", "marko") output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x)) diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/WsGremlinBinaryRequestDecoder.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/WsGremlinBinaryRequestDecoder.java index b05ae92..3af49f4 100644 --- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/WsGremlinBinaryRequestDecoder.java +++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/WsGremlinBinaryRequestDecoder.java @@ -76,6 +76,7 @@ public class WsGremlinBinaryRequestDecoder extends MessageToMessageDecoder<Binar try { objects.add(serializer.deserializeRequest(messageBytes.discardReadBytes())); } catch (SerializationException se) { + logger.warn(se.getMessage()); objects.add(RequestMessage.INVALID); } } finally { diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/WsGremlinTextRequestDecoder.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/WsGremlinTextRequestDecoder.java index 50dc6f3..84b0888 100644 --- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/WsGremlinTextRequestDecoder.java +++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/WsGremlinTextRequestDecoder.java @@ -63,6 +63,7 @@ public class WsGremlinTextRequestDecoder extends MessageToMessageDecoder<TextWeb objects.add(serializer.deserializeRequest(frame.text())); } catch (SerializationException se) { + logger.warn(se.getMessage()); objects.add(RequestMessage.INVALID); } } diff --git a/gremlin-test/features/sideEffect/Group.feature b/gremlin-test/features/sideEffect/Group.feature index b8e7b5c..01a5a21 100644 --- a/gremlin-test/features/sideEffect/Group.feature +++ b/gremlin-test/features/sideEffect/Group.feature @@ -264,17 +264,17 @@ Feature: Step - group() | m[{"software":"d[2.0].d", "person":"d[5.0].d"}] | # The post-ordering really isn't really right but works around TINKERPOP-2600 - Scenario: g_withSideEffectXa__marko_666_noone_blahX_V_groupXaX_byXnameX_byXoutE_label_foldX_capXaX - Given the modern graph - And using the parameter xx1 defined as "m[{\"marko\":l[\"666\"], \"noone\":l[\"blah\"]}]" - And the traversal of - """ - g.withSideEffect("a", xx1).V().group("a").by("name").by(__.outE().label().fold()).cap("a").unfold().group().by(keys).by(select(values).order(Scope.local).by(Order.asc)) - """ - When iterated to list - Then the result should be unordered - | result | - | m[{"ripple":[], "peter":["created"], "noone":["blah"], "vadas":[], "josh":["created", "created"], "lop":[], "marko":["666", "created", "knows", "knows"]}] | +# Scenario: g_withSideEffectXa__marko_666_noone_blahX_V_groupXaX_byXnameX_byXoutE_label_foldX_capXaX +# Given the modern graph +# And using the parameter xx1 defined as "m[{\"marko\":\"l[\"666\"]\", \"noone\":\"l[\"blah\"]\"}]" +# And the traversal of +# """ +# g.withSideEffect("a", xx1).V().group("a").by("name").by(__.outE().label().fold()).cap("a").unfold().group().by(Column.keys).by(select(Column.values).order(Scope.local).by(Order.asc)) +# """ +# When iterated to list +# Then the result should be unordered +# | result | +# | m[{"ripple":[], "peter":["created"], "noone":["blah"], "vadas":[], "josh":["created", "created"], "lop":[], "marko":["666", "created", "knows", "knows"]}] | @GraphComputerVerificationStarGraphExceeded Scenario: g_V_hasLabelXpersonX_asXpX_outXcreatedX_group_byXnameX_byXselectXpX_valuesXageX_sumX diff --git a/gremlin-test/features/sideEffect/Inject.feature b/gremlin-test/features/sideEffect/Inject.feature index a186095..75edc15 100644 --- a/gremlin-test/features/sideEffect/Inject.feature +++ b/gremlin-test/features/sideEffect/Inject.feature @@ -51,13 +51,14 @@ Feature: Step - inject() | p[v[marko],v[vadas],vadas,d[5].i] | | p[v[marko],v[josh],josh,d[4].i] | + @GraphComputerVerificationInjectionNotSupported Scenario: g_VX1X_injectXg_VX4XX_out_name Given the modern graph And using the parameter vid1 defined as "v[marko].id" - And using the parameter v4 defined as "v[josh]" + And using the parameter v2 defined as "v[josh]" And the traversal of """ - g.V(vid1).inject(v4).out().values("name") + g.V(vid1).inject(v2).out().values("name") """ When iterated to list Then the result should be unordered @@ -130,7 +131,6 @@ Feature: Step - inject() | result | | null | - Scenario: g_inject Given the empty graph And the traversal of @@ -140,7 +140,6 @@ Feature: Step - inject() When iterated to list Then the result should be empty - @GraphComputerVerificationInjectionNotSupported Scenario: g_VX1X_valuesXageX_injectXnull_nullX Given the modern graph And using the parameter xx1 defined as "v[marko].id" diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/StepDefinition.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/StepDefinition.java index ea5eed3..d896228 100644 --- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/StepDefinition.java +++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/StepDefinition.java @@ -125,7 +125,7 @@ public final class StepDefinition { add(Pair.with(Pattern.compile("v\\[(.+)\\]\\.sid"), s -> g.V().has("name", s).id().next().toString())); add(Pair.with(Pattern.compile("v\\[(.+)\\]"), s -> { final Iterator<Object> itty = g.V().has("name", s).id(); - return String.format("new Vertex(\"%s\",\"%s\")", itty.hasNext() ? itty.next() : s, Vertex.DEFAULT_LABEL); + return String.format("new Vertex(%s,\"%s\")", itty.hasNext() ? itty.next() : s, Vertex.DEFAULT_LABEL); })); add(Pair.with(Pattern.compile("e\\[(.+)\\]\\.id"), s -> getEdgeIdString(g, s))); add(Pair.with(Pattern.compile("e\\[(.+)\\]\\.sid"), s -> getEdgeIdString(g, s))); @@ -138,9 +138,6 @@ public final class StepDefinition { add(Pair.with(Pattern.compile("c\\[(.*)\\]"), s -> { throw new AssumptionViolatedException("This test uses a lambda as a parameter which is not supported by gremlin-language"); })); - add(Pair.with(Pattern.compile("v\\[(.+)\\]"), s -> { - throw new AssumptionViolatedException("This test uses a Vertex as a parameter which is not supported by gremlin-language"); - })); add(Pair.with(Pattern.compile("e\\[(.+)\\]"), s -> { throw new AssumptionViolatedException("This test uses a Edge as a parameter which is not supported by gremlin-language"); })); diff --git a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/map/TinkerMergeVertexStep.java b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/map/TinkerMergeVertexStep.java index 5876879..6771ebd 100644 --- a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/map/TinkerMergeVertexStep.java +++ b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/map/TinkerMergeVertexStep.java @@ -42,6 +42,7 @@ public class TinkerMergeVertexStep<S> extends MergeVertexStep<S> { super(step.getTraversal(), step.isStart(), step.getSearchCreateTraversal()); if (step.getOnMatchTraversal() != null) this.addChildOption(Merge.onMatch, step.getOnMatchTraversal()); if (step.getOnCreateTraversal() != null) this.addChildOption(Merge.onCreate, step.getOnCreateTraversal()); + if (step.getCallbackRegistry() != null) this.callbackRegistry = step.getCallbackRegistry(); } @Override diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/TinkerGraphWorld.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/TinkerGraphWorld.java index 7d6f820..46856f8 100644 --- a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/TinkerGraphWorld.java +++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/TinkerGraphWorld.java @@ -106,6 +106,7 @@ public class TinkerGraphWorld implements World { private static final List<String> TAGS_TO_IGNORE = Arrays.asList( "@StepDrop", + "@StepInject", "@StepV", "@GraphComputerVerificationOneBulk", "@GraphComputerVerificationStrategyNotSupported",
