From 2c0ce57ecb140a6368a8df29b6f11f3eb7f34777 Mon Sep 17 00:00:00 2001 From: Florian Hockmann Date: Wed, 17 Jan 2024 16:09:49 +0100 Subject: [PATCH 01/18] TINKERPOP-3030 Update to .NET 8 I've also noticed that the examples used camel casing for some method names which I switched to pascal casing to stay idiomatic in C#. I had to update the Docker image to Ubuntu 20.04 because .NET 8 is not available for Ubuntu 18.04. Since 18.04 is out of support since June already, this update makes sense in general [1]. [1]: https://wiki.ubuntu.com/Releases --- .github/workflows/build-test.yml | 4 ++-- docker/Dockerfile | 8 ++++---- .../dev/developer/development-environment.asciidoc | 4 ++-- .../Examples/BasicGremlin/BasicGremlin.csproj | 2 +- gremlin-dotnet/Examples/Connections/Connections.cs | 12 ++++++------ .../Examples/Connections/Connections.csproj | 2 +- .../ModernTraversals/ModernTraversals.csproj | 2 +- gremlin-dotnet/docker-compose.yml | 2 +- .../Gremlin.Net.Template/Gremlin.Net.Template.csproj | 2 +- .../Gremlin.Net.Benchmarks.csproj | 2 +- .../Gremlin.Net.IntegrationTest.csproj | 2 +- .../Gremlin.Net.Template.IntegrationTest.csproj | 2 +- .../Gremlin.Net.UnitTest/Gremlin.Net.UnitTest.csproj | 2 +- 13 files changed, 23 insertions(+), 23 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index ef18acddabc..30e291a09a4 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -264,10 +264,10 @@ jobs: with: java-version: '11' distribution: 'temurin' - - name: Set up .NET 6.0.x + - name: Set up .NET 8.0.x uses: actions/setup-dotnet@v4 with: - dotnet-version: '6.0.x' + dotnet-version: '8.0.x' - name: Get Cached Server Base Image uses: actions/cache@v3 id: gremlin-server-test-docker-image diff --git a/docker/Dockerfile b/docker/Dockerfile index e12cc0f962d..96a6f592272 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -15,24 +15,24 @@ # specific language governing permissions and limitations # under the License. -FROM ubuntu:bionic +FROM ubuntu:focal LABEL maintainer="Daniel Kuppitz " RUN apt-get update RUN apt-get -y install software-properties-common python3-software-properties apt-transport-https curl dpkg netcat net-tools iproute2 RUN add-apt-repository ppa:openjdk-r/ppa -RUN sh -c 'curl -s https://packages.microsoft.com/config/ubuntu/18.04/packages-microsoft-prod.deb -o packages-microsoft-prod.deb' +RUN sh -c 'curl -s https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -o packages-microsoft-prod.deb' RUN sh -c 'dpkg -i packages-microsoft-prod.deb' RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF RUN apt-get install apt-transport-https gnupg ca-certificates -RUN sh -c 'echo "deb https://download.mono-project.com/repo/ubuntu stable-bionic main" | tee /etc/apt/sources.list.d/mono-official-stable.list' +RUN sh -c 'echo "deb https://download.mono-project.com/repo/ubuntu stable-focal main" | tee /etc/apt/sources.list.d/mono-official-stable.list' RUN apt-get update # include both java 8/11 so that we can use the same docker image for future builds on that version of the jdk as we do # for the older release branches. the java version to use is just controlled by JAVA_HOME hardcoded below RUN apt-get install -y openjdk-8-jdk openjdk-11-jdk gawk git maven openssh-server subversion zip -RUN apt-get install -y --force-yes dotnet-sdk-6.0 mono-devel +RUN apt-get install -y --force-yes dotnet-sdk-8.0 mono-devel ENV DEBIAN_FRONTEND=noninteractive RUN apt-get install -y python3 python3.8 python3-dev python3.8-dev python3-pip build-essential checkinstall zlib1g-dev libreadline-gplv2-dev \ diff --git a/docs/src/dev/developer/development-environment.asciidoc b/docs/src/dev/developer/development-environment.asciidoc index 251ac7f58ad..eb53fc11838 100644 --- a/docs/src/dev/developer/development-environment.asciidoc +++ b/docs/src/dev/developer/development-environment.asciidoc @@ -57,7 +57,7 @@ NOTE: For those using Windows, efforts have been made to keep the build OS indep that TinkerPop's build system will only allow for a minimum build at best. + + Refer to <> section for more details. - + [[groovy-environment]] === Groovy Environment @@ -267,7 +267,7 @@ See the <> section for more information [[dotnet-environment]] === DotNet Environment -The build optionally requires link:https://dotnet.microsoft.com/download[.NET SDK] (>=6.0) to work with the +The build optionally requires link:https://dotnet.microsoft.com/download[.NET SDK] (>=8.0) to work with the `gremlin-dotnet` module. If .NET SDK is not installed, TinkerPop will still build with Maven, but .NET projects will be skipped. diff --git a/gremlin-dotnet/Examples/BasicGremlin/BasicGremlin.csproj b/gremlin-dotnet/Examples/BasicGremlin/BasicGremlin.csproj index 6fe7a3b6333..3dcaf373ca0 100644 --- a/gremlin-dotnet/Examples/BasicGremlin/BasicGremlin.csproj +++ b/gremlin-dotnet/Examples/BasicGremlin/BasicGremlin.csproj @@ -19,7 +19,7 @@ limitations under the License. Exe - net7.0 + net8.0 enable enable diff --git a/gremlin-dotnet/Examples/Connections/Connections.cs b/gremlin-dotnet/Examples/Connections/Connections.cs index 26490f750b2..940cc05990b 100644 --- a/gremlin-dotnet/Examples/Connections/Connections.cs +++ b/gremlin-dotnet/Examples/Connections/Connections.cs @@ -26,13 +26,13 @@ public class ConnectionExample { static void Main() { - withRemote(); - withConf(); - withSerializer(); + WithRemote(); + WithConf(); + WithSerializer(); } // Connecting to the server - static void withRemote() + static void WithRemote() { var server = new GremlinServer("localhost", 8182); using var remoteConnection = new DriverRemoteConnection(new GremlinClient(server), "g"); @@ -48,7 +48,7 @@ static void withRemote() } // Connecting to the server with customized configurations - static void withConf() + static void WithConf() { using var remoteConnection = new DriverRemoteConnection(new GremlinClient( new GremlinServer(hostname: "localhost", port: 8182, enableSsl: false, username: "", password: "")), "g"); @@ -60,7 +60,7 @@ static void withConf() } // Specifying a serializer - static void withSerializer() + static void WithSerializer() { var server = new GremlinServer("localhost", 8182); var client = new GremlinClient(server, new GraphSON3MessageSerializer()); diff --git a/gremlin-dotnet/Examples/Connections/Connections.csproj b/gremlin-dotnet/Examples/Connections/Connections.csproj index 6fe7a3b6333..3dcaf373ca0 100644 --- a/gremlin-dotnet/Examples/Connections/Connections.csproj +++ b/gremlin-dotnet/Examples/Connections/Connections.csproj @@ -19,7 +19,7 @@ limitations under the License. Exe - net7.0 + net8.0 enable enable diff --git a/gremlin-dotnet/Examples/ModernTraversals/ModernTraversals.csproj b/gremlin-dotnet/Examples/ModernTraversals/ModernTraversals.csproj index 31dd1928968..4ba70d70981 100644 --- a/gremlin-dotnet/Examples/ModernTraversals/ModernTraversals.csproj +++ b/gremlin-dotnet/Examples/ModernTraversals/ModernTraversals.csproj @@ -19,7 +19,7 @@ limitations under the License. Exe - net7.0 + net8.0 enable enable diff --git a/gremlin-dotnet/docker-compose.yml b/gremlin-dotnet/docker-compose.yml index 99464d942ea..c85369fea35 100644 --- a/gremlin-dotnet/docker-compose.yml +++ b/gremlin-dotnet/docker-compose.yml @@ -45,7 +45,7 @@ services: gremlin-dotnet-integration-tests: container_name: gremlin-dotnet-integration-tests - image: mcr.microsoft.com/dotnet/sdk:6.0 + image: mcr.microsoft.com/dotnet/sdk:8.0 volumes: - .:/gremlin-dotnet - ../gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features:/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features diff --git a/gremlin-dotnet/src/Gremlin.Net.Template/Gremlin.Net.Template.csproj b/gremlin-dotnet/src/Gremlin.Net.Template/Gremlin.Net.Template.csproj index 7e0f0d67f3a..c31f3d69a4c 100644 --- a/gremlin-dotnet/src/Gremlin.Net.Template/Gremlin.Net.Template.csproj +++ b/gremlin-dotnet/src/Gremlin.Net.Template/Gremlin.Net.Template.csproj @@ -19,7 +19,7 @@ limitations under the License. Exe - net6.0 + net8.0 diff --git a/gremlin-dotnet/test/Gremlin.Net.Benchmarks/Gremlin.Net.Benchmarks.csproj b/gremlin-dotnet/test/Gremlin.Net.Benchmarks/Gremlin.Net.Benchmarks.csproj index 18d9ed53eb6..af2f34b8902 100644 --- a/gremlin-dotnet/test/Gremlin.Net.Benchmarks/Gremlin.Net.Benchmarks.csproj +++ b/gremlin-dotnet/test/Gremlin.Net.Benchmarks/Gremlin.Net.Benchmarks.csproj @@ -2,7 +2,7 @@ Exe - net6.0 + net8.0 diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gremlin.Net.IntegrationTest.csproj b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gremlin.Net.IntegrationTest.csproj index 9d6ebf4650f..cfce8352f88 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gremlin.Net.IntegrationTest.csproj +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gremlin.Net.IntegrationTest.csproj @@ -1,6 +1,6 @@ - net6.0 + net8.0 diff --git a/gremlin-dotnet/test/Gremlin.Net.Template.IntegrationTest/Gremlin.Net.Template.IntegrationTest.csproj b/gremlin-dotnet/test/Gremlin.Net.Template.IntegrationTest/Gremlin.Net.Template.IntegrationTest.csproj index dd4616224a7..b8eca918fda 100644 --- a/gremlin-dotnet/test/Gremlin.Net.Template.IntegrationTest/Gremlin.Net.Template.IntegrationTest.csproj +++ b/gremlin-dotnet/test/Gremlin.Net.Template.IntegrationTest/Gremlin.Net.Template.IntegrationTest.csproj @@ -1,7 +1,7 @@ - net6.0 + net8.0 diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Gremlin.Net.UnitTest.csproj b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Gremlin.Net.UnitTest.csproj index 9cceb5a0844..3fc90c42ccd 100644 --- a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Gremlin.Net.UnitTest.csproj +++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Gremlin.Net.UnitTest.csproj @@ -1,7 +1,7 @@ - net6.0 + net8.0 ../../build/tinkerpop.snk true true From d4892ada5432e9e850883aef6a76b78a81200840 Mon Sep 17 00:00:00 2001 From: Stephen Mallette Date: Tue, 13 Feb 2024 13:30:13 -0500 Subject: [PATCH 02/18] TINKERPOP-3031 Fixed bug in translation of g.tx() options --- CHANGELOG.asciidoc | 1 + .../gremlin/process/traversal/GraphOp.java | 7 +++++-- .../dsl/graph/GraphTraversalSource.java | 1 + .../translator/DotNetTranslator.java | 4 ++++ .../translator/GolangTranslator.java | 21 ++++++++++++------- .../translator/GroovyTranslator.java | 5 ++++- .../translator/JavascriptTranslator.java | 4 ++++ .../translator/PythonTranslator.java | 6 +++++- .../traversal/util/BytecodeHelper.java | 1 + .../gremlin/structure/Transaction.java | 14 +++++++++++++ .../translator/DotNetTranslatorTest.java | 9 ++++++++ .../translator/GolangTranslatorTest.java | 9 ++++++++ .../translator/GroovyTranslatorTest.java | 9 ++++++++ .../translator/JavascriptTranslatorTest.java | 9 ++++++++ .../translator/PythonTranslatorTest.java | 9 ++++++++ 15 files changed, 97 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index e886f0a7ae7..40fa4748912 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -24,6 +24,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima === TinkerPop 3.6.7 (NOT OFFICIALLY RELEASED YET) * Fixed a bug in Gremlin.Net for .NET 8 that led to exceptions: `InvalidOperationException: Enumeration has not started. Call MoveNext.` +* Fixed bug in bytecode translation of `g.tx().commit()` and `g.tx().rollback()` in all languages. * Improved error message from `JavaTranslator` by including exception source. * Added missing `short` serialization (`gx:Int16`) to GraphSONV2 and GraphSONV3 in `gremlin-python` * Added tests for error handling for GLV's if tx.commit() is called remotely for graphs without transactions support. diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/GraphOp.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/GraphOp.java index 370009c1933..ad479294144 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/GraphOp.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/GraphOp.java @@ -18,6 +18,9 @@ */ package org.apache.tinkerpop.gremlin.process.traversal; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.apache.tinkerpop.gremlin.structure.Transaction; + /** * A {@code GraphOp} or "graph operation" is a static {@link Bytecode} form that does not translate to a traversal * but instead refers to a specific function to perform on a graph instance. @@ -27,12 +30,12 @@ public enum GraphOp { /** * Commit a transaction. */ - TX_COMMIT(new Bytecode("tx", "commit")), + TX_COMMIT(new Bytecode(GraphTraversalSource.Symbols.tx, Transaction.Symbols.commit)), /** * Rollback a transaction. */ - TX_ROLLBACK(new Bytecode("tx", "rollback")); + TX_ROLLBACK(new Bytecode(GraphTraversalSource.Symbols.tx, Transaction.Symbols.rollback)); private final Bytecode bytecode; diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSource.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSource.java index c12bf41e469..a4bc9e33fae 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSource.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSource.java @@ -77,6 +77,7 @@ private Symbols() { public static final String withBulk = "withBulk"; public static final String withPath = "withPath"; + public static final String tx = "tx"; } 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 8e70b3000b4..fbc2c1dc831 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 @@ -33,6 +33,7 @@ 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; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.apache.tinkerpop.gremlin.process.traversal.strategy.TraversalStrategyProxy; import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.PartitionStrategy; import org.apache.tinkerpop.gremlin.process.traversal.util.ConnectiveP; @@ -385,6 +386,9 @@ protected Script produceScript(final String traversalSource, final Bytecode o) { convertToScript(instArg); } script.append(","); + } else if (methodName.equals(GraphTraversalSource.Symbols.tx)) { + final String command = resolveSymbol(instruction.getArguments()[0].toString()); + script.append(").").append(command).append("()"); } else if (methodName.equals(GraphTraversal.Symbols.call)) { // call() // call(String) diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GolangTranslator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GolangTranslator.java index 6aa6a006c1f..8f9628bcb8b 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GolangTranslator.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GolangTranslator.java @@ -26,10 +26,10 @@ 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.Text; import org.apache.tinkerpop.gremlin.process.traversal.TextP; import org.apache.tinkerpop.gremlin.process.traversal.Translator; import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.apache.tinkerpop.gremlin.process.traversal.strategy.TraversalStrategyProxy; import org.apache.tinkerpop.gremlin.process.traversal.util.ConnectiveP; import org.apache.tinkerpop.gremlin.process.traversal.util.OrP; @@ -297,16 +297,21 @@ protected Script produceScript(final String traversalSource, final Bytecode o) { final String methodName = instruction.getOperator(); final Object[] arguments = instruction.getArguments(); - script.append(".").append(resolveSymbol(methodName)).append("("); + if (methodName.equals(GraphTraversalSource.Symbols.tx)) { + final String command = resolveSymbol(arguments[0].toString()); + script.append(".").append(resolveSymbol(methodName)).append("().").append(resolveSymbol(command)).append("()"); + } else { + script.append(".").append(resolveSymbol(methodName)).append("("); - for (int i = 0; i < arguments.length; i++) { - convertToScript(arguments[i]); - if (i != arguments.length - 1) { - script.append(", "); + for (int i = 0; i < arguments.length; i++) { + convertToScript(arguments[i]); + if (i != arguments.length - 1) { + script.append(", "); + } } - } - script.append(")"); + script.append(")"); + } } return script; } 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 d87c8415143..7d35e65857b 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 @@ -30,9 +30,9 @@ import org.apache.tinkerpop.gremlin.process.traversal.TextP; import org.apache.tinkerpop.gremlin.process.traversal.Translator; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.apache.tinkerpop.gremlin.process.traversal.strategy.TraversalStrategyProxy; import org.apache.tinkerpop.gremlin.process.traversal.util.ConnectiveP; -import org.apache.tinkerpop.gremlin.process.traversal.util.OrP; import org.apache.tinkerpop.gremlin.structure.Edge; import org.apache.tinkerpop.gremlin.structure.Vertex; import org.apache.tinkerpop.gremlin.structure.VertexProperty; @@ -342,6 +342,9 @@ protected Script produceScript(final String traversalSource, final Bytecode byte convertToScript(o); if (itty.hasNext()) script.append(","); } + } else if (methodName.equals(GraphTraversalSource.Symbols.tx)) { + final String command = instruction.getArguments()[0].toString(); + script.append(").").append(command).append("("); } else { final Iterator itty = Arrays.stream(instruction.getArguments()).iterator(); while (itty.hasNext()) { diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/JavascriptTranslator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/JavascriptTranslator.java index c03fd01ebb5..a81a3d5b409 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/JavascriptTranslator.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/JavascriptTranslator.java @@ -31,6 +31,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.Translator; 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.GraphTraversalSource; import org.apache.tinkerpop.gremlin.process.traversal.strategy.TraversalStrategyProxy; import org.apache.tinkerpop.gremlin.process.traversal.util.ConnectiveP; import org.apache.tinkerpop.gremlin.process.traversal.util.OrP; @@ -322,6 +323,9 @@ protected Script produceScript(final String traversalSource, final Bytecode o) { script.append(", (").append(castSecondArgTo).append(") "); convertToScript(instruction.getArguments()[1]); script.append(","); + } else if (methodName.equals(GraphTraversalSource.Symbols.tx)) { + final String command = instruction.getArguments()[0].toString(); + script.append(").").append(command).append("()"); } else { for (final Object object : instruction.getArguments()) { convertToScript(object); diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/PythonTranslator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/PythonTranslator.java index 814cfcd9b3d..659b90f44cf 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/PythonTranslator.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/PythonTranslator.java @@ -32,6 +32,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.Traversal; import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.apache.tinkerpop.gremlin.process.traversal.strategy.TraversalStrategyProxy; import org.apache.tinkerpop.gremlin.process.traversal.util.ConnectiveP; import org.apache.tinkerpop.gremlin.process.traversal.util.OrP; @@ -308,7 +309,10 @@ else if (methodName.equals("limit") && 1 == arguments.length) script.append("[0:").append(arguments[0].toString()).append("]"); else if (methodName.equals("values") && 1 == arguments.length && script.getScript().length() > 3 && !STEP_NAMES.contains(arguments[0].toString())) script.append(".").append(arguments[0].toString()); - else { + else if (methodName.equals(GraphTraversalSource.Symbols.tx)) { + final String command = instruction.getArguments()[0].toString(); + script.append(".").append(methodName).append("().").append(command).append("()"); + } else { script.append(".").append(resolveSymbol(methodName)).append("("); // python has trouble with java varargs...wrapping in collection seems to solve the problem diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/BytecodeHelper.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/BytecodeHelper.java index 06f819a6283..7fa26c5f040 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/BytecodeHelper.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/BytecodeHelper.java @@ -272,6 +272,7 @@ public final class BytecodeHelper { put(TraversalSource.Symbols.withComputer, Collections.emptyList()); put(GraphTraversalSource.Symbols.withBulk, Collections.emptyList()); put(GraphTraversalSource.Symbols.withPath, Collections.emptyList()); + put(GraphTraversalSource.Symbols.tx, Collections.emptyList()); }}; byteCodeSymbolStepMap = Collections.unmodifiableMap(operationStepMap); } diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Transaction.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Transaction.java index d3a0eb60da6..3b6bc740963 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Transaction.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Transaction.java @@ -36,6 +36,20 @@ */ public interface Transaction extends AutoCloseable { + //////////////// + + public static final class Symbols { + + private Symbols() { + // static fields only + } + + public static final String commit = "commit"; + public static final String rollback = "rollback"; + + } + + //////////////// /** * Opens a transaction. */ diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/DotNetTranslatorTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/DotNetTranslatorTest.java index 28256f79fec..f6c6b51c504 100644 --- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/DotNetTranslatorTest.java +++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/DotNetTranslatorTest.java @@ -19,6 +19,7 @@ package org.apache.tinkerpop.gremlin.process.traversal.translator; +import org.apache.tinkerpop.gremlin.process.traversal.GraphOp; import org.apache.tinkerpop.gremlin.process.traversal.Merge; import org.apache.tinkerpop.gremlin.process.traversal.Order; import org.apache.tinkerpop.gremlin.process.traversal.P; @@ -273,6 +274,14 @@ public void shouldTranslateVertexAndEdge() { script4); } + @Test + public void shouldTranslateTx() { + String script = translator.translate(GraphOp.TX_COMMIT.getBytecode()).getScript(); + assertEquals("g.Tx().Commit()", script); + script = translator.translate(GraphOp.TX_ROLLBACK.getBytecode()).getScript(); + assertEquals("g.Tx().Rollback()", script); + } + private void assertTranslation(final String expectedTranslation, final Object... objs) { final String script = translator.translate(g.inject(objs).asAdmin().getBytecode()).getScript(); assertEquals(String.format("g.Inject(%s)", expectedTranslation), script); diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GolangTranslatorTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GolangTranslatorTest.java index cbc611f89b5..fa81e35d5ab 100644 --- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GolangTranslatorTest.java +++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GolangTranslatorTest.java @@ -21,6 +21,7 @@ import org.apache.commons.text.StringEscapeUtils; import org.apache.tinkerpop.gremlin.process.traversal.Bytecode; +import org.apache.tinkerpop.gremlin.process.traversal.GraphOp; import org.apache.tinkerpop.gremlin.process.traversal.Translator; import org.apache.tinkerpop.gremlin.process.traversal.Traverser; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; @@ -125,4 +126,12 @@ public void shouldTranslateArrayOfArray() { assertEquals("g.Inject([]interface{}{[]interface{}{1, 2}, []interface{}{3, 4}})", translator.translate(g.inject(Arrays.asList(Arrays.asList(1,2),Arrays.asList(3,4))).asAdmin().getBytecode()).getScript()); } + + @Test + public void shouldTranslateTx() { + String script = translator.translate(GraphOp.TX_COMMIT.getBytecode()).getScript(); + assertEquals("g.Tx().Commit()", script); + script = translator.translate(GraphOp.TX_ROLLBACK.getBytecode()).getScript(); + assertEquals("g.Tx().Rollback()", script); + } } diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslatorTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslatorTest.java index 082c6cf353f..575c7336b9a 100644 --- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslatorTest.java +++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslatorTest.java @@ -19,6 +19,7 @@ package org.apache.tinkerpop.gremlin.process.traversal.translator; +import org.apache.tinkerpop.gremlin.process.traversal.GraphOp; import org.apache.tinkerpop.gremlin.process.traversal.Order; import org.apache.tinkerpop.gremlin.process.traversal.Pop; import org.apache.tinkerpop.gremlin.process.traversal.Scope; @@ -307,6 +308,14 @@ public void shouldTranslateVertexAndEdge() { script4); } + @Test + public void shouldTranslateTx() { + String script = translator.translate(GraphOp.TX_COMMIT.getBytecode()).getScript(); + assertEquals("g.tx().commit()", script); + script = translator.translate(GraphOp.TX_ROLLBACK.getBytecode()).getScript(); + assertEquals("g.tx().rollback()", script); + } + private void assertTranslation(final String expectedTranslation, final Object... objs) { final String script = translator.translate(g.inject(objs)).getScript(); assertEquals(String.format("g.inject(%s)", expectedTranslation), script); diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/JavascriptTranslatorTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/JavascriptTranslatorTest.java index 98de2f988ca..88bff57ee69 100644 --- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/JavascriptTranslatorTest.java +++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/JavascriptTranslatorTest.java @@ -19,6 +19,7 @@ package org.apache.tinkerpop.gremlin.process.traversal.translator; +import org.apache.tinkerpop.gremlin.process.traversal.GraphOp; import org.apache.tinkerpop.gremlin.process.traversal.Order; import org.apache.tinkerpop.gremlin.process.traversal.Pop; import org.apache.tinkerpop.gremlin.process.traversal.Scope; @@ -197,6 +198,14 @@ public void shouldTranslateVertexAndEdge() { script4); } + @Test + public void shouldTranslateTx() { + String script = translator.translate(GraphOp.TX_COMMIT.getBytecode()).getScript(); + assertEquals("g.tx().commit()", script); + script = translator.translate(GraphOp.TX_ROLLBACK.getBytecode()).getScript(); + assertEquals("g.tx().rollback()", script); + } + private void assertTranslation(final String expectedTranslation, final Object... objs) { final String script = translator.translate(g.inject(objs).asAdmin().getBytecode()).getScript(); assertEquals(String.format("g.inject(%s)", expectedTranslation), script); diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/PythonTranslatorTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/PythonTranslatorTest.java index 9fee3ed4a98..c2b4e39a2df 100644 --- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/PythonTranslatorTest.java +++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/PythonTranslatorTest.java @@ -19,6 +19,7 @@ package org.apache.tinkerpop.gremlin.process.traversal.translator; import org.apache.tinkerpop.gremlin.process.traversal.Bytecode; +import org.apache.tinkerpop.gremlin.process.traversal.GraphOp; import org.apache.tinkerpop.gremlin.process.traversal.TextP; import org.apache.tinkerpop.gremlin.process.traversal.Translator; import org.apache.tinkerpop.gremlin.process.traversal.Traverser; @@ -131,6 +132,14 @@ public void shouldTranslateWithoutSyntaxSugar() { assertEquals("g.V().range_(0,10).has('person','name','marko').limit(2).values('name')", gremlinAsPython); } + @Test + public void shouldTranslateTx() { + String script = translator.translate(GraphOp.TX_COMMIT.getBytecode()).getScript(); + assertEquals("g.tx().commit()", script); + script = translator.translate(GraphOp.TX_ROLLBACK.getBytecode()).getScript(); + assertEquals("g.tx().rollback()", script); + } + private void assertTranslation(final String expectedTranslation, final Object... objs) { final String script = translator.translate(g.inject(objs).asAdmin().getBytecode()).getScript(); assertEquals(String.format("g.inject(%s)", expectedTranslation), script); From 8f2fdcb5003e94ca70b660ead24227b7192c0cce Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 14 Feb 2024 14:33:22 +0000 Subject: [PATCH 03/18] Bump System.Text.Json from 8.0.1 to 8.0.2 in /gremlin-dotnet Bumps [System.Text.Json](https://github.com/dotnet/runtime) from 8.0.1 to 8.0.2. - [Release notes](https://github.com/dotnet/runtime/releases) - [Commits](https://github.com/dotnet/runtime/compare/v8.0.1...v8.0.2) --- updated-dependencies: - dependency-name: System.Text.Json dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gremlin-dotnet/src/Gremlin.Net/Gremlin.Net.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gremlin-dotnet/src/Gremlin.Net/Gremlin.Net.csproj b/gremlin-dotnet/src/Gremlin.Net/Gremlin.Net.csproj index 9ba623ab36e..ee159220f89 100644 --- a/gremlin-dotnet/src/Gremlin.Net/Gremlin.Net.csproj +++ b/gremlin-dotnet/src/Gremlin.Net/Gremlin.Net.csproj @@ -73,7 +73,7 @@ NOTE that versions suffixed with "-rc" are considered release candidates (i.e. p - + From aeedc575cddab7170039e3aca1518b606511a464 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 16 Feb 2024 14:24:02 +0000 Subject: [PATCH 04/18] Bump xunit from 2.6.6 to 2.7.0 in /gremlin-dotnet Bumps [xunit](https://github.com/xunit/xunit) from 2.6.6 to 2.7.0. - [Commits](https://github.com/xunit/xunit/compare/2.6.6...2.7.0) --- updated-dependencies: - dependency-name: xunit dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .../Gremlin.Net.IntegrationTest.csproj | 2 +- .../Gremlin.Net.Template.IntegrationTest.csproj | 2 +- .../test/Gremlin.Net.UnitTest/Gremlin.Net.UnitTest.csproj | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gremlin.Net.IntegrationTest.csproj b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gremlin.Net.IntegrationTest.csproj index ca4513293af..f3943bce4ca 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gremlin.Net.IntegrationTest.csproj +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gremlin.Net.IntegrationTest.csproj @@ -16,7 +16,7 @@ - + diff --git a/gremlin-dotnet/test/Gremlin.Net.Template.IntegrationTest/Gremlin.Net.Template.IntegrationTest.csproj b/gremlin-dotnet/test/Gremlin.Net.Template.IntegrationTest/Gremlin.Net.Template.IntegrationTest.csproj index 9aa221756ec..0f4b2cdba36 100644 --- a/gremlin-dotnet/test/Gremlin.Net.Template.IntegrationTest/Gremlin.Net.Template.IntegrationTest.csproj +++ b/gremlin-dotnet/test/Gremlin.Net.Template.IntegrationTest/Gremlin.Net.Template.IntegrationTest.csproj @@ -6,7 +6,7 @@ - + diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Gremlin.Net.UnitTest.csproj b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Gremlin.Net.UnitTest.csproj index 8ddb1b29bb8..f96bdd490d6 100644 --- a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Gremlin.Net.UnitTest.csproj +++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Gremlin.Net.UnitTest.csproj @@ -15,7 +15,7 @@ - + From 35cc1592ae10152a33218336072ab9a4632e089a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 16 Feb 2024 14:24:59 +0000 Subject: [PATCH 05/18] Bump gherkin from 27.0.0 to 28.0.0 in /gremlin-dotnet Bumps [gherkin](https://github.com/cucumber/gherkin) from 27.0.0 to 28.0.0. - [Release notes](https://github.com/cucumber/gherkin/releases) - [Changelog](https://github.com/cucumber/gherkin/blob/main/CHANGELOG.md) - [Commits](https://github.com/cucumber/gherkin/compare/v27.0.0...v28.0.0) --- updated-dependencies: - dependency-name: gherkin dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .../Gremlin.Net.IntegrationTest.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gremlin.Net.IntegrationTest.csproj b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gremlin.Net.IntegrationTest.csproj index ca4513293af..e9887e4a769 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gremlin.Net.IntegrationTest.csproj +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gremlin.Net.IntegrationTest.csproj @@ -11,7 +11,7 @@ - + From bf63fcb1811565cb6c61d00d0e2bd343c60d4f8a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 16 Feb 2024 14:27:05 +0000 Subject: [PATCH 06/18] Bump xunit.runner.visualstudio from 2.5.6 to 2.5.7 in /gremlin-dotnet Bumps [xunit.runner.visualstudio](https://github.com/xunit/visualstudio.xunit) from 2.5.6 to 2.5.7. - [Release notes](https://github.com/xunit/visualstudio.xunit/releases) - [Commits](https://github.com/xunit/visualstudio.xunit/compare/2.5.6...2.5.7) --- updated-dependencies: - dependency-name: xunit.runner.visualstudio dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .../Gremlin.Net.IntegrationTest.csproj | 2 +- .../Gremlin.Net.Template.IntegrationTest.csproj | 2 +- .../test/Gremlin.Net.UnitTest/Gremlin.Net.UnitTest.csproj | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gremlin.Net.IntegrationTest.csproj b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gremlin.Net.IntegrationTest.csproj index ca4513293af..b3f3043f441 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gremlin.Net.IntegrationTest.csproj +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gremlin.Net.IntegrationTest.csproj @@ -15,7 +15,7 @@ - + diff --git a/gremlin-dotnet/test/Gremlin.Net.Template.IntegrationTest/Gremlin.Net.Template.IntegrationTest.csproj b/gremlin-dotnet/test/Gremlin.Net.Template.IntegrationTest/Gremlin.Net.Template.IntegrationTest.csproj index 9aa221756ec..78a9a378a1a 100644 --- a/gremlin-dotnet/test/Gremlin.Net.Template.IntegrationTest/Gremlin.Net.Template.IntegrationTest.csproj +++ b/gremlin-dotnet/test/Gremlin.Net.Template.IntegrationTest/Gremlin.Net.Template.IntegrationTest.csproj @@ -7,7 +7,7 @@ - + diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Gremlin.Net.UnitTest.csproj b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Gremlin.Net.UnitTest.csproj index 8ddb1b29bb8..749e955297b 100644 --- a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Gremlin.Net.UnitTest.csproj +++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Gremlin.Net.UnitTest.csproj @@ -14,7 +14,7 @@ - + From b7115b57d314c0c616585a84495bd0d14ea8dd29 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Feb 2024 08:07:52 -0800 Subject: [PATCH 07/18] Bump eslint (#2507) Bumps [eslint](https://github.com/eslint/eslint) from 8.56.0 to 8.57.0. - [Release notes](https://github.com/eslint/eslint/releases) - [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint/eslint/compare/v8.56.0...v8.57.0) --- updated-dependencies: - dependency-name: eslint dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .../gremlin-javascript/package-lock.json | 64 +++++++++---------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/package-lock.json b/gremlin-javascript/src/main/javascript/gremlin-javascript/package-lock.json index 0b86446496f..4dcb4a385e5 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/package-lock.json +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/package-lock.json @@ -130,22 +130,22 @@ } }, "node_modules/@eslint/js": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", - "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.13", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", - "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^2.0.1", - "debug": "^4.1.1", + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", "minimatch": "^3.0.5" }, "engines": { @@ -166,9 +166,9 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", - "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", + "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", "dev": true }, "node_modules/@nodelib/fs.scandir": { @@ -1044,16 +1044,16 @@ } }, "node_modules/eslint": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", - "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.56.0", - "@humanwhocodes/config-array": "^0.11.13", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "@ungap/structured-clone": "^1.2.0", @@ -4007,19 +4007,19 @@ } }, "@eslint/js": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", - "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", "dev": true }, "@humanwhocodes/config-array": { - "version": "0.11.13", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", - "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", "dev": true, "requires": { - "@humanwhocodes/object-schema": "^2.0.1", - "debug": "^4.1.1", + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", "minimatch": "^3.0.5" } }, @@ -4030,9 +4030,9 @@ "dev": true }, "@humanwhocodes/object-schema": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", - "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", + "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", "dev": true }, "@nodelib/fs.scandir": { @@ -4711,16 +4711,16 @@ "dev": true }, "eslint": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", - "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.56.0", - "@humanwhocodes/config-array": "^0.11.13", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "@ungap/structured-clone": "^1.2.0", From af5c9148b61423b922d4796585ebd3e6e669798c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Feb 2024 08:08:26 -0800 Subject: [PATCH 08/18] Bump mocha in /gremlin-javascript/src/main/javascript/gremlin-javascript (#2484) Bumps [mocha](https://github.com/mochajs/mocha) from 10.2.0 to 10.3.0. - [Release notes](https://github.com/mochajs/mocha/releases) - [Changelog](https://github.com/mochajs/mocha/blob/master/CHANGELOG.md) - [Commits](https://github.com/mochajs/mocha/compare/v10.2.0...v10.3.0) --- updated-dependencies: - dependency-name: mocha dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .../gremlin-javascript/package-lock.json | 87 ++++--------------- 1 file changed, 19 insertions(+), 68 deletions(-) diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/package-lock.json b/gremlin-javascript/src/main/javascript/gremlin-javascript/package-lock.json index 4dcb4a385e5..8bf13a8572f 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/package-lock.json +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/package-lock.json @@ -2694,9 +2694,9 @@ } }, "node_modules/mocha": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", - "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.3.0.tgz", + "integrity": "sha512-uF2XJs+7xSLsrmIvn37i/wnc91nw7XjOQB8ccyx5aEgdnohr7n+rEiZP23WkCYHjilR6+EboEnbq/ZQDz4LSbg==", "dev": true, "dependencies": { "ansi-colors": "4.1.1", @@ -2706,13 +2706,12 @@ "diff": "5.0.0", "escape-string-regexp": "4.0.0", "find-up": "5.0.0", - "glob": "7.2.0", + "glob": "8.1.0", "he": "1.2.0", "js-yaml": "4.1.0", "log-symbols": "4.1.0", "minimatch": "5.0.1", "ms": "2.1.3", - "nanoid": "3.3.3", "serialize-javascript": "6.0.0", "strip-json-comments": "3.1.1", "supports-color": "8.1.1", @@ -2727,10 +2726,6 @@ }, "engines": { "node": ">= 14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" } }, "node_modules/mocha/node_modules/argparse": { @@ -2761,37 +2756,24 @@ } }, "node_modules/mocha/node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "minimatch": "^5.0.1", + "once": "^1.3.0" }, "engines": { - "node": "*" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/mocha/node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/mocha/node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -2863,18 +2845,6 @@ "thenify-all": "^1.0.0" } }, - "node_modules/nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", - "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -5949,9 +5919,9 @@ "dev": true }, "mocha": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", - "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.3.0.tgz", + "integrity": "sha512-uF2XJs+7xSLsrmIvn37i/wnc91nw7XjOQB8ccyx5aEgdnohr7n+rEiZP23WkCYHjilR6+EboEnbq/ZQDz4LSbg==", "dev": true, "requires": { "ansi-colors": "4.1.1", @@ -5961,13 +5931,12 @@ "diff": "5.0.0", "escape-string-regexp": "4.0.0", "find-up": "5.0.0", - "glob": "7.2.0", + "glob": "8.1.0", "he": "1.2.0", "js-yaml": "4.1.0", "log-symbols": "4.1.0", "minimatch": "5.0.1", "ms": "2.1.3", - "nanoid": "3.3.3", "serialize-javascript": "6.0.0", "strip-json-comments": "3.1.1", "supports-color": "8.1.1", @@ -5996,28 +5965,16 @@ "dev": true }, "glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "dependencies": { - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - } + "minimatch": "^5.0.1", + "once": "^1.3.0" } }, "js-yaml": { @@ -6083,12 +6040,6 @@ "thenify-all": "^1.0.0" } }, - "nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", - "dev": true - }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", From ddb646e51edcbd32dad4c394ab0fec17b05dc043 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Feb 2024 08:09:01 -0800 Subject: [PATCH 09/18] Bump github.com/cucumber/godog from 0.13.0 to 0.14.0 in /gremlin-go (#2471) Bumps [github.com/cucumber/godog](https://github.com/cucumber/godog) from 0.13.0 to 0.14.0. - [Release notes](https://github.com/cucumber/godog/releases) - [Changelog](https://github.com/cucumber/godog/blob/main/CHANGELOG.md) - [Commits](https://github.com/cucumber/godog/compare/v0.13.0...v0.14.0) --- updated-dependencies: - dependency-name: github.com/cucumber/godog dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- gremlin-go/go.mod | 2 +- gremlin-go/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gremlin-go/go.mod b/gremlin-go/go.mod index a3209ee9760..98d2defbd28 100644 --- a/gremlin-go/go.mod +++ b/gremlin-go/go.mod @@ -20,7 +20,7 @@ module github.com/apache/tinkerpop/gremlin-go/v3 go 1.20 require ( - github.com/cucumber/godog v0.13.0 + github.com/cucumber/godog v0.14.0 github.com/google/uuid v1.6.0 github.com/gorilla/websocket v1.5.1 github.com/nicksnyder/go-i18n/v2 v2.3.0 diff --git a/gremlin-go/go.sum b/gremlin-go/go.sum index 4f1476ca0d8..98d617f3d23 100644 --- a/gremlin-go/go.sum +++ b/gremlin-go/go.sum @@ -2,8 +2,8 @@ github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8 github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cucumber/gherkin/go/v26 v26.2.0 h1:EgIjePLWiPeslwIWmNQ3XHcypPsWAHoMCz/YEBKP4GI= github.com/cucumber/gherkin/go/v26 v26.2.0/go.mod h1:t2GAPnB8maCT4lkHL99BDCVNzCh1d7dBhCLt150Nr/0= -github.com/cucumber/godog v0.13.0 h1:KvX9kNWmAJwp882HmObGOyBbNUP5SXQ+SDLNajsuV7A= -github.com/cucumber/godog v0.13.0/go.mod h1:FX3rzIDybWABU4kuIXLZ/qtqEe1Ac5RdXmqvACJOces= +github.com/cucumber/godog v0.14.0 h1:h/K4t7XBxsFBF+UJEahNqJ1/2VHVepRXCSq3WWWnehs= +github.com/cucumber/godog v0.14.0/go.mod h1:FX3rzIDybWABU4kuIXLZ/qtqEe1Ac5RdXmqvACJOces= github.com/cucumber/messages/go/v21 v21.0.1 h1:wzA0LxwjlWQYZd32VTlAVDTkW6inOFmSM+RuOwHZiMI= github.com/cucumber/messages/go/v21 v21.0.1/go.mod h1:zheH/2HS9JLVFukdrsPWoPdmUtmYQAQPLk7w5vWsk5s= github.com/cucumber/messages/go/v22 v22.0.0/go.mod h1:aZipXTKc0JnjCsXrJnuZpWhtay93k7Rn3Dee7iyPJjs= From 3166f1b347bd1f8ff1e6923ea522f20ca9b5ffbe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Feb 2024 08:09:26 -0800 Subject: [PATCH 10/18] Bump github.com/nicksnyder/go-i18n/v2 from 2.3.0 to 2.4.0 in /gremlin-go (#2469) Bumps [github.com/nicksnyder/go-i18n/v2](https://github.com/nicksnyder/go-i18n) from 2.3.0 to 2.4.0. - [Release notes](https://github.com/nicksnyder/go-i18n/releases) - [Changelog](https://github.com/nicksnyder/go-i18n/blob/main/CHANGELOG.md) - [Commits](https://github.com/nicksnyder/go-i18n/compare/v2.3.0...v2.4.0) --- updated-dependencies: - dependency-name: github.com/nicksnyder/go-i18n/v2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- gremlin-go/go.mod | 2 +- gremlin-go/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gremlin-go/go.mod b/gremlin-go/go.mod index 98d2defbd28..111ad2210bd 100644 --- a/gremlin-go/go.mod +++ b/gremlin-go/go.mod @@ -23,7 +23,7 @@ require ( github.com/cucumber/godog v0.14.0 github.com/google/uuid v1.6.0 github.com/gorilla/websocket v1.5.1 - github.com/nicksnyder/go-i18n/v2 v2.3.0 + github.com/nicksnyder/go-i18n/v2 v2.4.0 github.com/stretchr/testify v1.8.4 golang.org/x/text v0.14.0 ) diff --git a/gremlin-go/go.sum b/gremlin-go/go.sum index 98d617f3d23..ab647d5a0da 100644 --- a/gremlin-go/go.sum +++ b/gremlin-go/go.sum @@ -34,8 +34,8 @@ github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/nicksnyder/go-i18n/v2 v2.3.0 h1:2NPsCsNFCVd7i+Su0xYsBrIhS3bE2XMv5gNTft2O+PQ= -github.com/nicksnyder/go-i18n/v2 v2.3.0/go.mod h1:nxYSZE9M0bf3Y70gPQjN9ha7XNHX7gMc814+6wVyEI4= +github.com/nicksnyder/go-i18n/v2 v2.4.0 h1:3IcvPOAvnCKwNm0TB0dLDTuawWEj+ax/RERNC+diLMM= +github.com/nicksnyder/go-i18n/v2 v2.4.0/go.mod h1:nxYSZE9M0bf3Y70gPQjN9ha7XNHX7gMc814+6wVyEI4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= From 1efe40b2881177c8975fca16b0791bd9ccf9fbd7 Mon Sep 17 00:00:00 2001 From: Ryan Tan <65996005+ryn5@users.noreply.github.com> Date: Thu, 29 Feb 2024 08:56:10 -0800 Subject: [PATCH 11/18] TINKERPOP-3054 Fix requestId Deserialization in `gremlin-python` (#2494) https://issues.apache.org/jira/browse/TINKERPOP-3054 Added str() guards to request_id before validating to avoid passing UUID into UUID constructor, which is intended to receive a string. --- CHANGELOG.asciidoc | 5 +++-- .../src/main/python/gremlin_python/driver/connection.py | 7 ++++--- .../src/main/python/gremlin_python/driver/serializer.py | 2 +- gremlin-python/src/main/python/tests/driver/test_client.py | 6 +++++- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index b70b64ccd7d..6f2e3d63c31 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -24,14 +24,15 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima === TinkerPop 3.6.7 (NOT OFFICIALLY RELEASED YET) * Fixed a bug in Gremlin.Net for .NET 8 that led to exceptions: `InvalidOperationException: Enumeration has not started. Call MoveNext.` +* Fixed message requestId serialization in `gremlin-python`. * Fixed bug in bytecode translation of `g.tx().commit()` and `g.tx().rollback()` in all languages. * Improved error message from `JavaTranslator` by including exception source. -* Added missing `short` serialization (`gx:Int16`) to GraphSONV2 and GraphSONV3 in `gremlin-python` +* Added missing `short` serialization (`gx:Int16`) to GraphSONV2 and GraphSONV3 in `gremlin-python`. * Added tests for error handling for GLV's if tx.commit() is called remotely for graphs without transactions support. * Introduced multi-architecture AMD64/ARM64 docker images for gremlin-console. * Fixed bug in `JavaTranslator` where `has(String, null)` could call `has(String, Traversal)` to generate an error. * Fixed issue where server errors weren't being properly parsed when sending bytecode over HTTP. -* Improved bulkset contains check for elements if all elements in bulkset are of the same type +* Improved bulkset contains check for elements if all elements in bulkset are of the same type. * Fixed bug in `EarlyLimitStrategy` which was too aggressive when promoting `limit()` before `map()`. * Fixed bug in mid-traversal `mergeE()` where mutations in `sideEffect()` were being applied to the current traverser rather than a `onMatch` edge. diff --git a/gremlin-python/src/main/python/gremlin_python/driver/connection.py b/gremlin-python/src/main/python/gremlin_python/driver/connection.py index 9641e4e203a..789de181d02 100644 --- a/gremlin-python/src/main/python/gremlin_python/driver/connection.py +++ b/gremlin-python/src/main/python/gremlin_python/driver/connection.py @@ -58,10 +58,11 @@ def close(self): def write(self, request_message): if not self._inited: self.connect() - request_id = str(uuid.uuid4()) if request_message.args.get("requestId"): - request_id = request_message.args.get("requestId") - uuid.UUID(request_id) # Checks for proper UUID or else server will return an error. + request_id = str(request_message.args.get("requestId")) + uuid.UUID(request_id) # Checks for proper UUID or else server will return an error. + else: + request_id = str(uuid.uuid4()) result_set = resultset.ResultSet(queue.Queue(), request_id) self._results[request_id] = result_set # Create write task diff --git a/gremlin-python/src/main/python/gremlin_python/driver/serializer.py b/gremlin-python/src/main/python/gremlin_python/driver/serializer.py index 74ed99523c2..6b522e50b39 100644 --- a/gremlin-python/src/main/python/gremlin_python/driver/serializer.py +++ b/gremlin-python/src/main/python/gremlin_python/driver/serializer.py @@ -240,7 +240,7 @@ def build_message(self, request_id, processor, op, args): def finalize_message(self, message, mime_len, mime_type): ba = bytearray() - request_id = uuid.UUID(message['requestId']) + request_id = uuid.UUID(str(message['requestId'])) ba.extend(self.header_pack(mime_len, mime_type, 0x81, (request_id.int >> 64) & self.max_int64, request_id.int & self.max_int64)) diff --git a/gremlin-python/src/main/python/tests/driver/test_client.py b/gremlin-python/src/main/python/tests/driver/test_client.py index 221b825ea6d..9bff038eb18 100644 --- a/gremlin-python/src/main/python/tests/driver/test_client.py +++ b/gremlin-python/src/main/python/tests/driver/test_client.py @@ -453,7 +453,11 @@ def test_client_custom_invalid_request_id_graphbinary_script(client): assert "badly formed hexadecimal UUID string" in str(ex) -def test_client_custom_valid_request_id_script(client): +def test_client_custom_valid_request_id_script_uuid(client): + assert len(client.submit('g.V()', request_options={"requestId":uuid.uuid4()}).all().result()) == 6 + + +def test_client_custom_valid_request_id_script_string(client): assert len(client.submit('g.V()', request_options={"requestId":str(uuid.uuid4())}).all().result()) == 6 From beb1a5f35d27e0e76d3a75f2cceb6546b503b297 Mon Sep 17 00:00:00 2001 From: Stephen Mallette Date: Fri, 1 Mar 2024 09:25:09 -0500 Subject: [PATCH 12/18] Improve performance of PathRetractionStrategy Helpful for traversals with lots of children where labels don't need to propagate. CTR --- CHANGELOG.asciidoc | 1 + .../strategy/optimization/PathRetractionStrategy.java | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index 6f2e3d63c31..e6f71e13bc3 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -25,6 +25,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima * Fixed a bug in Gremlin.Net for .NET 8 that led to exceptions: `InvalidOperationException: Enumeration has not started. Call MoveNext.` * Fixed message requestId serialization in `gremlin-python`. +* Improved performance of `PathRetractionStrategy` for traversals that carry many children, but don't hold many labels to propogate. * Fixed bug in bytecode translation of `g.tx().commit()` and `g.tx().rollback()` in all languages. * Improved error message from `JavaTranslator` by including exception source. * Added missing `short` serialization (`gx:Int16`) to GraphSONV2 and GraphSONV3 in `gremlin-python`. diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/PathRetractionStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/PathRetractionStrategy.java index cd29b288203..fc4e8457974 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/PathRetractionStrategy.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/PathRetractionStrategy.java @@ -249,6 +249,10 @@ private static boolean isNotApplicable(final Traversal.Admin traversal) { } private void applyToChildren(final Set keepLabels, final List> children) { + // if there are no labels to keep, then there no need to iterate all the children because we won't be + // adding anything PathProcessor keepLabels - avoids the added recursion + if (keepLabels.isEmpty()) return; + for (final Traversal.Admin child : children) { TraversalHelper.applyTraversalRecursively(trav -> addLabels(trav, keepLabels), child); } From 2d950116db2ec61e54d23cf3ea36dc3ef977af06 Mon Sep 17 00:00:00 2001 From: steigma <87522003+steigma@users.noreply.github.com> Date: Tue, 5 Mar 2024 22:51:19 +0100 Subject: [PATCH 13/18] Avoiding expensive hash computation for complex steps with many children in filter ranking strategy (#2504) Avoiding expensive hash computation for complex steps with many children in filter ranking strategy by using identity hash map instead of linked hash map. With the linked hash map, a hash computation is repeated for the traversal parent with each child when doing the grouping, which can be quite costly when there are several hundreds of children (especially since the hash computation also includes the hash of child steps). --- CHANGELOG.asciidoc | 1 + .../optimization/FilterRankingStrategy.java | 129 +++++- ...ankingStrategyCacheInitializationTest.java | 434 ++++++++++++++++++ .../FilterRankingStrategyTest.java | 179 ++++++-- 4 files changed, 681 insertions(+), 62 deletions(-) create mode 100644 gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategyCacheInitializationTest.java diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index e6f71e13bc3..27fde68afd7 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -36,6 +36,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima * Improved bulkset contains check for elements if all elements in bulkset are of the same type. * Fixed bug in `EarlyLimitStrategy` which was too aggressive when promoting `limit()` before `map()`. * Fixed bug in mid-traversal `mergeE()` where mutations in `sideEffect()` were being applied to the current traverser rather than a `onMatch` edge. +* Improved performance of the application of `FilterRankingStrategy` for large traversals with deeply nested traversals by improving the cache operation. [[release-3-6-6]] === TinkerPop 3.6.6 (November 20, 2023) diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategy.java index 9ebfeb7ed80..96630be526f 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategy.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategy.java @@ -35,18 +35,21 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.filter.TraversalFilterStep; import org.apache.tinkerpop.gremlin.process.traversal.step.filter.WherePredicateStep; import org.apache.tinkerpop.gremlin.process.traversal.step.filter.WhereTraversalStep; +import org.apache.tinkerpop.gremlin.process.traversal.step.util.EmptyStep; import org.apache.tinkerpop.gremlin.process.traversal.step.map.OrderGlobalStep; import org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy; +import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.IdentityRemovalStrategy; import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper; import org.javatuples.Pair; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.Stack; import java.util.stream.Collectors; /** @@ -85,35 +88,24 @@ public void apply(final Traversal.Admin traversal) { // this cache holds the parent and a pair. the first item in the pair is a boolean which is true if // lambda is present and false otherwise. the second item in the pair is a set of labels from any // Scoping steps - final Map>> traversalParentCache = new HashMap<>(); final Map stepRanking = new HashMap<>(); // gather the parents and their Scoping/LambdaHolder steps to build up the cache. since the traversal is // processed in depth first manner, the entries gathered to m are deepest child first and held in order, // so that the cache can be constructed with parent's knowing their children were processed first - final Map>> m = - TraversalHelper.getStepsOfAssignableClassRecursivelyFromDepth(traversal, TraversalParent.class).stream(). - collect(Collectors.groupingBy(step -> ((Step) step).getTraversal().getParent(), LinkedHashMap::new, Collectors.toList())); - - // build the cache and use it to detect if any children impact the Pair in any way. in the case of a - // child with a lambda, the parent would simply inherit that true. in the case of additional labels they - // would just be appended to the list for the parent. - m.forEach((k, v) -> { - final boolean hasLambda = v.stream().anyMatch(s -> s instanceof LambdaHolder || - (traversalParentCache.containsKey(s) && traversalParentCache.get(s).getValue0())); - if (hasLambda) { - traversalParentCache.put(k, Pair.with(true, Collections.emptySet())); - } else { - final Set currentEntryScopeLabels = v.stream().filter(s -> s instanceof Scoping). - flatMap(s -> ((Scoping) s).getScopeKeys().stream()).collect(Collectors.toSet()); - final Set allScopeLabels = new HashSet<>(currentEntryScopeLabels); - v.stream().filter(traversalParentCache::containsKey).forEach(s -> { - final TraversalParent parent = (TraversalParent) s; - allScopeLabels.addAll(traversalParentCache.get(parent).getValue1()); - }); - traversalParentCache.put(k, Pair.with(false, allScopeLabels)); - } - }); + // Note: We should avoid using streams with groupingBy collectors for this (e.g., with code of the form + // TraversalHelper.getStepsOfAssignableClassRecursivelyFromDepth(traversal, TraversalParent.class).stream(). + // collect(Collectors.groupingBy(step -> ((Step) step).getTraversal().getParent(), LinkedHashMap::new, Collectors.toList())) ) + // since it would mean that we do hash computation multiple times for the traversal parent (which can be a + // complex step with many children). + // Also note that IdentityHashMap is not an option for above Collectors.groupingBy call since it would not + // retain the required order (deepest traversal parents first). + final List>>> traversalParentsStepsCollection = + collectStepsOfAssignableClassRecursivelyFromDepthGroupedByParent(traversal); + + // create cache + final Map>> traversalParentCache = + getTraversalParentCache(traversalParentsStepsCollection); TraversalHelper.applyTraversalRecursively(t -> { boolean modified = true; @@ -144,6 +136,34 @@ public void apply(final Traversal.Admin traversal) { } } + public static Map>> getTraversalParentCache( + final List>>> traversalParentsStepsCollection) { + final Map>> traversalParentCache = new HashMap<>(); + + // build the cache and use it to detect if any children impact the Pair in any way. in the case of a + // child with a lambda, the parent would simply inherit that true. in the case of additional labels they + // would just be appended to the list for the parent. + traversalParentsStepsCollection.forEach(pair -> { + final TraversalParent k = pair.getValue0(); + final List> v = pair.getValue1(); + final boolean hasLambda = v.stream().anyMatch(s -> s instanceof LambdaHolder || + (traversalParentCache.containsKey(s) && traversalParentCache.get(s).getValue0())); + if (hasLambda) { + traversalParentCache.put(k, Pair.with(true, Collections.emptySet())); + } else { + final Set currentEntryScopeLabels = v.stream().filter(s -> s instanceof Scoping). + flatMap(s -> ((Scoping) s).getScopeKeys().stream()).collect(Collectors.toSet()); + final Set allScopeLabels = new HashSet<>(currentEntryScopeLabels); + v.stream().filter(traversalParentCache::containsKey).forEach(s -> { + final TraversalParent parent = (TraversalParent) s; + allScopeLabels.addAll(traversalParentCache.get(parent).getValue1()); + }); + traversalParentCache.put(k, Pair.with(false, allScopeLabels)); + } + }); + return traversalParentCache; + } + /** * Ranks the given step. Steps with lower ranks can be moved in front of steps with higher ranks. 0 means that * the step has no rank and thus is not exchangeable with its neighbors. @@ -232,4 +252,63 @@ public Set> applyPrior() { public static FilterRankingStrategy instance() { return INSTANCE; } + + /** + * Get steps of the specified class throughout the traversal and grouping them based on the traversal parent + * collecting them in a fashion that orders them from the deepest steps first + */ + public static List>>> collectStepsOfAssignableClassRecursivelyFromDepthGroupedByParent( + final Traversal.Admin traversal) { + + final List>>> traversalParentCollectionList = new ArrayList<>(); + final Stack> processingStack = new Stack<>(); + + final List> noParentlist = new ArrayList<>(); + traversal.getSteps().forEach(childStep -> { + handleChildStepCollection(processingStack, noParentlist, childStep); + }); + if (!noParentlist.isEmpty()) { + // we reverse the list here to keep it the same way as we had it before combining + // the recursive collection and grouping into this method + Collections.reverse(noParentlist); + // steps of the main/root traversal do not have any parent, so we just add them under the EmptyStep + traversalParentCollectionList.add(new Pair<>((TraversalParent)EmptyStep.instance(), noParentlist)); + } + + while (!processingStack.isEmpty()) { + final List> childStepCollectionlist = new ArrayList<>(); + final Step current = processingStack.pop(); + + if (current instanceof TraversalParent) { + ((TraversalParent) current).getLocalChildren().forEach(localChild -> localChild.getSteps().forEach(childStep -> { + handleChildStepCollection(processingStack, childStepCollectionlist, childStep); + })); + ((TraversalParent) current).getGlobalChildren().forEach(globalChild -> globalChild.getSteps().forEach(childStep -> { + handleChildStepCollection(processingStack, childStepCollectionlist, childStep); + })); + + if (!childStepCollectionlist.isEmpty()) { + // we reverse the childStepCollectionlist here to keep it the same way as we had it before combining + // the recursive collection and grouping into this method + Collections.reverse(childStepCollectionlist); + // desired children are added together/grouped on the traversal parent + traversalParentCollectionList.add(new Pair<>((TraversalParent)current, childStepCollectionlist)); + } + } + } + // reverse the list such that we get the deepest steps first + Collections.reverse(traversalParentCollectionList); + return traversalParentCollectionList; + } + + /** + * Small helper method that collects desired children (i.e., steps that are either traversal parents or LambdaHolders). + * All children are added to the stack such that they are also processed. + */ + private static void handleChildStepCollection(final Stack> processingStack, final List> collectionList, final Step childStep) { + if (TraversalParent.class.isAssignableFrom(childStep.getClass()) || LambdaHolder.class.isAssignableFrom(childStep.getClass())) { + collectionList.add(childStep); + } + processingStack.push(childStep); + } } \ No newline at end of file diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategyCacheInitializationTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategyCacheInitializationTest.java new file mode 100644 index 00000000000..5302f800f08 --- /dev/null +++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategyCacheInitializationTest.java @@ -0,0 +1,434 @@ +/* + * 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. + */ +package org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization; + +import org.apache.tinkerpop.gremlin.process.traversal.Step; +import org.apache.tinkerpop.gremlin.process.traversal.Traversal; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.DefaultGraphTraversal; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; +import org.apache.tinkerpop.gremlin.process.traversal.step.LambdaHolder; +import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent; +import org.apache.tinkerpop.gremlin.process.traversal.step.util.EmptyStep; +import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper; +import org.apache.tinkerpop.gremlin.util.function.Lambda; +import org.javatuples.Pair; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.where; + +/** + * Testing whether the cache for the FilterRankingStrategy is correctly initialized, + * which includes gathering/collecting the traversal parents and their children steps + * in the correct deep first manner. + */ +@RunWith(JUnit4.class) +public class FilterRankingStrategyCacheInitializationTest { + + + @Test + public void shouldCorrectlyInitializeTraversalParentCacheForNestedLambdas() { + // traversal + final Traversal traversal = __.V().as("n"). + where( + __.or( + __.select("n").hasLabel("software"), + __.select("n").map(Lambda.function("it.get().out()")) + ) + ). + select("n").by("name"); + + // expected order of traversal parents + final List> collectedTraversalParents = Arrays.asList( + __.or( + __.select("n").hasLabel("software"), + __.select("n").map(Lambda.function("it.get().out()")) + ), + __.where( + __.or( + __.select("n").hasLabel("software"), + __.select("n").map(Lambda.function("it.get().out()")) + ) + )); + + // cache entries + final List>> expectedTraversalParentCacheEntries = Arrays.asList( + new Pair<>(true, new HashSet<>()), + new Pair<>(true, new HashSet<>()), + new Pair<>(true, new HashSet<>()) // last entry for empty step/root traversal parent + ); + + doTest(traversal, Optional.of(collectedTraversalParents), Optional.of(expectedTraversalParentCacheEntries)); + } + + + @Test + public void shouldCorrectlyInitializeTraversalParentCacheForNestedWhereOrSteps() { + // traversal + final Traversal traversal = __.V().as("n"). + where( + __.or( + __.select("n").hasLabel("software"), + __.select("n").hasLabel("person") + ) + ). + select("n").by("name"); + + // expected order of traversal parents + final List> collectedTraversalParents = Arrays.asList( + __.or( + __.select("n").hasLabel("software"), + __.select("n").hasLabel("person") + ), + __.where( + __.or( + __.select("n").hasLabel("software"), + __.select("n").hasLabel("person") + ) + )); + + // cache entries + final List>> expectedTraversalParentCacheEntries = Arrays.asList( + new Pair<>(false, new HashSet<>(Collections.singletonList("n"))), + new Pair<>(false, new HashSet<>(Collections.singletonList("n"))), + new Pair<>(false, new HashSet<>(Collections.singletonList("n"))) // last entry for empty step/root traversal parent + ); + + doTest(traversal, Optional.of(collectedTraversalParents), Optional.of(expectedTraversalParentCacheEntries)); + } + + + @Test + public void shouldCorrectlyInitializeTraversalParentCacheForNestedWhereOrStepsWithDifferentLabels() { + // traversal + final Traversal traversal = __.V().as("n").out().as("m"). + where( + __.or( + __.select("n").hasLabel("software"), + __.select("m").hasLabel("person") + ) + ). + select("n").by("name"); + + // expected order of traversal parents + final List> collectedTraversalParents = Arrays.asList( + __.or( + __.select("n").hasLabel("software"), + __.select("m").hasLabel("person") + ), + __.where( + __.or( + __.select("n").hasLabel("software"), + __.select("m").hasLabel("person") + ) + )); + + // cache entries + final List>> expectedTraversalParentCacheEntries = Arrays.asList( + new Pair<>(false, new HashSet<>(Arrays.asList("n", "m"))), + new Pair<>(false, new HashSet<>(Arrays.asList("n", "m"))), + new Pair<>(false, new HashSet<>(Arrays.asList("n", "m"))) // last entry for empty step/root traversal parent + ); + + doTest(traversal, Optional.of(collectedTraversalParents), Optional.of(expectedTraversalParentCacheEntries)); + } + + + @Test + public void shouldCorrectlyInitializeTraversalParentCacheForNestedUnionOrStepsWithDifferentLabels() { + // traversal + final Traversal traversal = __.V().as("n").out().as("m"). + union( + __.or( + __.select("n").hasLabel("software"), + __.select("m").hasLabel("person") + ), + __.or( + __.select("n").hasLabel("person") + ), + __.or( + __.hasLabel("person").as("x").select("x") + ) + ); + + // expected order of traversal parents + final List> collectedTraversalParents = Arrays.asList( + __.or( + __.select("n").hasLabel("software"), + __.select("m").hasLabel("person") + ), + __.or( + __.select("n").hasLabel("person") + ), + __.or( + __.hasLabel("person").as("x").select("x") + ), + __.union( + __.or( + __.select("n").hasLabel("software"), + __.select("m").hasLabel("person") + ), + __.or( + __.select("n").hasLabel("person") + ), + __.or( + __.hasLabel("person").as("x").select("x") + ) + )); + + // cache entries + final List>> expectedTraversalParentCacheEntries = Arrays.asList( + new Pair<>(false, new HashSet<>(Arrays.asList("n", "m"))), + new Pair<>(false, new HashSet<>(Collections.singletonList("n"))), + new Pair<>(false, new HashSet<>(Collections.singletonList("x"))), + new Pair<>(false, new HashSet<>(Arrays.asList("n", "m", "x"))), + new Pair<>(false, new HashSet<>(Arrays.asList("n", "m", "x"))) // last entry for empty step/root traversal parent + ); + + doTest(traversal, Optional.of(collectedTraversalParents), Optional.of(expectedTraversalParentCacheEntries)); + } + + + @Test + public void shouldCorrectlyInitializeTraversalParentCacheForNestedWhereUnionSteps() { + // traversal + final Traversal traversal = __.V().as("n"). + where( + __.or( + __.select("n").hasLabel("software"), + __.select("n").hasLabel("person") + ) + ). + union( + __.select("n").hasLabel("software"), + __.select("n").hasLabel("person") + ). + select("n").by("name"); + + // expected order of traversal parents + final List> collectedTraversalParents = Arrays.asList( + __.or( + __.select("n").hasLabel("software"), + __.select("n").hasLabel("person") + ), + __.where( + __.or( + __.select("n").hasLabel("software"), + __.select("n").hasLabel("person") + ) + ), + __.union( + __.select("n").hasLabel("software"), + __.select("n").hasLabel("person") + ) + ); + + // cache entries + final List>> expectedTraversalParentCacheEntries = Arrays.asList( + new Pair<>(false, new HashSet<>(Collections.singletonList("n"))), + new Pair<>(false, new HashSet<>(Collections.singletonList("n"))), + new Pair<>(false, new HashSet<>(Collections.singletonList("n"))), + new Pair<>(false, new HashSet<>(Collections.singletonList("n"))) // last entry for empty step/root traversal parent + ); + + doTest(traversal, Optional.of(collectedTraversalParents), Optional.of(expectedTraversalParentCacheEntries)); + } + + + @Test + public void shouldCorrectlyInitializeTraversalParentCacheForDeeplyNestedWhereUnionSteps() { + // traversal + final Traversal traversal = __.V().as("n"). + where( + where( + __.or( + __.select("n").hasLabel("software"), + __.select("n").hasLabel("person") + ) + ). + union( + __.select("n").hasLabel("software"), + __.select("n").hasLabel("person") + ). + select("n").by("name") + ); + + // expected order of traversal parents + final List> collectedTraversalParents = Arrays.asList(new Traversal[]{ + __.or( + __.select("n").hasLabel("software"), + __.select("n").hasLabel("person") + ), + __.where( + __.or( + __.select("n").hasLabel("software"), + __.select("n").hasLabel("person") + ) + ), + __.union( + __.select("n").hasLabel("software"), + __.select("n").hasLabel("person") + ), + where( + where( + __.or( + __.select("n").hasLabel("software"), + __.select("n").hasLabel("person") + ) + ). + union( + __.select("n").hasLabel("software"), + __.select("n").hasLabel("person") + ). + select("n").by("name") + ) + }); + + // cache entries + final List>> expectedTraversalParentCacheEntries = Arrays.asList( + new Pair<>(false, new HashSet<>(Collections.singletonList("n"))), + new Pair<>(false, new HashSet<>(Collections.singletonList("n"))), + new Pair<>(false, new HashSet<>(Collections.singletonList("n"))), + new Pair<>(false, new HashSet<>(Collections.singletonList("n"))), + new Pair<>(false, new HashSet<>(Collections.singletonList("n"))) // last entry for empty step/root traversal parent + ); + + doTest(traversal, Optional.of(collectedTraversalParents), Optional.of(expectedTraversalParentCacheEntries)); + } + + @Test + public void shouldCorrectlyInitializeTraversalParentCacheForDeeplyNestedWhereUnionSteps2() { + // traversal + final Traversal traversal = __.V().as("n"). + where( + where( + where( + __.or( + __.select("n").hasLabel("software"), + __.select("n").hasLabel("person") + ) + ). + union( + __.select("n").hasLabel("software"), + __.select("n").hasLabel("person") + ). + select("n").by("name") + ) + ); + + // no cache entries/no expected order of traversal parents, so the method will just compare with old collection method + doTest(traversal, Optional.empty(), Optional.empty()); + } + + + @Test + public void shouldCorrectlyInitializeTraversalParentCacheForDeeplyNestedWhereUnionSteps3() { + // traversal + final Traversal traversal = __.V().as("n"). + where( + where( + where( + __.or( + __.select("n").hasLabel("software1"), + __.select("n").hasLabel("person1") + ) + ). + union( + __.select("n").hasLabel("software2"), + __.select("n").hasLabel("person2") + ). + select("n").by("name") + ). + union( + __.or( + __.select("n").hasLabel("abc"), + __.select("n").hasLabel("123") + ), + __.select("m").hasLabel("person") + ). + select("m").by("name") + ); + + // no cache entries/no expected order of traversal parents, so the method will just compare with old collection method + doTest(traversal, Optional.empty(), Optional.empty()); + } + + public void doTest(final Traversal traversal, + final Optional>> collectedTraversalParents, + final Optional>>> expectedTraversalParentCacheEntries) { + + List>>> traversalParentsStepsCollection = + FilterRankingStrategy.collectStepsOfAssignableClassRecursivelyFromDepthGroupedByParent(traversal.asAdmin()); + Map>> traversalParentCache = FilterRankingStrategy.getTraversalParentCache(traversalParentsStepsCollection); + + // Old method of collecting traversal parents and their children steps, which can be significantly less efficient + // when hash codes of very complex steps must be computing. Replacing LinkedHashMap with IdentityHashMap will show some failures + final Map>> traversalParentsStepsMap = + TraversalHelper.getStepsOfAssignableClassRecursivelyFromDepth(traversal.asAdmin(), TraversalParent.class, LambdaHolder.class).stream(). + collect(Collectors.groupingBy(step -> ((Step) step).getTraversal().getParent(), LinkedHashMap::new, Collectors.toList())); + // Note that the new method does not result in exactly the same list as traversal parents on the same level/depth are ordered + // differently, i.e., we cannot compare traversalParentsStepsCollection and oldTraversalParentsStepsCollection. + // The new collection method leads however also to a correct initialization of the cache. + List>>> oldTraversalParentsStepsCollection = new ArrayList<>(); + traversalParentsStepsMap.forEach((k, v) -> { + oldTraversalParentsStepsCollection.add(new Pair<>(k, v)); + }); + // computing the cache on the old way of collecting the traversal parents + Map>> oldCollectionTraversalParentCache = FilterRankingStrategy.getTraversalParentCache(oldTraversalParentsStepsCollection); + + expectedTraversalParentCacheEntries.ifPresent(pairs -> Assert.assertEquals(pairs.size(), traversalParentCache.size())); + + if (collectedTraversalParents.isPresent() && expectedTraversalParentCacheEntries.isPresent()) { + for (int i = 0; i < collectedTraversalParents.get().size(); ++i) { + final Pair>> traversalParentStepListPair = traversalParentsStepsCollection.get(i); + final TraversalParent traversalParent = traversalParentStepListPair.getValue0(); + final Traversal expectedTraversalParent = collectedTraversalParents.get().get(i); + Assert.assertEquals(((DefaultGraphTraversal) expectedTraversalParent).getSteps().get(0), traversalParent); + + final Pair> expectedCacheEntry = expectedTraversalParentCacheEntries.get().get(i); + final Pair> cacheEntry = traversalParentCache.get(traversalParent); + Assert.assertEquals(expectedCacheEntry, cacheEntry); + } + + Assert.assertEquals(collectedTraversalParents.get().size() + 1, traversalParentsStepsCollection.size()); + Assert.assertEquals(traversalParentsStepsCollection.get(collectedTraversalParents.get().size()).getValue0(), EmptyStep.instance()); + final Pair> expectedCacheEntry = expectedTraversalParentCacheEntries.get().get(collectedTraversalParents.get().size()); + final Pair> cacheEntry = traversalParentCache.get(EmptyStep.instance()); + Assert.assertEquals(expectedCacheEntry, cacheEntry); + } + + Assert.assertEquals(oldCollectionTraversalParentCache, traversalParentCache); + } + +} + + diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategyTest.java index 5ebc52c0234..26ac4dc433b 100644 --- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategyTest.java +++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategyTest.java @@ -27,6 +27,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.translator.GroovyTranslator; import org.apache.tinkerpop.gremlin.process.traversal.util.DefaultTraversalStrategies; import org.apache.tinkerpop.gremlin.structure.Graph; +import org.apache.tinkerpop.gremlin.util.function.Lambda; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -85,44 +86,148 @@ public void doTest() { @Parameterized.Parameters(name = "{0}") public static Iterable generateTestParameters() { final Predicate testP = t -> true; + return Arrays.asList(new Object[][]{ - {__.dedup().order(), __.dedup().order(), Collections.emptyList()}, - {__.has("name", "marko").as("a").out().as("b").has("age", 32).where("a", neq("b")).as("c").out(), __.has("name", "marko").as("a").out().has("age", 32).as("b").where("a", neq("b")).as("c").out(), Collections.emptyList()}, - {__.has("name", "marko").as("a").out().has("age", 32).as("b").where("a", neq("b")), __.has("name", "marko").as("a").out().has("age", 32).as("b").where("a", neq("b")), Collections.emptyList()}, - {__.has("name", "marko").has("age", 32).dedup().has("name", "bob").as("a"), __.has("name", "marko").has("age", 32).has("name", "bob").dedup().as("a"), Collections.singletonList(InlineFilterStrategy.instance())}, - {__.has("name", "marko").dedup().as("a").has("age", 32).has("name", "bob").as("b"), __.has("name", "marko").has("age", 32).has("name", "bob").dedup().as("b", "a"), Collections.singletonList(InlineFilterStrategy.instance())}, - {__.where("b", eq("c")).as("a").dedup("a").has("name", "marko"), __.has("name", "marko").where("b", eq("c")).as("a").dedup("a"), Collections.emptyList()}, - {__.where("b", eq("c")).has("name", "bob").as("a").dedup("a").has("name", "marko"), __.has("name", "bob").has("name", "marko").where("b", eq("c")).as("a").dedup("a"), Collections.singletonList(InlineFilterStrategy.instance())}, - {__.has("name", "marko").as("a").out().has("name", "bob").dedup().as("b").where(__.as("a").out().as("b")), __.has("name", "marko").as("a").out().has("name", "bob").dedup().as("b").where(__.as("a").out().as("b")), Collections.singletonList(InlineFilterStrategy.instance())}, - {__.has("name", "marko").as("a").out().has("name", "bob").as("b").dedup().where(__.as("a").out().as("b")), __.has("name", "marko").as("a").out().has("name", "bob").dedup().as("b").where(__.as("a").out().as("b")), Collections.singletonList(InlineFilterStrategy.instance())}, - {__.has("name", "marko").as("a").out().has("name", "bob").dedup().as("c").where(__.as("a").out().as("b")), __.has("name", "marko").as("a").out().has("name", "bob").where(__.as("a").out().as("b")).dedup().as("c"), Collections.singletonList(InlineFilterStrategy.instance())}, - {__.order().dedup(), __.dedup().order(), Collections.emptyList()}, - {__.order().filter(testP).dedup(), __.order().filter(testP).dedup(), Collections.emptyList()}, - {__.order().as("a").dedup(), __.dedup().order().as("a"), Collections.emptyList()}, - {__.order().as("a").dedup("a"), __.order().as("a").dedup("a"), Collections.emptyList()}, - {__.order().as("a").dedup("a").has("name", "marko"), __.has("name", "marko").as("a").dedup("a").order(), Collections.emptyList()}, - {__.order().as("a").dedup("a").has("name", "marko").out(), __.has("name", "marko").as("a").dedup("a").order().out(), Collections.emptyList()}, - {__.order().as("a").dedup("a").has("name", "marko").where("a", eq("b")).out(), __.has("name", "marko").as("a").where("a", eq("b")).dedup("a").order().out(), Collections.emptyList()}, - {__.identity().order().dedup(), __.dedup().order(), Collections.singletonList(IdentityRemovalStrategy.instance())}, - {__.order().identity().dedup(), __.dedup().order(), Collections.singletonList(IdentityRemovalStrategy.instance())}, - {__.order().out().dedup(), __.order().out().dedup(), Collections.emptyList()}, - {has("value", 0).filter(out()).dedup(), has("value", 0).filter(out()).dedup(), Collections.emptyList()}, - {__.dedup().has("value", 0).or(not(has("age")), has("age", 10)).has("value", 1), __.has("value", 0).has("value", 1).or(not(has("age")), has("age", 10)).dedup(), Collections.singletonList(InlineFilterStrategy.instance())}, - {__.dedup().filter(out()).has("value", 0), has("value", 0).filter(out()).dedup(), Collections.emptyList()}, - {filter(out()).dedup().has("value", 0), has("value", 0).filter(out()).dedup(), Collections.emptyList()}, - {__.as("a").out().has("age").where(P.eq("a")), __.as("a").out().where(P.eq("a")).has("age"), Collections.emptyList()}, - {__.as("a").out().has("age").where(P.eq("a")).by("age"), __.as("a").out().has("age").where(P.eq("a")).by("age"), Collections.emptyList()}, - {__.as("a").out().and(has("age"), has("name")).where(P.eq("a")).by("age"), __.as("a").out().and(has("age"), has("name")).where(P.eq("a")).by("age"), Collections.emptyList()}, - {__.as("a").out().and(has("age"), has("name")).where(P.eq("a")), __.as("a").out().where(P.eq("a")).and(has("age"), has("name")), Collections.emptyList()}, - {__.as("a").out().and(has("age"), has("name")).where(P.eq("a")).by("age"), __.as("a").out().has("age").has("name").where(P.eq("a")).by("age"), Collections.singletonList(InlineFilterStrategy.instance())}, - {__.as("a").out().and(has("age"), has("name")).where(P.eq("a")), __.as("a").out().where(P.eq("a")).has("age").has("name"), Collections.singletonList(InlineFilterStrategy.instance())}, - {__.as("a").out().and(has("age"), has("name")).filter(__.where(P.eq("a"))), __.as("a").out().where(P.eq("a")).has("age").has("name"), Collections.singletonList(InlineFilterStrategy.instance())}, - {__.as("a").out().and(has("age"), has("name")).filter(__.where(P.eq("a")).by("age")), __.as("a").out().has("age").has("name").where(P.eq("a")).by("age"), Collections.singletonList(InlineFilterStrategy.instance())}, - {has("value", 0).filter(out()).dedup(), has("value", 0).filter(out()).dedup(), Collections.emptyList()}, - {has("value", 0).or(has("name"), has("age")).has("value", 1).dedup(), has("value", 0).has("value", 1).or(has("name"), has("age")).dedup(), Collections.singletonList(InlineFilterStrategy.instance())}, - {has("value", 0).or(out(), in()).as(Graph.Hidden.hide("x")).has("value", 1).dedup(), has("value", 0).has("value", 1).or(outE(), inE()).dedup(), TraversalStrategies.GlobalCache.getStrategies(Graph.class).toList()}, - {has("value", 0).and(has("age"), has("name", "marko")).is(10), __.is(10).has("value", 0).has("age").has("name", "marko"), Collections.singletonList(InlineFilterStrategy.instance())}, - {has("value", 0).filter(or(not(has("age")), has("age", 1))).has("value", 1).dedup(), has("value", 0).has("value", 1).or(not(filter(properties("age"))), has("age", 1)).dedup(), TraversalStrategies.GlobalCache.getStrategies(Graph.class).toList()}, + {__.has("name", "marko").as("a").out().as("b").has("age", 32).where("a", neq("b")).as("c").out(), + __.has("name", "marko").as("a").out().has("age", 32).as("b").where("a", neq("b")).as("c").out(), + Collections.emptyList()}, + + {__.V().as("n").where(__.or(__.select("n").hasLabel("software"),__.select("n").hasLabel("person"))).select("n").by("name"), + __.V().as("n").where(__.or(__.select("n").hasLabel("software"),__.select("n").hasLabel("person"))).select("n").by("name"), + Collections.emptyList()}, + + {__.V().as("n").where(__.where(__.where(__.where(__.or(__.select("n").hasLabel("software"),__.select("n").hasLabel("person")))))).select("n").by("name"), + __.V().as("n").where(__.where(__.where(__.where(__.or(__.select("n").hasLabel("software"),__.select("n").hasLabel("person")))))).select("n").by("name"), + Collections.emptyList()}, + + {__.V().as("n").where(__.where(__.where(__.where(__.or(__.select("n").hasLabel("software"),__.select("n").hasLabel("person")))))).has("test", "val").select("n").by("name"), + __.V().has("test", "val").as("n").where(__.where(__.where(__.where(__.or(__.select("n").hasLabel("software"),__.select("n").hasLabel("person")))))).select("n").by("name"), + Collections.emptyList()}, + + {__.V().as("n").out().where(__.or(__.hasLabel("out-dest-label1").select("n").hasLabel("software"),__.hasLabel("out-dest-label2").select("n").hasLabel("person"))).select("n").by("name"), + __.V().as("n").out().where(__.or(__.hasLabel("out-dest-label1").select("n").hasLabel("software"),__.hasLabel("out-dest-label2").select("n").hasLabel("person"))).select("n").by("name"), + Collections.emptyList()}, + + // some lambda tests, where reordering over lambdas should not happen + {__.order().map(Lambda.function("it.get().out()")).dedup(), + __.order().map(Lambda.function("it.get().out()")).dedup(), + Collections.emptyList()}, + + {__.order().filter(__.map(Lambda.function("it.get().out()"))).dedup(), + __.order().filter(__.map(Lambda.function("it.get().out()"))).dedup(), + Collections.emptyList()}, + + {__.dedup().order(), + __.dedup().order(), + Collections.emptyList()}, + {__.has("name", "marko").as("a").out().as("b").has("age", 32).where("a", neq("b")).as("c").out(), + __.has("name", "marko").as("a").out().has("age", 32).as("b").where("a", neq("b")).as("c").out(), + Collections.emptyList()}, + {__.has("name", "marko").as("a").out().has("age", 32).as("b").where("a", neq("b")), + __.has("name", "marko").as("a").out().has("age", 32).as("b").where("a", neq("b")), + Collections.emptyList()}, + {__.has("name", "marko").has("age", 32).dedup().has("name", "bob").as("a"), + __.has("name", "marko").has("age", 32).has("name", "bob").dedup().as("a"), + Collections.singletonList(InlineFilterStrategy.instance())}, + {__.has("name", "marko").dedup().as("a").has("age", 32).has("name", "bob").as("b"), + __.has("name", "marko").has("age", 32).has("name", "bob").dedup().as("b", "a"), + Collections.singletonList(InlineFilterStrategy.instance())}, + {__.where("b", eq("c")).as("a").dedup("a").has("name", "marko"), + __.has("name", "marko").where("b", eq("c")).as("a").dedup("a"), + Collections.emptyList()}, + {__.where("b", eq("c")).has("name", "bob").as("a").dedup("a").has("name", "marko"), + __.has("name", "bob").has("name", "marko").where("b", eq("c")).as("a").dedup("a"), + Collections.singletonList(InlineFilterStrategy.instance())}, + {__.has("name", "marko").as("a").out().has("name", "bob").dedup().as("b").where(__.as("a").out().as("b")), + __.has("name", "marko").as("a").out().has("name", "bob").dedup().as("b").where(__.as("a").out().as("b")), + Collections.singletonList(InlineFilterStrategy.instance())}, + {__.has("name", "marko").as("a").out().has("name", "bob").as("b").dedup().where(__.as("a").out().as("b")), + __.has("name", "marko").as("a").out().has("name", "bob").dedup().as("b").where(__.as("a").out().as("b")), + Collections.singletonList(InlineFilterStrategy.instance())}, + {__.has("name", "marko").as("a").out().has("name", "bob").dedup().as("c").where(__.as("a").out().as("b")), + __.has("name", "marko").as("a").out().has("name", "bob").where(__.as("a").out().as("b")).dedup().as("c"), + Collections.singletonList(InlineFilterStrategy.instance())}, + {__.order().dedup(), + __.dedup().order(), + Collections.emptyList()}, + {__.order().filter(testP).dedup(), + __.order().filter(testP).dedup(), + Collections.emptyList()}, + {__.order().as("a").dedup(), + __.dedup().order().as("a"), + Collections.emptyList()}, + {__.order().as("a").dedup("a"), + __.order().as("a").dedup("a"), + Collections.emptyList()}, + {__.order().as("a").dedup("a").has("name", "marko"), + __.has("name", "marko").as("a").dedup("a").order(), + Collections.emptyList()}, + {__.order().as("a").dedup("a").has("name", "marko").out(), + __.has("name", "marko").as("a").dedup("a").order().out(), + Collections.emptyList()}, + {__.order().as("a").dedup("a").has("name", "marko").where("a", eq("b")).out(), + __.has("name", "marko").as("a").where("a", eq("b")).dedup("a").order().out(), + Collections.emptyList()}, + {__.identity().order().dedup(), + __.dedup().order(), + Collections.singletonList(IdentityRemovalStrategy.instance())}, + {__.order().identity().dedup(), + __.dedup().order(), + Collections.singletonList(IdentityRemovalStrategy.instance())}, + {__.order().out().dedup(), + __.order().out().dedup(), + Collections.emptyList()}, + {has("value", 0).filter(out()).dedup(), + has("value", 0).filter(out()).dedup(), + Collections.emptyList()}, + {__.dedup().has("value", 0).or(not(has("age")), has("age", 10)).has("value", 1), + __.has("value", 0).has("value", 1).or(not(has("age")), has("age", 10)).dedup(), + Collections.singletonList(InlineFilterStrategy.instance())}, + {__.dedup().filter(out()).has("value", 0), + has("value", 0).filter(out()).dedup(), + Collections.emptyList()}, + {filter(out()).dedup().has("value", 0), + has("value", 0).filter(out()).dedup(), + Collections.emptyList()}, + {__.as("a").out().has("age").where(P.eq("a")), + __.as("a").out().where(P.eq("a")).has("age"), + Collections.emptyList()}, + {__.as("a").out().has("age").where(P.eq("a")).by("age"), + __.as("a").out().has("age").where(P.eq("a")).by("age"), + Collections.emptyList()}, + {__.as("a").out().and(has("age"), has("name")).where(P.eq("a")).by("age"), + __.as("a").out().and(has("age"), has("name")).where(P.eq("a")).by("age"), + Collections.emptyList()}, + {__.as("a").out().and(has("age"), has("name")).where(P.eq("a")), + __.as("a").out().where(P.eq("a")).and(has("age"), has("name")), + Collections.emptyList()}, + {__.as("a").out().and(has("age"), has("name")).where(P.eq("a")).by("age"), + __.as("a").out().has("age").has("name").where(P.eq("a")).by("age"), + Collections.singletonList(InlineFilterStrategy.instance())}, + {__.as("a").out().and(has("age"), has("name")).where(P.eq("a")), + __.as("a").out().where(P.eq("a")).has("age").has("name"), + Collections.singletonList(InlineFilterStrategy.instance())}, + {__.as("a").out().and(has("age"), has("name")).filter(__.where(P.eq("a"))), + __.as("a").out().where(P.eq("a")).has("age").has("name"), + Collections.singletonList(InlineFilterStrategy.instance())}, + {__.as("a").out().and(has("age"), has("name")).filter(__.where(P.eq("a")).by("age")), + __.as("a").out().has("age").has("name").where(P.eq("a")).by("age"), + Collections.singletonList(InlineFilterStrategy.instance())}, + {has("value", 0).filter(out()).dedup(), + has("value", 0).filter(out()).dedup(), + Collections.emptyList()}, + {has("value", 0).or(has("name"), has("age")).has("value", 1).dedup(), + has("value", 0).has("value", 1).or(has("name"), has("age")).dedup(), + Collections.singletonList(InlineFilterStrategy.instance())}, + {has("value", 0).or(out(), in()).as(Graph.Hidden.hide("x")).has("value", 1).dedup(), + has("value", 0).has("value", 1).or(outE(), inE()).dedup(), + TraversalStrategies.GlobalCache.getStrategies(Graph.class).toList()}, + {has("value", 0).and(has("age"), has("name", "marko")).is(10), + __.is(10).has("value", 0).has("age").has("name", "marko"), + Collections.singletonList(InlineFilterStrategy.instance())}, + {has("value", 0).filter(or(not(has("age")), has("age", 1))).has("value", 1).dedup(), + has("value", 0).has("value", 1).or(not(filter(properties("age"))), has("age", 1)).dedup(), + TraversalStrategies.GlobalCache.getStrategies(Graph.class).toList()}, }); } } From aa90f77595608a24a79c2547a96d0d1b651e892c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Mar 2024 14:32:57 +0000 Subject: [PATCH 14/18] Bump Polly from 8.3.0 to 8.3.1 in /gremlin-dotnet Bumps [Polly](https://github.com/App-vNext/Polly) from 8.3.0 to 8.3.1. - [Release notes](https://github.com/App-vNext/Polly/releases) - [Changelog](https://github.com/App-vNext/Polly/blob/main/CHANGELOG.md) - [Commits](https://github.com/App-vNext/Polly/compare/8.3.0...8.3.1) --- updated-dependencies: - dependency-name: Polly dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gremlin-dotnet/src/Gremlin.Net/Gremlin.Net.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gremlin-dotnet/src/Gremlin.Net/Gremlin.Net.csproj b/gremlin-dotnet/src/Gremlin.Net/Gremlin.Net.csproj index ee159220f89..336763f2847 100644 --- a/gremlin-dotnet/src/Gremlin.Net/Gremlin.Net.csproj +++ b/gremlin-dotnet/src/Gremlin.Net/Gremlin.Net.csproj @@ -74,7 +74,7 @@ NOTE that versions suffixed with "-rc" are considered release candidates (i.e. p - + From f5d8225ca8ca03c1670a88ba197b31939bedab41 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Mar 2024 15:02:16 +0000 Subject: [PATCH 15/18] Bump System.Text.Json from 8.0.2 to 8.0.3 in /gremlin-dotnet Bumps [System.Text.Json](https://github.com/dotnet/runtime) from 8.0.2 to 8.0.3. - [Release notes](https://github.com/dotnet/runtime/releases) - [Commits](https://github.com/dotnet/runtime/commits) --- updated-dependencies: - dependency-name: System.Text.Json dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gremlin-dotnet/src/Gremlin.Net/Gremlin.Net.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gremlin-dotnet/src/Gremlin.Net/Gremlin.Net.csproj b/gremlin-dotnet/src/Gremlin.Net/Gremlin.Net.csproj index 336763f2847..bc09b4f127e 100644 --- a/gremlin-dotnet/src/Gremlin.Net/Gremlin.Net.csproj +++ b/gremlin-dotnet/src/Gremlin.Net/Gremlin.Net.csproj @@ -73,7 +73,7 @@ NOTE that versions suffixed with "-rc" are considered release candidates (i.e. p - + From 196d61920cee68e54ef488e26ddbeb44a6eeb4a8 Mon Sep 17 00:00:00 2001 From: Stephen Mallette Date: Thu, 14 Mar 2024 07:33:21 -0400 Subject: [PATCH 16/18] Added test for select() semantics CTR --- .../Gherkin/Gremlin.cs | 1 + gremlin-go/driver/cucumber/gremlin.go | 1 + .../gremlin-javascript/test/cucumber/gremlin.js | 1 + gremlin-python/src/main/python/radish/gremlin.py | 1 + .../gremlin/test/features/map/Select.feature | 16 ++++++++++++++++ 5 files changed, 20 insertions(+) diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs index c44e000bb5a..9fc7e76b511 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs @@ -888,6 +888,7 @@ private static IDictionary, ITraversal>> {(g,p) =>g.WithStrategies(new ProductiveByStrategy(productiveKeys: new List {})).V().As("a").Select("a").By("age")}}, {"g_withSideEffectXk_nullX_injectXxX_selectXkX", new List, ITraversal>> {(g,p) =>g.WithSideEffect("k",null).Inject("x").Select("k")}}, {"g_V_out_in_selectXall_a_a_aX_byXunfold_name_foldX", new List, ITraversal>> {(g,p) =>g.AddV("A").Property("name","a1").As("a1").AddV("A").Property("name","a2").As("a2").AddV("A").Property("name","a3").As("a3").AddV("B").Property("name","b1").As("b1").AddV("B").Property("name","b2").As("b2").AddV("B").Property("name","b3").As("b3").AddE("ab").From("a1").To("b1").AddE("ab").From("a2").To("b2").AddE("ab").From("a3").To("b3"), (g,p) =>g.V().As("a").Out().As("a").In().As("a").Select(Pop.All,"a","a","a").By(__.Unfold().Values("name").Fold())}}, + {"g_V_asXlabelX_aggregateXlocal_xX_selectXxX_selectXlabelX", new List, ITraversal>> {(g,p) =>g.V().As("label").Aggregate(Scope.Local,"x").Select("x").Select("label")}}, {"g_V_shortestPath", new List, ITraversal>> {(g,p) =>g.V().Identity().ShortestPath()}}, {"g_V_both_dedup_shortestPath", new List, ITraversal>> {(g,p) =>g.V().Both().Dedup().ShortestPath()}}, {"g_V_shortestPath_edgesIncluded", new List, ITraversal>> {(g,p) =>g.V().Identity().ShortestPath().With("~tinkerpop.shortestPath.includeEdges")}}, diff --git a/gremlin-go/driver/cucumber/gremlin.go b/gremlin-go/driver/cucumber/gremlin.go index babc62777f6..d1f6fc14932 100644 --- a/gremlin-go/driver/cucumber/gremlin.go +++ b/gremlin-go/driver/cucumber/gremlin.go @@ -859,6 +859,7 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[ "g_withStrategiesXProductiveByStrategyX_V_asXaX_selectXaX_byXageX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.WithStrategies(gremlingo.ProductiveByStrategy(gremlingo.ProductiveByStrategyConfig{ProductiveKeys: []string{}})).V().As("a").Select("a").By("age")}}, "g_withSideEffectXk_nullX_injectXxX_selectXkX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.WithSideEffect("k", nil).Inject("x").Select("k")}}, "g_V_out_in_selectXall_a_a_aX_byXunfold_name_foldX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("A").Property("name", "a1").As("a1").AddV("A").Property("name", "a2").As("a2").AddV("A").Property("name", "a3").As("a3").AddV("B").Property("name", "b1").As("b1").AddV("B").Property("name", "b2").As("b2").AddV("B").Property("name", "b3").As("b3").AddE("ab").From("a1").To("b1").AddE("ab").From("a2").To("b2").AddE("ab").From("a3").To("b3")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().As("a").Out().As("a").In().As("a").Select(gremlingo.Pop.All, "a", "a", "a").By(gremlingo.T__.Unfold().Values("name").Fold())}}, + "g_V_asXlabelX_aggregateXlocal_xX_selectXxX_selectXlabelX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().As("label").Aggregate(gremlingo.Scope.Local, "x").Select("x").Select("label")}}, "g_V_shortestPath": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Identity().ShortestPath()}}, "g_V_both_dedup_shortestPath": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Both().Dedup().ShortestPath()}}, "g_V_shortestPath_edgesIncluded": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Identity().ShortestPath().With("~tinkerpop.shortestPath.includeEdges")}}, 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 55e070d495c..479575d5fc8 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 @@ -878,6 +878,7 @@ const gremlins = { g_withStrategiesXProductiveByStrategyX_V_asXaX_selectXaX_byXageX: [function({g}) { return g.withStrategies(new ProductiveByStrategy({productiveKeys:[]})).V().as("a").select("a").by("age") }], g_withSideEffectXk_nullX_injectXxX_selectXkX: [function({g}) { return g.withSideEffect("k",null).inject("x").select("k") }], g_V_out_in_selectXall_a_a_aX_byXunfold_name_foldX: [function({g}) { return g.addV("A").property("name","a1").as("a1").addV("A").property("name","a2").as("a2").addV("A").property("name","a3").as("a3").addV("B").property("name","b1").as("b1").addV("B").property("name","b2").as("b2").addV("B").property("name","b3").as("b3").addE("ab").from_("a1").to("b1").addE("ab").from_("a2").to("b2").addE("ab").from_("a3").to("b3") }, function({g}) { return g.V().as("a").out().as("a").in_().as("a").select(Pop.all,"a","a","a").by(__.unfold().values("name").fold()) }], + g_V_asXlabelX_aggregateXlocal_xX_selectXxX_selectXlabelX: [function({g}) { return g.V().as("label").aggregate(Scope.local,"x").select("x").select("label") }], g_V_shortestPath: [function({g}) { return g.V().identity().shortestPath() }], g_V_both_dedup_shortestPath: [function({g}) { return g.V().both().dedup().shortestPath() }], g_V_shortestPath_edgesIncluded: [function({g}) { return g.V().identity().shortestPath().with_("~tinkerpop.shortestPath.includeEdges") }], diff --git a/gremlin-python/src/main/python/radish/gremlin.py b/gremlin-python/src/main/python/radish/gremlin.py index 25fe62acd36..448114d306a 100644 --- a/gremlin-python/src/main/python/radish/gremlin.py +++ b/gremlin-python/src/main/python/radish/gremlin.py @@ -860,6 +860,7 @@ 'g_withStrategiesXProductiveByStrategyX_V_asXaX_selectXaX_byXageX': [(lambda g:g.withStrategies(*[TraversalStrategy('ProductiveByStrategy',{'productiveKeys':[],'strategy':'org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.ProductiveByStrategy'}, 'org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.ProductiveByStrategy')]).V().as_('a').select('a').by('age'))], 'g_withSideEffectXk_nullX_injectXxX_selectXkX': [(lambda g:g.withSideEffect('k',None).inject('x').select('k'))], 'g_V_out_in_selectXall_a_a_aX_byXunfold_name_foldX': [(lambda g:g.addV('A').property('name','a1').as_('a1').addV('A').property('name','a2').as_('a2').addV('A').property('name','a3').as_('a3').addV('B').property('name','b1').as_('b1').addV('B').property('name','b2').as_('b2').addV('B').property('name','b3').as_('b3').addE('ab').from_('a1').to('b1').addE('ab').from_('a2').to('b2').addE('ab').from_('a3').to('b3')), (lambda g:g.V().as_('a').out().as_('a').in_().as_('a').select(Pop.all_,'a','a','a').by(__.unfold().name.fold()))], + 'g_V_asXlabelX_aggregateXlocal_xX_selectXxX_selectXlabelX': [(lambda g:g.V().as_('label').aggregate(Scope.local,'x').select('x').select('label'))], 'g_V_shortestPath': [(lambda g:g.V().identity().shortestPath())], 'g_V_both_dedup_shortestPath': [(lambda g:g.V().both().dedup().shortestPath())], 'g_V_shortestPath_edgesIncluded': [(lambda g:g.V().identity().shortestPath().with_('~tinkerpop.shortestPath.includeEdges'))], diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Select.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Select.feature index ef8d815ed9a..b2f8ef8dc53 100644 --- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Select.feature +++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Select.feature @@ -901,3 +901,19 @@ Feature: Step - select() | m[{"a":["a1","b1","a1"]}] | | m[{"a":["a2","b2","a2"]}] | | m[{"a":["a3","b3","a3"]}] | + + Scenario: g_V_asXlabelX_aggregateXlocal_xX_selectXxX_selectXlabelX + Given the modern graph + And the traversal of + """ + g.V().as("label").aggregate(local,"x").select("x").select("label") + """ + When iterated to list + Then the result should be unordered + | result | + | v[marko] | + | v[vadas] | + | v[lop] | + | v[josh] | + | v[ripple] | + | v[peter] | \ No newline at end of file From f7c64dabf07f6d5008bf457690b85b6a86d2c924 Mon Sep 17 00:00:00 2001 From: Stephen Mallette Date: Fri, 22 Mar 2024 09:03:26 -0400 Subject: [PATCH 17/18] TINKERPOP-3056 Follow-on fix for mid-traversal mergeE/V Prevents child traversals to option() from having an Element in it so that you can't mistakenly update the wrong thing CTR --- CHANGELOG.asciidoc | 6 +- docs/src/reference/the-traversal.asciidoc | 14 ++++ .../traversal/step/map/MergeEdgeStep.java | 8 +- .../process/traversal/step/map/MergeStep.java | 35 +++++++++ .../traversal/step/map/MergeVertexStep.java | 7 +- .../Gherkin/Gremlin.cs | 8 +- gremlin-go/driver/cucumber/gremlin.go | 8 +- .../test/cucumber/gremlin.js | 8 +- .../src/main/python/radish/gremlin.py | 8 +- .../test/features/map/MergeEdge.feature | 77 +++++++++++++++++-- .../test/features/map/MergeVertex.feature | 46 ++++++++++- 11 files changed, 201 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index 27fde68afd7..b813d15ae77 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -29,13 +29,13 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima * Fixed bug in bytecode translation of `g.tx().commit()` and `g.tx().rollback()` in all languages. * Improved error message from `JavaTranslator` by including exception source. * Added missing `short` serialization (`gx:Int16`) to GraphSONV2 and GraphSONV3 in `gremlin-python`. -* Added tests for error handling for GLV's if tx.commit() is called remotely for graphs without transactions support. +* Added tests for error handling for GLV's if `tx.commit()`` is called remotely for graphs without transactions support. * Introduced multi-architecture AMD64/ARM64 docker images for gremlin-console. * Fixed bug in `JavaTranslator` where `has(String, null)` could call `has(String, Traversal)` to generate an error. * Fixed issue where server errors weren't being properly parsed when sending bytecode over HTTP. -* Improved bulkset contains check for elements if all elements in bulkset are of the same type. +* Improved `Bulkset` contains check for elements if all elements in `Bulkset` are of the same type. * Fixed bug in `EarlyLimitStrategy` which was too aggressive when promoting `limit()` before `map()`. -* Fixed bug in mid-traversal `mergeE()` where mutations in `sideEffect()` were being applied to the current traverser rather than a `onMatch` edge. +* Prevented mid-traversal `mergeE()` and `mergeV()` from operating on an incoming `Traverser` that contains an `Element`. * Improved performance of the application of `FilterRankingStrategy` for large traversals with deeply nested traversals by improving the cache operation. [[release-3-6-6]] diff --git a/docs/src/reference/the-traversal.asciidoc b/docs/src/reference/the-traversal.asciidoc index ef1192d0ad2..ca89014eef2 100644 --- a/docs/src/reference/the-traversal.asciidoc +++ b/docs/src/reference/the-traversal.asciidoc @@ -2515,6 +2515,13 @@ g.E().elementMap() <1> Create three dogs. <2> Stream the edge maps into `mergeE()` steps. +WARNING: There is a bit of an inconsistency present when `mergeE()` is used as a start step versus when it is used +mid-traversal. As a start step, `mergeE()` will promote the currently created or matched `Edge` to the child traversal, +allowing you to directly update it like `option(onMatch, property('k', 'v').constant([:]))`. However, when `mergeE()` is +used mid-traversal, the `Edge` is not promoted to the child traversal and the incoming traverser is used instead. Such +behavior is essentially blocked to prevent accidental misuse and will result in an exception at execution time that will +have a message like, "The incoming traverser for MergeEdgeStep cannot be an Element". + The `mergeE` step can be combined with the `mergeV` step (or any other step producing a `Vertex`) using the `Merge.outV` and `Merge.inV` option modulators. These options can be used to "late-bind" the `OUT` and `IN` vertices in the main merge argument and in the `onCreate` argument: @@ -2732,6 +2739,13 @@ g.V(400).valueMap().with(WithOptions.tokens) <5> <4> Pixel exists now, so we will take this option. <5> The `updated` property has now been added. +WARNING: There is a bit of an inconsistency present when `mergeV()` is used as a start step versus when it is used +mid-traversal. As a start step, `mergeV()` will promote the currently created or matched `Vertex` to the child +traversal, allowing you to directly update it like `option(onMatch, property('k', 'v').constant([:]))`. However, when +`mergeV()` is used mid-traversal, the `Vertex` is not promoted to the child traversal and the incoming traverser is used +instead. Such behavior is essentially blocked to prevent accidental misuse and will result in an exception at execution +time that will have a message like, "The incoming traverser for MergeVertexStep cannot be an Element". + *Additional References* link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#mergeV()++[`mergeV()`], diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeEdgeStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeEdgeStep.java index 761426efe34..1010ca5fbaa 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeEdgeStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeEdgeStep.java @@ -34,6 +34,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.Traverser; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; import org.apache.tinkerpop.gremlin.process.traversal.lambda.ConstantTraversal; +import org.apache.tinkerpop.gremlin.process.traversal.step.filter.LambdaFilterStep; import org.apache.tinkerpop.gremlin.process.traversal.step.util.event.Event; import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.EventStrategy; import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil; @@ -274,8 +275,11 @@ protected Iterator flatMap(final Traverser.Admin traverser) { edges = IteratorUtils.peek(edges, e -> { // override current traverser with the matched Edge so that the option() traversal can operate - // on it properly - traverser.set((S) e); + // on it properly. this should only work this way for the start step form to retain the original + // behavior for 3.6.0 where you might do g.inject(Map).mergeE() and want that Map to pass through. + // in 4.x this will be rectified such that the edge will always be promoted and you will be forced + // to select() the map if you did want the behavior. + if (isStart) traverser.set((S) e); // assume good input from GraphTraversal - folks might drop in a T here even though it is immutable final Map onMatchMap = materializeMap(traverser, onMatchTraversal); diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeStep.java index c9a1cf1b0d3..d1166c98ce8 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeStep.java @@ -46,6 +46,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper; import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil; import org.apache.tinkerpop.gremlin.structure.Direction; +import org.apache.tinkerpop.gremlin.structure.Element; import org.apache.tinkerpop.gremlin.structure.Graph; import org.apache.tinkerpop.gremlin.structure.T; import org.apache.tinkerpop.gremlin.structure.Vertex; @@ -142,6 +143,14 @@ public void addChildOption(final Merge token, final Traversal.Admin traver if (token == Merge.onCreate) { this.onCreateTraversal = this.integrateChild(traversalOption); } else if (token == Merge.onMatch) { + // add a guard rail to ensure that the incoming object is not an Element. this will prevent + // a possibly inadvertent mutation of the graph if you did something like g.V().mergeE(). for + // 3.x we won't allow this behavior at all but in 4.x we will make it consistent like it will + // be in 4.x + if (!isStart && traversalOption != null && !(traversalOption instanceof ConstantTraversal)) { + traversalOption.addStep(0, new GuardRailStep<>(traversalOption, getClass().getSimpleName())); + } + this.onMatchTraversal = this.integrateChild(traversalOption); } else { throw new UnsupportedOperationException(String.format("Option %s for Merge is not supported", token.name())); @@ -374,4 +383,30 @@ protected GraphTraversal searchVerticesPropertyConstraints(GraphTraversal t, fin protected abstract Set getAllowedTokens(); + /** + * Guard rail to ensure that the incoming object is not an {@link Element}. + */ + public static class GuardRailStep extends ScalarMapStep { + private final String stepType; + + public GuardRailStep(final Traversal.Admin traversal, final String stepType) { + super(traversal); + this.stepType = stepType; + } + + @Override + protected E map(final Traverser.Admin t) { + if (t.get() instanceof Element) { + throw new IllegalArgumentException( + String.format("The incoming traverser for %s cannot be an Element", stepType)); + } + return (E) t.get(); + } + + @Override + public String toString() { + return StringFactory.stepString(this); + } + } + } 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 a976775a994..132adf3e7c8 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 @@ -93,8 +93,11 @@ protected Iterator flatMap(final Traverser.Admin traverser) { // attach the onMatch properties vertices = IteratorUtils.peek(vertices, v -> { - // if this was a start step the traverser is initialized with Boolean/false, so override that with - // the matched Vertex so that the option() traversal can operate on it properly + // override current traverser with the matched Edge so that the option() traversal can operate + // on it properly. this should only work this way for the start step form to retain the original + // behavior for 3.6.0 where you might do g.inject(Map).mergeV() and want that Map to pass through. + // in 4.x this will be rectified such that the edge will always be promoted and you will be forced + // to select() the map if you did want the behavior. if (isStart) traverser.set((S) v); // assume good input from GraphTraversal - folks might drop in a T here even though it is immutable diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs index 9fc7e76b511..bf7e01c810a 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs @@ -689,8 +689,10 @@ private static IDictionary, ITraversal>> {(g,p) =>g.MergeV((IDictionary) p["xx1"]).As("outV").MergeV((IDictionary) p["xx2"]).As("inV").MergeE((IDictionary) p["xx3"]).Option(Merge.OutV, (ITraversal) __.Select("outV")).Option(Merge.InV, (ITraversal) __.Select("inV")), (g,p) =>g.V(), (g,p) =>g.E(), (g,p) =>g.V().Has("name","marko").Out("knows").Has("name","vadas")}}, {"g_mergeV_mergeE_combination_existing_vertices", new List, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").AddV("person").Property("name","vadas"), (g,p) =>g.MergeV((IDictionary) p["xx1"]).As("outV").MergeV((IDictionary) p["xx2"]).As("inV").MergeE((IDictionary) p["xx3"]).Option(Merge.OutV, (ITraversal) __.Select("outV")).Option(Merge.InV, (ITraversal) __.Select("inV")), (g,p) =>g.V(), (g,p) =>g.E(), (g,p) =>g.V().Has("name","marko").Out("knows").Has("name","vadas")}}, {"g_V_asXvX_mergeEXxx1X_optionXMerge_onMatch_xx2X_optionXMerge_outV_selectXvXX_optionXMerge_inV_selectXvXX", new List, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29), (g,p) =>g.V().As("v").MergeE((IDictionary) p["xx1"]).Option(Merge.OnMatch, (IDictionary) p["xx2"]).Option(Merge.OutV, (ITraversal) __.Select("v")).Option(Merge.InV, (ITraversal) __.Select("v"))}}, - {"g_V_mergeEXlabel_knows_out_marko_in_vadasX_optionXonMatch_sideEffectXpropertyXweight_0XX_constantXemptyXX", new List, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").As("a").AddV("person").Property("name","vadas").As("b").AddE("knows").Property("weight",1).From("a").To("b"), (g,p) =>g.V().MergeE((IDictionary) p["xx1"]).Option(Merge.OnMatch, (ITraversal) __.SideEffect(__.Property("weight",0)).Constant(new Dictionary {})), (g,p) =>g.V(), (g,p) =>g.E().HasLabel("knows").Has("weight",1), (g,p) =>g.E().HasLabel("knows").Has("weight",0), (g,p) =>g.V().Has("weight")}}, + {"g_V_mergeEXlabel_knows_out_marko_in_vadasX_optionXonMatch_sideEffectXpropertyXweight_0XX_constantXemptyXX", new List, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").As("a").AddV("person").Property("name","vadas").As("b").AddE("knows").Property("weight",1).From("a").To("b"), (g,p) =>g.V().MergeE((IDictionary) p["xx1"]).Option(Merge.OnMatch, (ITraversal) __.SideEffect(__.Property("weight",0)).Constant(new Dictionary {}))}}, {"g_mergeEXlabel_knows_out_marko_in_vadasX_optionXonMatch_sideEffectXpropertyXweight_0XX_constantXemptyXX", new List, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").As("a").AddV("person").Property("name","vadas").As("b").AddE("knows").Property("weight",1).From("a").To("b"), (g,p) =>g.MergeE((IDictionary) p["xx1"]).Option(Merge.OnMatch, (ITraversal) __.SideEffect(__.Property("weight",0)).Constant(new Dictionary {})), (g,p) =>g.V(), (g,p) =>g.E().HasLabel("knows").Has("weight",1), (g,p) =>g.E().HasLabel("knows").Has("weight",0), (g,p) =>g.V().Has("weight")}}, + {"g_injectXlist1_list2X_mergeEXlimitXlocal_1XX_optionXonCreate_rangeXlocal_1_2XX_optionXonMatch_tailXlocalXX_to_match", new List, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29).As("marko").AddV("person").Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property("name","lop").Property("lang","java").As("lop").AddV("person").Property("name","josh").Property("age",32).As("josh").AddV("software").Property("name","ripple").Property("lang","java").As("ripple").AddV("person").Property("name","peter").Property("age",35).As("peter").AddE("knows").From("marko").To("vadas").Property("weight",0.5).AddE("knows").From("marko").To("josh").Property("weight",1.0).AddE("created").From("marko").To("lop").Property("weight",0.4).AddE("created").From("josh").To("ripple").Property("weight",1.0).AddE("created").From("josh").To("lop").Property("weight",0.4).AddE("created").From("peter").To("lop").Property("weight",0.2), (g,p) =>g.Inject(p["xx1"],p["xx1"],p["xx2"]).Fold().MergeE((ITraversal) __.Limit(Scope.Local,1)).Option(Merge.OnCreate, (ITraversal) __.Range(Scope.Local,1,2)).Option(Merge.OnMatch, (ITraversal) __.Tail(Scope.Local)), (g,p) =>g.V(), (g,p) =>g.E(), (g,p) =>g.E().Has("created","N"), (g,p) =>g.V().Has("person","name","marko").OutE("knows").Has("created","N").InV().Has("person","name","vadas")}}, + {"g_injectXlist1_list2X_mergeEXlimitXlocal_1XX_optionXonCreate_rangeXlocal_1_2XX_optionXonMatch_tailXlocalXX_to_create", new List, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29).As("marko").AddV("person").Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property("name","lop").Property("lang","java").As("lop").AddV("person").Property("name","josh").Property("age",32).As("josh").AddV("software").Property("name","ripple").Property("lang","java").As("ripple").AddV("person").Property("name","peter").Property("age",35).As("peter").AddE("knows").From("marko").To("vadas").Property("weight",0.5).AddE("knows").From("marko").To("josh").Property("weight",1.0).AddE("created").From("marko").To("lop").Property("weight",0.4).AddE("created").From("josh").To("ripple").Property("weight",1.0).AddE("created").From("josh").To("lop").Property("weight",0.4).AddE("created").From("peter").To("lop").Property("weight",0.2), (g,p) =>g.Inject(p["xx1"],p["xx1"],p["xx2"]).Fold().MergeE((ITraversal) __.Limit(Scope.Local,1)).Option(Merge.OnCreate, (ITraversal) __.Range(Scope.Local,1,2)).Option(Merge.OnMatch, (ITraversal) __.Tail(Scope.Local)), (g,p) =>g.V(), (g,p) =>g.E(), (g,p) =>g.E().HasNot("created"), (g,p) =>g.V().Has("person","name","marko").OutE("knows").HasNot("created").InV().Has("person","name","vadas"), (g,p) =>g.V().Has("person","name","vadas").OutE("self").HasNot("weight").InV().Has("person","name","vadas")}}, {"g_mergeVXemptyX_optionXonMatch_nullX", new List, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29), (g,p) =>g.MergeV((IDictionary) new Dictionary {}).Option(Merge.OnMatch, (IDictionary) null), (g,p) =>g.V().Has("person","name","marko").Has("age",29)}}, {"g_V_mergeVXemptyX_optionXonMatch_nullX", new List, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29), (g,p) =>g.V().MergeV((IDictionary) new Dictionary {}).Option(Merge.OnMatch, (IDictionary) null), (g,p) =>g.V().Has("person","name","marko").Has("age",29)}}, {"g_mergeVXnullX_optionXonCreate_label_null_name_markoX", new List, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29), (g,p) =>g.MergeV((IDictionary) p["xx1"])}}, @@ -725,7 +727,7 @@ private static IDictionary, ITraversal>> {(g,p) =>g.AddV("person").Property("name","vadas").Property("age",29).AddV("person").Property("name","vadas").Property("age",27), (g,p) =>g.MergeV((IDictionary) p["xx1"]).Option(Merge.OnMatch, (IDictionary) p["xx2"]), (g,p) =>g.V().Has("age",35), (g,p) =>g.V()}}, {"g_V_mapXmergeXlabel_person_name_joshXX", new List, ITraversal>> {(g,p) =>g.AddV("person").Property("name","vadas").Property("age",29).AddV("person").Property("name","stephen").Property("age",27), (g,p) =>g.V().Map(__.MergeV((IDictionary) p["xx1"])), (g,p) =>g.V().Has("person","name","josh"), (g,p) =>g.V()}}, {"g_withSideEffectXc_label_person_name_markoX_withSideEffectXm_age_19X_mergeVXselectXcXX_optionXonMatch_sideEffectXpropertiesXageX_dropX_selectXmXX_option", new List, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property(Cardinality.List,"age",29).Property(Cardinality.List,"age",31).Property(Cardinality.List,"age",32), (g,p) =>g.WithSideEffect("c",p["xx1"]).WithSideEffect("m",p["xx2"]).MergeV((ITraversal) __.Select("c")).Option(Merge.OnMatch, (ITraversal) __.SideEffect(__.Properties("age").Drop()).Select("m")), (g,p) =>g.V().Has("person","name","marko").Has("age",19), (g,p) =>g.V().Has("person","name","marko").Has("age")}}, - {"g_withSideEffectXm_age_19X_V_hasXperson_name_markoX_mergeVXselectXcXX_optionXonMatch_sideEffectXpropertiesXageX_dropX_selectXmXX_option", new List, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property(Cardinality.List,"age",29).Property(Cardinality.List,"age",31).Property(Cardinality.List,"age",32), (g,p) =>g.WithSideEffect("m",p["xx1"]).V().Has("person","name","marko").MergeV((IDictionary) new Dictionary {}).Option(Merge.OnMatch, (ITraversal) __.SideEffect(__.Properties("age").Drop()).Select("m")), (g,p) =>g.V().Has("person","name","marko").Has("age",19), (g,p) =>g.V().Has("person","name","marko").Has("age")}}, + {"g_withSideEffectXm_age_19X_V_hasXperson_name_markoX_mergeVXselectXcXX_optionXonMatch_sideEffectXpropertiesXageX_dropX_selectXmXX_option", new List, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property(Cardinality.List,"age",29).Property(Cardinality.List,"age",31).Property(Cardinality.List,"age",32), (g,p) =>g.WithSideEffect("m",p["xx1"]).V().Has("person","name","marko").MergeV((IDictionary) new Dictionary {}).Option(Merge.OnMatch, (ITraversal) __.SideEffect(__.Properties("age").Drop()).Select("m"))}}, {"g_mergeV_onCreate_inheritance_existing", new List, ITraversal>> {(g,p) =>g.AddV("person").Property("name","mike").Property(T.Id,"1"), (g,p) =>g.MergeV((IDictionary) p["xx1"]).Option(Merge.OnCreate, (IDictionary) p["xx2"]), (g,p) =>g.V(), (g,p) =>g.V("1").Has("person","name","mike")}}, {"g_mergeV_onCreate_inheritance_new_1", new List, ITraversal>> {(g,p) =>g.MergeV((IDictionary) p["xx1"]).Option(Merge.OnCreate, (IDictionary) p["xx2"]), (g,p) =>g.V(), (g,p) =>g.V("1").Has("person","name","mike")}}, {"g_mergeV_onCreate_inheritance_new_2", new List, ITraversal>> {(g,p) =>g.MergeV((IDictionary) p["xx1"]).Option(Merge.OnCreate, (IDictionary) p["xx2"]), (g,p) =>g.V(), (g,p) =>g.V("1").Has("person","name","mike")}}, @@ -740,6 +742,8 @@ private static IDictionary, ITraversal>> {(g,p) =>g.AddV("vertex"), (g,p) =>g.MergeV((IDictionary) new Dictionary {}).Option(Merge.OnMatch, (IDictionary) p["xx1"])}}, {"g_mergeV_hidden_label_key_matched_onMatch_matched_prohibited", new List, ITraversal>> {(g,p) =>g.AddV("vertex"), (g,p) =>g.MergeV((IDictionary) new Dictionary {}).Option(Merge.OnMatch, (IDictionary) p["xx1"])}}, {"g_mergeV_hidden_label_key_onMatch_matched_prohibited", new List, ITraversal>> {(g,p) =>g.MergeV((IDictionary) new Dictionary {}).Option(Merge.OnMatch, (IDictionary) p["xx1"])}}, + {"g_injectXlist1_list2X_mergeVXlimitXlocal_1XX_optionXonCreate_rangeXlocal_1_2X_optionXonMatch_tailXlocalXX_to_match", new List, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29), (g,p) =>g.Inject(p["xx1"],p["xx1"],p["xx2"]).Fold().MergeV((ITraversal) __.Limit(Scope.Local,1)).Option(Merge.OnCreate, (ITraversal) __.Range(Scope.Local,1,2)).Option(Merge.OnMatch, (ITraversal) __.Tail(Scope.Local)), (g,p) =>g.V().Has("person","name","marko").Has("created","N"), (g,p) =>g.V()}}, + {"g_injectXlist1_list2X_mergeVXlimitXlocal_1XX_optionXonCreate_rangeXlocal_1_2X_optionXonMatch_tailXlocalXX_to_create", new List, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29), (g,p) =>g.Inject(p["xx1"],p["xx1"],p["xx2"]).Fold().MergeV((ITraversal) __.Limit(Scope.Local,1)).Option(Merge.OnCreate, (ITraversal) __.Range(Scope.Local,1,2)).Option(Merge.OnMatch, (ITraversal) __.Tail(Scope.Local)), (g,p) =>g.V().Has("person","name","stephen").HasNot("created"), (g,p) =>g.V()}}, {"g_V_age_min", new List, ITraversal>> {(g,p) =>g.V().Values("age").Min()}}, {"g_V_foo_min", new List, ITraversal>> {(g,p) =>g.V().Values("foo").Min()}}, {"g_V_name_min", new List, ITraversal>> {(g,p) =>g.V().Values("name").Min()}}, diff --git a/gremlin-go/driver/cucumber/gremlin.go b/gremlin-go/driver/cucumber/gremlin.go index d1f6fc14932..f67e22056d8 100644 --- a/gremlin-go/driver/cucumber/gremlin.go +++ b/gremlin-go/driver/cucumber/gremlin.go @@ -660,8 +660,10 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[ "g_mergeV_mergeE_combination_new_vertices": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.MergeV(p["xx1"]).As("outV").MergeV(p["xx2"]).As("inV").MergeE(p["xx3"]).Option(gremlingo.Merge.OutV, gremlingo.T__.Select("outV")).Option(gremlingo.Merge.InV, gremlingo.T__.Select("inV"))}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V()}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E()}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", "marko").Out("knows").Has("name", "vadas")}}, "g_mergeV_mergeE_combination_existing_vertices": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").AddV("person").Property("name", "vadas")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.MergeV(p["xx1"]).As("outV").MergeV(p["xx2"]).As("inV").MergeE(p["xx3"]).Option(gremlingo.Merge.OutV, gremlingo.T__.Select("outV")).Option(gremlingo.Merge.InV, gremlingo.T__.Select("inV"))}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V()}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E()}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", "marko").Out("knows").Has("name", "vadas")}}, "g_V_asXvX_mergeEXxx1X_optionXMerge_onMatch_xx2X_optionXMerge_outV_selectXvXX_optionXMerge_inV_selectXvXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").Property("age", 29)}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().As("v").MergeE(p["xx1"]).Option(gremlingo.Merge.OnMatch, p["xx2"]).Option(gremlingo.Merge.OutV, gremlingo.T__.Select("v")).Option(gremlingo.Merge.InV, gremlingo.T__.Select("v"))}}, - "g_V_mergeEXlabel_knows_out_marko_in_vadasX_optionXonMatch_sideEffectXpropertyXweight_0XX_constantXemptyXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").As("a").AddV("person").Property("name", "vadas").As("b").AddE("knows").Property("weight", 1).From("a").To("b")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().MergeE(p["xx1"]).Option(gremlingo.Merge.OnMatch, gremlingo.T__.SideEffect(gremlingo.T__.Property("weight", 0)).Constant(map[interface{}]interface{}{}))}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V()}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E().HasLabel("knows").Has("weight", 1)}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E().HasLabel("knows").Has("weight", 0)}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("weight")}}, + "g_V_mergeEXlabel_knows_out_marko_in_vadasX_optionXonMatch_sideEffectXpropertyXweight_0XX_constantXemptyXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").As("a").AddV("person").Property("name", "vadas").As("b").AddE("knows").Property("weight", 1).From("a").To("b")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().MergeE(p["xx1"]).Option(gremlingo.Merge.OnMatch, gremlingo.T__.SideEffect(gremlingo.T__.Property("weight", 0)).Constant(map[interface{}]interface{}{}))}}, "g_mergeEXlabel_knows_out_marko_in_vadasX_optionXonMatch_sideEffectXpropertyXweight_0XX_constantXemptyXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").As("a").AddV("person").Property("name", "vadas").As("b").AddE("knows").Property("weight", 1).From("a").To("b")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.MergeE(p["xx1"]).Option(gremlingo.Merge.OnMatch, gremlingo.T__.SideEffect(gremlingo.T__.Property("weight", 0)).Constant(map[interface{}]interface{}{}))}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V()}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E().HasLabel("knows").Has("weight", 1)}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E().HasLabel("knows").Has("weight", 0)}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("weight")}}, + "g_injectXlist1_list2X_mergeEXlimitXlocal_1XX_optionXonCreate_rangeXlocal_1_2XX_optionXonMatch_tailXlocalXX_to_match": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").Property("age", 29).As("marko").AddV("person").Property("name", "vadas").Property("age", 27).As("vadas").AddV("software").Property("name", "lop").Property("lang", "java").As("lop").AddV("person").Property("name", "josh").Property("age", 32).As("josh").AddV("software").Property("name", "ripple").Property("lang", "java").As("ripple").AddV("person").Property("name", "peter").Property("age", 35).As("peter").AddE("knows").From("marko").To("vadas").Property("weight", 0.5).AddE("knows").From("marko").To("josh").Property("weight", 1.0).AddE("created").From("marko").To("lop").Property("weight", 0.4).AddE("created").From("josh").To("ripple").Property("weight", 1.0).AddE("created").From("josh").To("lop").Property("weight", 0.4).AddE("created").From("peter").To("lop").Property("weight", 0.2)}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(p["xx1"], p["xx1"], p["xx2"]).Fold().MergeE(gremlingo.T__.Limit(gremlingo.Scope.Local, 1)).Option(gremlingo.Merge.OnCreate, gremlingo.T__.Range(gremlingo.Scope.Local, 1, 2)).Option(gremlingo.Merge.OnMatch, gremlingo.T__.Tail(gremlingo.Scope.Local))}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V()}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E()}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E().Has("created", "N")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("person", "name", "marko").OutE("knows").Has("created", "N").InV().Has("person", "name", "vadas")}}, + "g_injectXlist1_list2X_mergeEXlimitXlocal_1XX_optionXonCreate_rangeXlocal_1_2XX_optionXonMatch_tailXlocalXX_to_create": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").Property("age", 29).As("marko").AddV("person").Property("name", "vadas").Property("age", 27).As("vadas").AddV("software").Property("name", "lop").Property("lang", "java").As("lop").AddV("person").Property("name", "josh").Property("age", 32).As("josh").AddV("software").Property("name", "ripple").Property("lang", "java").As("ripple").AddV("person").Property("name", "peter").Property("age", 35).As("peter").AddE("knows").From("marko").To("vadas").Property("weight", 0.5).AddE("knows").From("marko").To("josh").Property("weight", 1.0).AddE("created").From("marko").To("lop").Property("weight", 0.4).AddE("created").From("josh").To("ripple").Property("weight", 1.0).AddE("created").From("josh").To("lop").Property("weight", 0.4).AddE("created").From("peter").To("lop").Property("weight", 0.2)}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(p["xx1"], p["xx1"], p["xx2"]).Fold().MergeE(gremlingo.T__.Limit(gremlingo.Scope.Local, 1)).Option(gremlingo.Merge.OnCreate, gremlingo.T__.Range(gremlingo.Scope.Local, 1, 2)).Option(gremlingo.Merge.OnMatch, gremlingo.T__.Tail(gremlingo.Scope.Local))}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V()}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E()}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E().HasNot("created")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("person", "name", "marko").OutE("knows").HasNot("created").InV().Has("person", "name", "vadas")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("person", "name", "vadas").OutE("self").HasNot("weight").InV().Has("person", "name", "vadas")}}, "g_mergeVXemptyX_optionXonMatch_nullX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").Property("age", 29)}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.MergeV(map[interface{}]interface{}{}).Option(gremlingo.Merge.OnMatch, nil)}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("person", "name", "marko").Has("age", 29)}}, "g_V_mergeVXemptyX_optionXonMatch_nullX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").Property("age", 29)}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().MergeV(map[interface{}]interface{}{}).Option(gremlingo.Merge.OnMatch, nil)}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("person", "name", "marko").Has("age", 29)}}, "g_mergeVXnullX_optionXonCreate_label_null_name_markoX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").Property("age", 29)}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.MergeV(p["xx1"])}}, @@ -696,7 +698,7 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[ "g_mergeXlabel_person_name_vadasX_optionXonMatch_age_35X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "vadas").Property("age", 29).AddV("person").Property("name", "vadas").Property("age", 27)}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.MergeV(p["xx1"]).Option(gremlingo.Merge.OnMatch, p["xx2"])}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("age", 35)}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V()}}, "g_V_mapXmergeXlabel_person_name_joshXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "vadas").Property("age", 29).AddV("person").Property("name", "stephen").Property("age", 27)}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Map(gremlingo.T__.MergeV(p["xx1"]))}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("person", "name", "josh")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V()}}, "g_withSideEffectXc_label_person_name_markoX_withSideEffectXm_age_19X_mergeVXselectXcXX_optionXonMatch_sideEffectXpropertiesXageX_dropX_selectXmXX_option": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").Property(gremlingo.Cardinality.List, "age", 29).Property(gremlingo.Cardinality.List, "age", 31).Property(gremlingo.Cardinality.List, "age", 32)}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.WithSideEffect("c", p["xx1"]).WithSideEffect("m", p["xx2"]).MergeV(gremlingo.T__.Select("c")).Option(gremlingo.Merge.OnMatch, gremlingo.T__.SideEffect(gremlingo.T__.Properties("age").Drop()).Select("m"))}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("person", "name", "marko").Has("age", 19)}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("person", "name", "marko").Has("age")}}, - "g_withSideEffectXm_age_19X_V_hasXperson_name_markoX_mergeVXselectXcXX_optionXonMatch_sideEffectXpropertiesXageX_dropX_selectXmXX_option": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").Property(gremlingo.Cardinality.List, "age", 29).Property(gremlingo.Cardinality.List, "age", 31).Property(gremlingo.Cardinality.List, "age", 32)}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.WithSideEffect("m", p["xx1"]).V().Has("person", "name", "marko").MergeV(map[interface{}]interface{}{}).Option(gremlingo.Merge.OnMatch, gremlingo.T__.SideEffect(gremlingo.T__.Properties("age").Drop()).Select("m"))}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("person", "name", "marko").Has("age", 19)}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("person", "name", "marko").Has("age")}}, + "g_withSideEffectXm_age_19X_V_hasXperson_name_markoX_mergeVXselectXcXX_optionXonMatch_sideEffectXpropertiesXageX_dropX_selectXmXX_option": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").Property(gremlingo.Cardinality.List, "age", 29).Property(gremlingo.Cardinality.List, "age", 31).Property(gremlingo.Cardinality.List, "age", 32)}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.WithSideEffect("m", p["xx1"]).V().Has("person", "name", "marko").MergeV(map[interface{}]interface{}{}).Option(gremlingo.Merge.OnMatch, gremlingo.T__.SideEffect(gremlingo.T__.Properties("age").Drop()).Select("m"))}}, "g_mergeV_onCreate_inheritance_existing": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "mike").Property(gremlingo.T.Id, "1")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.MergeV(p["xx1"]).Option(gremlingo.Merge.OnCreate, p["xx2"])}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V()}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V("1").Has("person", "name", "mike")}}, "g_mergeV_onCreate_inheritance_new_1": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.MergeV(p["xx1"]).Option(gremlingo.Merge.OnCreate, p["xx2"])}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V()}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V("1").Has("person", "name", "mike")}}, "g_mergeV_onCreate_inheritance_new_2": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.MergeV(p["xx1"]).Option(gremlingo.Merge.OnCreate, p["xx2"])}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V()}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V("1").Has("person", "name", "mike")}}, @@ -711,6 +713,8 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[ "g_mergeV_hidden_id_key_onMatch_matched_prohibited": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("vertex")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.MergeV(map[interface{}]interface{}{}).Option(gremlingo.Merge.OnMatch, p["xx1"])}}, "g_mergeV_hidden_label_key_matched_onMatch_matched_prohibited": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("vertex")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.MergeV(map[interface{}]interface{}{}).Option(gremlingo.Merge.OnMatch, p["xx1"])}}, "g_mergeV_hidden_label_key_onMatch_matched_prohibited": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.MergeV(map[interface{}]interface{}{}).Option(gremlingo.Merge.OnMatch, p["xx1"])}}, + "g_injectXlist1_list2X_mergeVXlimitXlocal_1XX_optionXonCreate_rangeXlocal_1_2X_optionXonMatch_tailXlocalXX_to_match": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").Property("age", 29)}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(p["xx1"], p["xx1"], p["xx2"]).Fold().MergeV(gremlingo.T__.Limit(gremlingo.Scope.Local, 1)).Option(gremlingo.Merge.OnCreate, gremlingo.T__.Range(gremlingo.Scope.Local, 1, 2)).Option(gremlingo.Merge.OnMatch, gremlingo.T__.Tail(gremlingo.Scope.Local))}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("person", "name", "marko").Has("created", "N")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V()}}, + "g_injectXlist1_list2X_mergeVXlimitXlocal_1XX_optionXonCreate_rangeXlocal_1_2X_optionXonMatch_tailXlocalXX_to_create": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").Property("age", 29)}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(p["xx1"], p["xx1"], p["xx2"]).Fold().MergeV(gremlingo.T__.Limit(gremlingo.Scope.Local, 1)).Option(gremlingo.Merge.OnCreate, gremlingo.T__.Range(gremlingo.Scope.Local, 1, 2)).Option(gremlingo.Merge.OnMatch, gremlingo.T__.Tail(gremlingo.Scope.Local))}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("person", "name", "stephen").HasNot("created")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V()}}, "g_V_age_min": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Min()}}, "g_V_foo_min": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("foo").Min()}}, "g_V_name_min": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("name").Min()}}, 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 479575d5fc8..b82c018dee1 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 @@ -679,8 +679,10 @@ const gremlins = { g_mergeV_mergeE_combination_new_vertices: [function({g, xx1, xx3, xx2}) { return g.mergeV(xx1).as("outV").mergeV(xx2).as("inV").mergeE(xx3).option(Merge.outV,__.select("outV")).option(Merge.inV,__.select("inV")) }, function({g, xx1, xx3, xx2}) { return g.V() }, function({g, xx1, xx3, xx2}) { return g.E() }, function({g, xx1, xx3, xx2}) { return g.V().has("name","marko").out("knows").has("name","vadas") }], g_mergeV_mergeE_combination_existing_vertices: [function({g, xx1, xx3, xx2}) { return g.addV("person").property("name","marko").addV("person").property("name","vadas") }, function({g, xx1, xx3, xx2}) { return g.mergeV(xx1).as("outV").mergeV(xx2).as("inV").mergeE(xx3).option(Merge.outV,__.select("outV")).option(Merge.inV,__.select("inV")) }, function({g, xx1, xx3, xx2}) { return g.V() }, function({g, xx1, xx3, xx2}) { return g.E() }, function({g, xx1, xx3, xx2}) { return g.V().has("name","marko").out("knows").has("name","vadas") }], g_V_asXvX_mergeEXxx1X_optionXMerge_onMatch_xx2X_optionXMerge_outV_selectXvXX_optionXMerge_inV_selectXvXX: [function({g, xx1, xx2}) { return g.addV("person").property("name","marko").property("age",29) }, function({g, xx1, xx2}) { return g.V().as("v").mergeE(xx1).option(Merge.onMatch,xx2).option(Merge.outV,__.select("v")).option(Merge.inV,__.select("v")) }], - g_V_mergeEXlabel_knows_out_marko_in_vadasX_optionXonMatch_sideEffectXpropertyXweight_0XX_constantXemptyXX: [function({g, xx1}) { return g.addV("person").property("name","marko").as("a").addV("person").property("name","vadas").as("b").addE("knows").property("weight",1).from_("a").to("b") }, function({g, xx1}) { return g.V().mergeE(xx1).option(Merge.onMatch,__.sideEffect(__.property("weight",0)).constant(new Map([]))) }, function({g, xx1}) { return g.V() }, function({g, xx1}) { return g.E().hasLabel("knows").has("weight",1) }, function({g, xx1}) { return g.E().hasLabel("knows").has("weight",0) }, function({g, xx1}) { return g.V().has("weight") }], + g_V_mergeEXlabel_knows_out_marko_in_vadasX_optionXonMatch_sideEffectXpropertyXweight_0XX_constantXemptyXX: [function({g, xx1}) { return g.addV("person").property("name","marko").as("a").addV("person").property("name","vadas").as("b").addE("knows").property("weight",1).from_("a").to("b") }, function({g, xx1}) { return g.V().mergeE(xx1).option(Merge.onMatch,__.sideEffect(__.property("weight",0)).constant(new Map([]))) }], g_mergeEXlabel_knows_out_marko_in_vadasX_optionXonMatch_sideEffectXpropertyXweight_0XX_constantXemptyXX: [function({g, xx1}) { return g.addV("person").property("name","marko").as("a").addV("person").property("name","vadas").as("b").addE("knows").property("weight",1).from_("a").to("b") }, function({g, xx1}) { return g.mergeE(xx1).option(Merge.onMatch,__.sideEffect(__.property("weight",0)).constant(new Map([]))) }, function({g, xx1}) { return g.V() }, function({g, xx1}) { return g.E().hasLabel("knows").has("weight",1) }, function({g, xx1}) { return g.E().hasLabel("knows").has("weight",0) }, function({g, xx1}) { return g.V().has("weight") }], + g_injectXlist1_list2X_mergeEXlimitXlocal_1XX_optionXonCreate_rangeXlocal_1_2XX_optionXonMatch_tailXlocalXX_to_match: [function({g, xx1, xx2}) { return g.addV("person").property("name","marko").property("age",29).as("marko").addV("person").property("name","vadas").property("age",27).as("vadas").addV("software").property("name","lop").property("lang","java").as("lop").addV("person").property("name","josh").property("age",32).as("josh").addV("software").property("name","ripple").property("lang","java").as("ripple").addV("person").property("name","peter").property("age",35).as("peter").addE("knows").from_("marko").to("vadas").property("weight",0.5).addE("knows").from_("marko").to("josh").property("weight",1.0).addE("created").from_("marko").to("lop").property("weight",0.4).addE("created").from_("josh").to("ripple").property("weight",1.0).addE("created").from_("josh").to("lop").property("weight",0.4).addE("created").from_("peter").to("lop").property("weight",0.2) }, function({g, xx1, xx2}) { return g.inject(xx1,xx1,xx2).fold().mergeE(__.limit(Scope.local,1)).option(Merge.onCreate,__.range(Scope.local,1,2)).option(Merge.onMatch,__.tail(Scope.local)) }, function({g, xx1, xx2}) { return g.V() }, function({g, xx1, xx2}) { return g.E() }, function({g, xx1, xx2}) { return g.E().has("created","N") }, function({g, xx1, xx2}) { return g.V().has("person","name","marko").outE("knows").has("created","N").inV().has("person","name","vadas") }], + g_injectXlist1_list2X_mergeEXlimitXlocal_1XX_optionXonCreate_rangeXlocal_1_2XX_optionXonMatch_tailXlocalXX_to_create: [function({g, xx1, xx2}) { return g.addV("person").property("name","marko").property("age",29).as("marko").addV("person").property("name","vadas").property("age",27).as("vadas").addV("software").property("name","lop").property("lang","java").as("lop").addV("person").property("name","josh").property("age",32).as("josh").addV("software").property("name","ripple").property("lang","java").as("ripple").addV("person").property("name","peter").property("age",35).as("peter").addE("knows").from_("marko").to("vadas").property("weight",0.5).addE("knows").from_("marko").to("josh").property("weight",1.0).addE("created").from_("marko").to("lop").property("weight",0.4).addE("created").from_("josh").to("ripple").property("weight",1.0).addE("created").from_("josh").to("lop").property("weight",0.4).addE("created").from_("peter").to("lop").property("weight",0.2) }, function({g, xx1, xx2}) { return g.inject(xx1,xx1,xx2).fold().mergeE(__.limit(Scope.local,1)).option(Merge.onCreate,__.range(Scope.local,1,2)).option(Merge.onMatch,__.tail(Scope.local)) }, function({g, xx1, xx2}) { return g.V() }, function({g, xx1, xx2}) { return g.E() }, function({g, xx1, xx2}) { return g.E().hasNot("created") }, function({g, xx1, xx2}) { return g.V().has("person","name","marko").outE("knows").hasNot("created").inV().has("person","name","vadas") }, function({g, xx1, xx2}) { return g.V().has("person","name","vadas").outE("self").hasNot("weight").inV().has("person","name","vadas") }], g_mergeVXemptyX_optionXonMatch_nullX: [function({g}) { return g.addV("person").property("name","marko").property("age",29) }, function({g}) { return g.mergeV(new Map([])).option(Merge.onMatch,null) }, function({g}) { return g.V().has("person","name","marko").has("age",29) }], g_V_mergeVXemptyX_optionXonMatch_nullX: [function({g}) { return g.addV("person").property("name","marko").property("age",29) }, function({g}) { return g.V().mergeV(new Map([])).option(Merge.onMatch,null) }, function({g}) { return g.V().has("person","name","marko").has("age",29) }], g_mergeVXnullX_optionXonCreate_label_null_name_markoX: [function({g, xx1}) { return g.addV("person").property("name","marko").property("age",29) }, function({g, xx1}) { return g.mergeV(xx1) }], @@ -715,7 +717,7 @@ const gremlins = { g_mergeXlabel_person_name_vadasX_optionXonMatch_age_35X: [function({g, xx1, xx2}) { return g.addV("person").property("name","vadas").property("age",29).addV("person").property("name","vadas").property("age",27) }, function({g, xx1, xx2}) { return g.mergeV(xx1).option(Merge.onMatch,xx2) }, function({g, xx1, xx2}) { return g.V().has("age",35) }, function({g, xx1, xx2}) { return g.V() }], g_V_mapXmergeXlabel_person_name_joshXX: [function({g, xx1}) { return g.addV("person").property("name","vadas").property("age",29).addV("person").property("name","stephen").property("age",27) }, function({g, xx1}) { return g.V().map(__.mergeV(xx1)) }, function({g, xx1}) { return g.V().has("person","name","josh") }, function({g, xx1}) { return g.V() }], g_withSideEffectXc_label_person_name_markoX_withSideEffectXm_age_19X_mergeVXselectXcXX_optionXonMatch_sideEffectXpropertiesXageX_dropX_selectXmXX_option: [function({g, xx1, xx2}) { return g.addV("person").property("name","marko").property(Cardinality.list,"age",29).property(Cardinality.list,"age",31).property(Cardinality.list,"age",32) }, function({g, xx1, xx2}) { return g.withSideEffect("c",xx1).withSideEffect("m",xx2).mergeV(__.select("c")).option(Merge.onMatch,__.sideEffect(__.properties("age").drop()).select("m")) }, function({g, xx1, xx2}) { return g.V().has("person","name","marko").has("age",19) }, function({g, xx1, xx2}) { return g.V().has("person","name","marko").has("age") }], - g_withSideEffectXm_age_19X_V_hasXperson_name_markoX_mergeVXselectXcXX_optionXonMatch_sideEffectXpropertiesXageX_dropX_selectXmXX_option: [function({g, xx1}) { return g.addV("person").property("name","marko").property(Cardinality.list,"age",29).property(Cardinality.list,"age",31).property(Cardinality.list,"age",32) }, function({g, xx1}) { return g.withSideEffect("m",xx1).V().has("person","name","marko").mergeV(new Map([])).option(Merge.onMatch,__.sideEffect(__.properties("age").drop()).select("m")) }, function({g, xx1}) { return g.V().has("person","name","marko").has("age",19) }, function({g, xx1}) { return g.V().has("person","name","marko").has("age") }], + g_withSideEffectXm_age_19X_V_hasXperson_name_markoX_mergeVXselectXcXX_optionXonMatch_sideEffectXpropertiesXageX_dropX_selectXmXX_option: [function({g, xx1}) { return g.addV("person").property("name","marko").property(Cardinality.list,"age",29).property(Cardinality.list,"age",31).property(Cardinality.list,"age",32) }, function({g, xx1}) { return g.withSideEffect("m",xx1).V().has("person","name","marko").mergeV(new Map([])).option(Merge.onMatch,__.sideEffect(__.properties("age").drop()).select("m")) }], g_mergeV_onCreate_inheritance_existing: [function({g, xx1, xx2}) { return g.addV("person").property("name","mike").property(T.id,"1") }, function({g, xx1, xx2}) { return g.mergeV(xx1).option(Merge.onCreate,xx2) }, function({g, xx1, xx2}) { return g.V() }, function({g, xx1, xx2}) { return g.V("1").has("person","name","mike") }], g_mergeV_onCreate_inheritance_new_1: [function({g, xx1, xx2}) { return g.mergeV(xx1).option(Merge.onCreate,xx2) }, function({g, xx1, xx2}) { return g.V() }, function({g, xx1, xx2}) { return g.V("1").has("person","name","mike") }], g_mergeV_onCreate_inheritance_new_2: [function({g, xx1, xx2}) { return g.mergeV(xx1).option(Merge.onCreate,xx2) }, function({g, xx1, xx2}) { return g.V() }, function({g, xx1, xx2}) { return g.V("1").has("person","name","mike") }], @@ -730,6 +732,8 @@ const gremlins = { g_mergeV_hidden_id_key_onMatch_matched_prohibited: [function({g, xx1}) { return g.addV("vertex") }, function({g, xx1}) { return g.mergeV(new Map([])).option(Merge.onMatch,xx1) }], g_mergeV_hidden_label_key_matched_onMatch_matched_prohibited: [function({g, xx1}) { return g.addV("vertex") }, function({g, xx1}) { return g.mergeV(new Map([])).option(Merge.onMatch,xx1) }], g_mergeV_hidden_label_key_onMatch_matched_prohibited: [function({g, xx1}) { return g.mergeV(new Map([])).option(Merge.onMatch,xx1) }], + g_injectXlist1_list2X_mergeVXlimitXlocal_1XX_optionXonCreate_rangeXlocal_1_2X_optionXonMatch_tailXlocalXX_to_match: [function({g, xx1, xx2}) { return g.addV("person").property("name","marko").property("age",29) }, function({g, xx1, xx2}) { return g.inject(xx1,xx1,xx2).fold().mergeV(__.limit(Scope.local,1)).option(Merge.onCreate,__.range(Scope.local,1,2)).option(Merge.onMatch,__.tail(Scope.local)) }, function({g, xx1, xx2}) { return g.V().has("person","name","marko").has("created","N") }, function({g, xx1, xx2}) { return g.V() }], + g_injectXlist1_list2X_mergeVXlimitXlocal_1XX_optionXonCreate_rangeXlocal_1_2X_optionXonMatch_tailXlocalXX_to_create: [function({g, xx1, xx2}) { return g.addV("person").property("name","marko").property("age",29) }, function({g, xx1, xx2}) { return g.inject(xx1,xx1,xx2).fold().mergeV(__.limit(Scope.local,1)).option(Merge.onCreate,__.range(Scope.local,1,2)).option(Merge.onMatch,__.tail(Scope.local)) }, function({g, xx1, xx2}) { return g.V().has("person","name","stephen").hasNot("created") }, function({g, xx1, xx2}) { return g.V() }], g_V_age_min: [function({g}) { return g.V().values("age").min() }], g_V_foo_min: [function({g}) { return g.V().values("foo").min() }], g_V_name_min: [function({g}) { return g.V().values("name").min() }], diff --git a/gremlin-python/src/main/python/radish/gremlin.py b/gremlin-python/src/main/python/radish/gremlin.py index 448114d306a..5d0e7b78bf8 100644 --- a/gremlin-python/src/main/python/radish/gremlin.py +++ b/gremlin-python/src/main/python/radish/gremlin.py @@ -661,8 +661,10 @@ 'g_mergeV_mergeE_combination_new_vertices': [(lambda g, xx1=None,xx3=None,xx2=None:g.merge_v(xx1).as_('outV').merge_v(xx2).as_('inV').merge_e(xx3).option(Merge.out_v,__.select('outV')).option(Merge.in_v,__.select('inV'))), (lambda g, xx1=None,xx3=None,xx2=None:g.V()), (lambda g, xx1=None,xx3=None,xx2=None:g.E()), (lambda g, xx1=None,xx3=None,xx2=None:g.V().has('name','marko').out('knows').has('name','vadas'))], 'g_mergeV_mergeE_combination_existing_vertices': [(lambda g, xx1=None,xx3=None,xx2=None:g.addV('person').property('name','marko').addV('person').property('name','vadas')), (lambda g, xx1=None,xx3=None,xx2=None:g.merge_v(xx1).as_('outV').merge_v(xx2).as_('inV').merge_e(xx3).option(Merge.out_v,__.select('outV')).option(Merge.in_v,__.select('inV'))), (lambda g, xx1=None,xx3=None,xx2=None:g.V()), (lambda g, xx1=None,xx3=None,xx2=None:g.E()), (lambda g, xx1=None,xx3=None,xx2=None:g.V().has('name','marko').out('knows').has('name','vadas'))], 'g_V_asXvX_mergeEXxx1X_optionXMerge_onMatch_xx2X_optionXMerge_outV_selectXvXX_optionXMerge_inV_selectXvXX': [(lambda g, xx1=None,xx2=None:g.addV('person').property('name','marko').property('age',29)), (lambda g, xx1=None,xx2=None:g.V().as_('v').merge_e(xx1).option(Merge.on_match,xx2).option(Merge.out_v,__.select('v')).option(Merge.in_v,__.select('v')))], - 'g_V_mergeEXlabel_knows_out_marko_in_vadasX_optionXonMatch_sideEffectXpropertyXweight_0XX_constantXemptyXX': [(lambda g, xx1=None:g.addV('person').property('name','marko').as_('a').addV('person').property('name','vadas').as_('b').addE('knows').property('weight',1).from_('a').to('b')), (lambda g, xx1=None:g.V().merge_e(xx1).option(Merge.on_match,__.sideEffect(__.property('weight',0)).constant({}))), (lambda g, xx1=None:g.V()), (lambda g, xx1=None:g.E().hasLabel('knows').has('weight',1)), (lambda g, xx1=None:g.E().hasLabel('knows').has('weight',0)), (lambda g, xx1=None:g.V().has('weight'))], + 'g_V_mergeEXlabel_knows_out_marko_in_vadasX_optionXonMatch_sideEffectXpropertyXweight_0XX_constantXemptyXX': [(lambda g, xx1=None:g.addV('person').property('name','marko').as_('a').addV('person').property('name','vadas').as_('b').addE('knows').property('weight',1).from_('a').to('b')), (lambda g, xx1=None:g.V().merge_e(xx1).option(Merge.on_match,__.sideEffect(__.property('weight',0)).constant({})))], 'g_mergeEXlabel_knows_out_marko_in_vadasX_optionXonMatch_sideEffectXpropertyXweight_0XX_constantXemptyXX': [(lambda g, xx1=None:g.addV('person').property('name','marko').as_('a').addV('person').property('name','vadas').as_('b').addE('knows').property('weight',1).from_('a').to('b')), (lambda g, xx1=None:g.merge_e(xx1).option(Merge.on_match,__.sideEffect(__.property('weight',0)).constant({}))), (lambda g, xx1=None:g.V()), (lambda g, xx1=None:g.E().hasLabel('knows').has('weight',1)), (lambda g, xx1=None:g.E().hasLabel('knows').has('weight',0)), (lambda g, xx1=None:g.V().has('weight'))], + 'g_injectXlist1_list2X_mergeEXlimitXlocal_1XX_optionXonCreate_rangeXlocal_1_2XX_optionXonMatch_tailXlocalXX_to_match': [(lambda g, xx1=None,xx2=None:g.addV('person').property('name','marko').property('age',29).as_('marko').addV('person').property('name','vadas').property('age',27).as_('vadas').addV('software').property('name','lop').property('lang','java').as_('lop').addV('person').property('name','josh').property('age',32).as_('josh').addV('software').property('name','ripple').property('lang','java').as_('ripple').addV('person').property('name','peter').property('age',35).as_('peter').addE('knows').from_('marko').to('vadas').property('weight',float(0.5)).addE('knows').from_('marko').to('josh').property('weight',float(1.0)).addE('created').from_('marko').to('lop').property('weight',float(0.4)).addE('created').from_('josh').to('ripple').property('weight',float(1.0)).addE('created').from_('josh').to('lop').property('weight',float(0.4)).addE('created').from_('peter').to('lop').property('weight',float(0.2))), (lambda g, xx1=None,xx2=None:g.inject(xx1,xx1,xx2).fold().merge_e(__.limit(Scope.local,1)).option(Merge.on_create,__.range_(Scope.local,1,2)).option(Merge.on_match,__.tail(Scope.local))), (lambda g, xx1=None,xx2=None:g.V()), (lambda g, xx1=None,xx2=None:g.E()), (lambda g, xx1=None,xx2=None:g.E().has('created','N')), (lambda g, xx1=None,xx2=None:g.V().has('person','name','marko').outE('knows').has('created','N').in_v().has('person','name','vadas'))], + 'g_injectXlist1_list2X_mergeEXlimitXlocal_1XX_optionXonCreate_rangeXlocal_1_2XX_optionXonMatch_tailXlocalXX_to_create': [(lambda g, xx1=None,xx2=None:g.addV('person').property('name','marko').property('age',29).as_('marko').addV('person').property('name','vadas').property('age',27).as_('vadas').addV('software').property('name','lop').property('lang','java').as_('lop').addV('person').property('name','josh').property('age',32).as_('josh').addV('software').property('name','ripple').property('lang','java').as_('ripple').addV('person').property('name','peter').property('age',35).as_('peter').addE('knows').from_('marko').to('vadas').property('weight',float(0.5)).addE('knows').from_('marko').to('josh').property('weight',float(1.0)).addE('created').from_('marko').to('lop').property('weight',float(0.4)).addE('created').from_('josh').to('ripple').property('weight',float(1.0)).addE('created').from_('josh').to('lop').property('weight',float(0.4)).addE('created').from_('peter').to('lop').property('weight',float(0.2))), (lambda g, xx1=None,xx2=None:g.inject(xx1,xx1,xx2).fold().merge_e(__.limit(Scope.local,1)).option(Merge.on_create,__.range_(Scope.local,1,2)).option(Merge.on_match,__.tail(Scope.local))), (lambda g, xx1=None,xx2=None:g.V()), (lambda g, xx1=None,xx2=None:g.E()), (lambda g, xx1=None,xx2=None:g.E().hasNot('created')), (lambda g, xx1=None,xx2=None:g.V().has('person','name','marko').outE('knows').hasNot('created').in_v().has('person','name','vadas')), (lambda g, xx1=None,xx2=None:g.V().has('person','name','vadas').outE('self').hasNot('weight').in_v().has('person','name','vadas'))], 'g_mergeVXemptyX_optionXonMatch_nullX': [(lambda g:g.addV('person').property('name','marko').property('age',29)), (lambda g:g.merge_v({}).option(Merge.on_match,None)), (lambda g:g.V().has('person','name','marko').has('age',29))], 'g_V_mergeVXemptyX_optionXonMatch_nullX': [(lambda g:g.addV('person').property('name','marko').property('age',29)), (lambda g:g.V().merge_v({}).option(Merge.on_match,None)), (lambda g:g.V().has('person','name','marko').has('age',29))], 'g_mergeVXnullX_optionXonCreate_label_null_name_markoX': [(lambda g, xx1=None:g.addV('person').property('name','marko').property('age',29)), (lambda g, xx1=None:g.merge_v(xx1))], @@ -697,7 +699,7 @@ 'g_mergeXlabel_person_name_vadasX_optionXonMatch_age_35X': [(lambda g, xx1=None,xx2=None:g.addV('person').property('name','vadas').property('age',29).addV('person').property('name','vadas').property('age',27)), (lambda g, xx1=None,xx2=None:g.merge_v(xx1).option(Merge.on_match,xx2)), (lambda g, xx1=None,xx2=None:g.V().has('age',35)), (lambda g, xx1=None,xx2=None:g.V())], 'g_V_mapXmergeXlabel_person_name_joshXX': [(lambda g, xx1=None:g.addV('person').property('name','vadas').property('age',29).addV('person').property('name','stephen').property('age',27)), (lambda g, xx1=None:g.V().map(__.merge_v(xx1))), (lambda g, xx1=None:g.V().has('person','name','josh')), (lambda g, xx1=None:g.V())], 'g_withSideEffectXc_label_person_name_markoX_withSideEffectXm_age_19X_mergeVXselectXcXX_optionXonMatch_sideEffectXpropertiesXageX_dropX_selectXmXX_option': [(lambda g, xx1=None,xx2=None:g.addV('person').property('name','marko').property(Cardinality.list_,'age',29).property(Cardinality.list_,'age',31).property(Cardinality.list_,'age',32)), (lambda g, xx1=None,xx2=None:g.withSideEffect('c',xx1).withSideEffect('m',xx2).merge_v(__.select('c')).option(Merge.on_match,__.sideEffect(__.properties('age').drop()).select('m'))), (lambda g, xx1=None,xx2=None:g.V().has('person','name','marko').has('age',19)), (lambda g, xx1=None,xx2=None:g.V().has('person','name','marko').has('age'))], - 'g_withSideEffectXm_age_19X_V_hasXperson_name_markoX_mergeVXselectXcXX_optionXonMatch_sideEffectXpropertiesXageX_dropX_selectXmXX_option': [(lambda g, xx1=None:g.addV('person').property('name','marko').property(Cardinality.list_,'age',29).property(Cardinality.list_,'age',31).property(Cardinality.list_,'age',32)), (lambda g, xx1=None:g.withSideEffect('m',xx1).V().has('person','name','marko').merge_v({}).option(Merge.on_match,__.sideEffect(__.properties('age').drop()).select('m'))), (lambda g, xx1=None:g.V().has('person','name','marko').has('age',19)), (lambda g, xx1=None:g.V().has('person','name','marko').has('age'))], + 'g_withSideEffectXm_age_19X_V_hasXperson_name_markoX_mergeVXselectXcXX_optionXonMatch_sideEffectXpropertiesXageX_dropX_selectXmXX_option': [(lambda g, xx1=None:g.addV('person').property('name','marko').property(Cardinality.list_,'age',29).property(Cardinality.list_,'age',31).property(Cardinality.list_,'age',32)), (lambda g, xx1=None:g.withSideEffect('m',xx1).V().has('person','name','marko').merge_v({}).option(Merge.on_match,__.sideEffect(__.properties('age').drop()).select('m')))], 'g_mergeV_onCreate_inheritance_existing': [(lambda g, xx1=None,xx2=None:g.addV('person').property('name','mike').property(T.id_,'1')), (lambda g, xx1=None,xx2=None:g.merge_v(xx1).option(Merge.on_create,xx2)), (lambda g, xx1=None,xx2=None:g.V()), (lambda g, xx1=None,xx2=None:g.V('1').has('person','name','mike'))], 'g_mergeV_onCreate_inheritance_new_1': [(lambda g, xx1=None,xx2=None:g.merge_v(xx1).option(Merge.on_create,xx2)), (lambda g, xx1=None,xx2=None:g.V()), (lambda g, xx1=None,xx2=None:g.V('1').has('person','name','mike'))], 'g_mergeV_onCreate_inheritance_new_2': [(lambda g, xx1=None,xx2=None:g.merge_v(xx1).option(Merge.on_create,xx2)), (lambda g, xx1=None,xx2=None:g.V()), (lambda g, xx1=None,xx2=None:g.V('1').has('person','name','mike'))], @@ -712,6 +714,8 @@ 'g_mergeV_hidden_id_key_onMatch_matched_prohibited': [(lambda g, xx1=None:g.addV('vertex')), (lambda g, xx1=None:g.merge_v({}).option(Merge.on_match,xx1))], 'g_mergeV_hidden_label_key_matched_onMatch_matched_prohibited': [(lambda g, xx1=None:g.addV('vertex')), (lambda g, xx1=None:g.merge_v({}).option(Merge.on_match,xx1))], 'g_mergeV_hidden_label_key_onMatch_matched_prohibited': [(lambda g, xx1=None:g.merge_v({}).option(Merge.on_match,xx1))], + 'g_injectXlist1_list2X_mergeVXlimitXlocal_1XX_optionXonCreate_rangeXlocal_1_2X_optionXonMatch_tailXlocalXX_to_match': [(lambda g, xx1=None,xx2=None:g.addV('person').property('name','marko').property('age',29)), (lambda g, xx1=None,xx2=None:g.inject(xx1,xx1,xx2).fold().merge_v(__.limit(Scope.local,1)).option(Merge.on_create,__.range_(Scope.local,1,2)).option(Merge.on_match,__.tail(Scope.local))), (lambda g, xx1=None,xx2=None:g.V().has('person','name','marko').has('created','N')), (lambda g, xx1=None,xx2=None:g.V())], + 'g_injectXlist1_list2X_mergeVXlimitXlocal_1XX_optionXonCreate_rangeXlocal_1_2X_optionXonMatch_tailXlocalXX_to_create': [(lambda g, xx1=None,xx2=None:g.addV('person').property('name','marko').property('age',29)), (lambda g, xx1=None,xx2=None:g.inject(xx1,xx1,xx2).fold().merge_v(__.limit(Scope.local,1)).option(Merge.on_create,__.range_(Scope.local,1,2)).option(Merge.on_match,__.tail(Scope.local))), (lambda g, xx1=None,xx2=None:g.V().has('person','name','stephen').hasNot('created')), (lambda g, xx1=None,xx2=None:g.V())], 'g_V_age_min': [(lambda g:g.V().age.min_())], 'g_V_foo_min': [(lambda g:g.V().foo.min_())], 'g_V_name_min': [(lambda g:g.V().name.min_())], diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/MergeEdge.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/MergeEdge.feature index 6186d68f586..6991799668a 100644 --- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/MergeEdge.feature +++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/MergeEdge.feature @@ -857,11 +857,7 @@ Feature: Step - mergeE() option(Merge.onMatch, __.sideEffect(__.property("weight", 0)).constant([:])) """ When iterated to list - Then the result should have a count of 2 - And the graph should return 2 for count of "g.V()" - And the graph should return 0 for count of "g.E().hasLabel(\"knows\").has(\"weight\",1)" - And the graph should return 1 for count of "g.E().hasLabel(\"knows\").has(\"weight\",0)" - And the graph should return 0 for count of "g.V().has(\"weight\")" + Then the traversal will raise an error with message containing text of "The incoming traverser for MergeEdgeStep cannot be an Element" Scenario: g_mergeEXlabel_knows_out_marko_in_vadasX_optionXonMatch_sideEffectXpropertyXweight_0XX_constantXemptyXX Given the empty graph @@ -882,4 +878,73 @@ Feature: Step - mergeE() And the graph should return 2 for count of "g.V()" And the graph should return 0 for count of "g.E().hasLabel(\"knows\").has(\"weight\",1)" And the graph should return 1 for count of "g.E().hasLabel(\"knows\").has(\"weight\",0)" - And the graph should return 0 for count of "g.V().has(\"weight\")" \ No newline at end of file + And the graph should return 0 for count of "g.V().has(\"weight\")" + + Scenario: g_injectXlist1_list2X_mergeEXlimitXlocal_1XX_optionXonCreate_rangeXlocal_1_2XX_optionXonMatch_tailXlocalXX_to_match + Given the empty graph + And the graph initializer of + """ + g.addV("person").property("name", "marko").property("age", 29).as("marko"). + addV("person").property("name", "vadas").property("age", 27).as("vadas"). + addV("software").property("name", "lop").property("lang", "java").as("lop"). + addV("person").property("name","josh").property("age", 32).as("josh"). + addV("software").property("name", "ripple").property("lang", "java").as("ripple"). + addV("person").property("name", "peter").property("age", 35).as('peter'). + addE("knows").from("marko").to("vadas").property("weight", 0.5d). + addE("knows").from("marko").to("josh").property("weight", 1.0d). + addE("created").from("marko").to("lop").property("weight", 0.4d). + addE("created").from("josh").to("ripple").property("weight", 1.0d). + addE("created").from("josh").to("lop").property("weight", 0.4d). + addE("created").from("peter").to("lop").property("weight", 0.2d) + """ + And using the parameter xx1 defined as "m[{\"t[label]\": \"knows\", \"D[OUT]\":\"v[marko]\", \"D[IN]\":\"v[vadas]\"}]" + And using the parameter xx2 defined as "m[{\"created\": \"N\"}]" + And the traversal of + """ + g.inject(xx1, xx1, xx2). + fold(). + mergeE(__.limit(Scope.local,1)). + option(Merge.onCreate, __.range(Scope.local, 1, 2)). + option(Merge.onMatch, __.tail(Scope.local)) + """ + When iterated to list + Then the result should have a count of 1 + And the graph should return 6 for count of "g.V()" + And the graph should return 6 for count of "g.E()" + And the graph should return 1 for count of "g.E().has(\"created\",\"N\")" + And the graph should return 1 for count of "g.V().has(\"person\",\"name\",\"marko\").outE(\"knows\").has(\"created\",\"N\").inV().has(\"person\",\"name\",\"vadas\")" + + Scenario: g_injectXlist1_list2X_mergeEXlimitXlocal_1XX_optionXonCreate_rangeXlocal_1_2XX_optionXonMatch_tailXlocalXX_to_create + Given the empty graph + And the graph initializer of + """ + g.addV("person").property("name", "marko").property("age", 29).as("marko"). + addV("person").property("name", "vadas").property("age", 27).as("vadas"). + addV("software").property("name", "lop").property("lang", "java").as("lop"). + addV("person").property("name","josh").property("age", 32).as("josh"). + addV("software").property("name", "ripple").property("lang", "java").as("ripple"). + addV("person").property("name", "peter").property("age", 35).as('peter'). + addE("knows").from("marko").to("vadas").property("weight", 0.5d). + addE("knows").from("marko").to("josh").property("weight", 1.0d). + addE("created").from("marko").to("lop").property("weight", 0.4d). + addE("created").from("josh").to("ripple").property("weight", 1.0d). + addE("created").from("josh").to("lop").property("weight", 0.4d). + addE("created").from("peter").to("lop").property("weight", 0.2d) + """ + And using the parameter xx1 defined as "m[{\"t[label]\": \"self\", \"D[OUT]\":\"v[vadas]\", \"D[IN]\":\"v[vadas]\"}]" + And using the parameter xx2 defined as "m[{\"created\": \"N\"}]" + And the traversal of + """ + g.inject(xx1, xx1, xx2). + fold(). + mergeE(__.limit(Scope.local,1)). + option(Merge.onCreate, __.range(Scope.local, 1, 2)). + option(Merge.onMatch, __.tail(Scope.local)) + """ + When iterated to list + Then the result should have a count of 1 + And the graph should return 6 for count of "g.V()" + And the graph should return 7 for count of "g.E()" + And the graph should return 7 for count of "g.E().hasNot(\"created\")" + And the graph should return 1 for count of "g.V().has(\"person\",\"name\",\"marko\").outE(\"knows\").hasNot(\"created\").inV().has(\"person\",\"name\",\"vadas\")" + And the graph should return 1 for count of "g.V().has(\"person\",\"name\",\"vadas\").outE(\"self\").hasNot('weight').inV().has(\"person\",\"name\",\"vadas\")" \ No newline at end of file diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/MergeVertex.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/MergeVertex.feature index a0967bf9ef8..175fc44b42f 100644 --- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/MergeVertex.feature +++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/MergeVertex.feature @@ -654,9 +654,7 @@ Feature: Step - mergeV() option(Merge.onMatch, __.sideEffect(__.properties("age").drop()).select("m")) """ When iterated to list - Then the result should have a count of 1 - And the graph should return 1 for count of "g.V().has(\"person\",\"name\",\"marko\").has(\"age\", 19)" - And the graph should return 1 for count of "g.V().has(\"person\",\"name\",\"marko\").has(\"age\")" + Then the traversal will raise an error with message containing text of "The incoming traverser for MergeVertexStep cannot be an Element" # onCreate inheritance from merge @UserSuppliedVertexIds @@ -838,3 +836,45 @@ Feature: Step - mergeV() """ When iterated to list Then the traversal will raise an error with message containing text of "Property key can not be a hidden key: ~label" + + Scenario: g_injectXlist1_list2X_mergeVXlimitXlocal_1XX_optionXonCreate_rangeXlocal_1_2X_optionXonMatch_tailXlocalXX_to_match + Given the empty graph + And the graph initializer of + """ + g.addV("person").property("name", "marko").property("age", 29) + """ + And using the parameter xx1 defined as "m[{\"t[label]\": \"person\", \"name\":\"marko\"}]" + And using the parameter xx2 defined as "m[{\"created\": \"N\"}]" + And the traversal of + """ + g.inject(xx1, xx1, xx2). + fold(). + mergeV(__.limit(Scope.local,1)). + option(Merge.onCreate, __.range(Scope.local, 1, 2)). + option(Merge.onMatch, __.tail(Scope.local)) + """ + When iterated to list + Then the result should have a count of 1 + And the graph should return 1 for count of "g.V().has(\"person\",\"name\",\"marko\").has(\"created\",\"N\")" + And the graph should return 1 for count of "g.V()" + + Scenario: g_injectXlist1_list2X_mergeVXlimitXlocal_1XX_optionXonCreate_rangeXlocal_1_2X_optionXonMatch_tailXlocalXX_to_create + Given the empty graph + And the graph initializer of + """ + g.addV("person").property("name", "marko").property("age", 29) + """ + And using the parameter xx1 defined as "m[{\"t[label]\": \"person\", \"name\":\"stephen\"}]" + And using the parameter xx2 defined as "m[{\"created\": \"N\"}]" + And the traversal of + """ + g.inject(xx1, xx1, xx2). + fold(). + mergeV(__.limit(Scope.local,1)). + option(Merge.onCreate, __.range(Scope.local, 1, 2)). + option(Merge.onMatch, __.tail(Scope.local)) + """ + When iterated to list + Then the result should have a count of 1 + And the graph should return 1 for count of "g.V().has(\"person\",\"name\",\"stephen\").hasNot(\"created\")" + And the graph should return 2 for count of "g.V()" \ No newline at end of file From dd7cb2466986b9a2665ee6f3bdc917e76c9f691e Mon Sep 17 00:00:00 2001 From: Cole-Greer Date: Fri, 22 Mar 2024 13:57:16 -0700 Subject: [PATCH 18/18] CTR touchup docs and comments --- CHANGELOG.asciidoc | 2 +- .../gremlin/process/traversal/step/map/MergeVertexStep.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index b813d15ae77..eceb847c172 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -29,7 +29,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima * Fixed bug in bytecode translation of `g.tx().commit()` and `g.tx().rollback()` in all languages. * Improved error message from `JavaTranslator` by including exception source. * Added missing `short` serialization (`gx:Int16`) to GraphSONV2 and GraphSONV3 in `gremlin-python`. -* Added tests for error handling for GLV's if `tx.commit()`` is called remotely for graphs without transactions support. +* Added tests for error handling for GLV's if `tx.commit()` is called remotely for graphs without transactions support. * Introduced multi-architecture AMD64/ARM64 docker images for gremlin-console. * Fixed bug in `JavaTranslator` where `has(String, null)` could call `has(String, Traversal)` to generate an error. * Fixed issue where server errors weren't being properly parsed when sending bytecode over HTTP. 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 132adf3e7c8..70eca71f649 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 @@ -93,10 +93,10 @@ protected Iterator flatMap(final Traverser.Admin traverser) { // attach the onMatch properties vertices = IteratorUtils.peek(vertices, v -> { - // override current traverser with the matched Edge so that the option() traversal can operate + // override current traverser with the matched Vertex so that the option() traversal can operate // on it properly. this should only work this way for the start step form to retain the original // behavior for 3.6.0 where you might do g.inject(Map).mergeV() and want that Map to pass through. - // in 4.x this will be rectified such that the edge will always be promoted and you will be forced + // in 4.x this will be rectified such that the vertex will always be promoted and you will be forced // to select() the map if you did want the behavior. if (isStart) traverser.set((S) v);