You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by xi...@apache.org on 2026/06/05 05:22:44 UTC
(tinkerpop) branch steps-taking-traversal-poc updated (7bdcb80ef6 -> 4a7f23e52c)
This is an automated email from the ASF dual-hosted git repository.
xiazcy pushed a change to branch steps-taking-traversal-poc
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
discard 7bdcb80ef6 clean up & refactors
discard 0c2a39dc17 update within() to take first result
discard 7456bf6389 add hasLabel(Traversal)
discard 7d30d4c367 update to restrict mutations in all traversal taking steps.
discard 0acca58ff5 update to implement where(P)
discard cafd013d9e add compile time check & strategy verification to prevent child traversal mutating steps
discard a974a8eb2c Add error throwing for mixed cases instead of silent failure
discard 80ca229e10 Add optimizations into has and P
discard fe7f83bd0c allow V()/E() start steps to take traversals by generating a false traverser like mergeV/mergeE
discard 60ba191a86 use P.eq() semantics instead of P.with() for has(key, traversal)
discard 89260d5ab3 Add support in GLVs for steps taking traversals
discard 49d462b1c4 Add multi-traversal within()/without() support, fix HasContainer folding to continue past traversal-bearing steps, and reject V(traversal)/E(traversal) at parse time for start steps
discard ea5778834b Add traversal-accepting arguments to has(), V(), E(), property(), is(), and predicates.
add 9eca2f5b31 [TINKERPOP-3249] Remove sparql-gremlin (#3426)
add c1e7b6afcb Refactor JS CI jobs to use matrix strategy and add Node 26 (#3425)
add 6d0e2c259d Merge branch '3.7-dev' into 3.8-dev
add 7175989121 Merge branch '3.8-dev'
add d396815e4c TINKERPOP-3244 Add NextN(n) to Traversal in gremlin-go
add ec32b0c4d5 TINKERPOP-3244 Wire NextN(n) into Go translators and document divergence
add 584ada5d4d TINKERPOP-3244 Mention Go translator updates in CHANGELOG entry
add a28cd1f2f1 Merge branch 'master' into improvement/TINKERPOP-3244-go-next-n
add 40fa3ef90d [TINKERPOP-3244] Add NextN(n) to Traversal in gremlin-go (#3416)
add c11d71b30d Add streaming HTTP response support to gremlin-driver (#3419)
add cf0118a45c Add typed numeric wrappers and precise number mode to gremlin-javascript (#3427)
add d129283e08 Fix Flaky .Net and server tests (#3431)
add 8e49072e9f Fixed issues with dangling docker infrastructure (#3435)
add ec6830fadd [INFRA] Set up default rulesets for default and release branches (#3429)
add 86a0612c85 Fix port binding race between sequential GLV integration test runs
add 06da5d4485 Enable autocommit in GremlinServer (#3423)
add 8f88bba804 Subgraph support for GLVs (#3428)
add 0afea960b9 Added to .gitignore CTR
new 9a3a9ed92b Add traversal-accepting arguments to has(), V(), E(), property(), is(), and predicates.
new a9b52b44c6 Add multi-traversal within()/without() support, fix HasContainer folding to continue past traversal-bearing steps, and reject V(traversal)/E(traversal) at parse time for start steps
new b1b02894f6 Add support in GLVs for steps taking traversals
new 8e87651de4 use P.eq() semantics instead of P.with() for has(key, traversal)
new a9d1f64217 allow V()/E() start steps to take traversals by generating a false traverser like mergeV/mergeE
new d8dd2ae0de Add optimizations into has and P
new 96e921c5ea Add error throwing for mixed cases instead of silent failure
new 433c2e4e3e add compile time check & strategy verification to prevent child traversal mutating steps
new 6aac8a0401 update to implement where(P)
new 0b6985881e update to restrict mutations in all traversal taking steps.
new 5c53f98e67 add hasLabel(Traversal)
new 54e04f6d2f update within() to take first result
new eee4d8192b clean up & refactors
new 4a7f23e52c restrict P(Traversal) in union()
This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version. This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:
* -- * -- B -- O -- O -- O (7bdcb80ef6)
\
N -- N -- N refs/heads/steps-taking-traversal-poc (4a7f23e52c)
You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.
Any revisions marked "omit" are not gone; other references still
refer to them. Any revisions marked "discard" are gone forever.
The 14 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.asf.yaml | 14 +-
.github/workflows/build-test.yml | 40 +-
.gitignore | 1 +
CHANGELOG.asciidoc | 6 +
docs/preprocessor/install-plugins.sh | 2 +-
docs/site/home/community.html | 4 -
docs/src/dev/provider/index.asciidoc | 28 +-
docs/src/reference/compilers.asciidoc | 440 -----------------
docs/src/reference/gremlin-applications.asciidoc | 22 +-
docs/src/reference/gremlin-variants.asciidoc | 116 ++++-
docs/src/reference/index.asciidoc | 1 -
docs/src/reference/intro.asciidoc | 3 +-
docs/src/reference/the-traversal.asciidoc | 10 +-
docs/src/upgrade/release-4.x.x.asciidoc | 75 +++
.../language/translator/GoTranslateVisitor.java | 13 +
.../traversal/dsl/graph/GraphTraversal.java | 8 +
.../structure/io/graphson/GraphSONModule.java | 17 +-
.../gremlin/structure/io/gryo/GryoVersion.java | 3 +-
.../language/translator/GremlinTranslatorTest.java | 2 +-
gremlin-dotnet/src/Gremlin.Net/Structure/Graph.cs | 17 +
.../Structure/IO/GraphBinary4/DataType.cs | 3 +-
.../IO/GraphBinary4/TypeSerializerRegistry.cs | 2 +
.../IO/GraphBinary4/Types/GraphSerializer.cs | 225 +++++++++
.../Driver/PropertyDeserializationTests.cs | 5 +
.../Gherkin/CommonSteps.cs | 58 +++
.../Gherkin/GherkinTestRunner.cs | 14 +-
.../Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs | 7 +-
.../Gherkin/IgnoreException.cs | 5 -
.../DriverRemoteConnection/GraphTraversalTests.cs | 1 +
.../IO/GraphBinary4/GraphSerializerTests.cs | 127 +++++
gremlin-dotnet/test/pom.xml | 55 +--
.../tinkerpop/gremlin/driver/Channelizer.java | 44 +-
.../apache/tinkerpop/gremlin/driver/Cluster.java | 18 +
.../tinkerpop/gremlin/driver/Connection.java | 23 +-
.../tinkerpop/gremlin/driver/ConnectionPool.java | 1 +
.../driver/handler/GremlinResponseHandler.java | 21 +-
.../handler/HttpStreamingResponseHandler.java | 242 ++++++++++
.../driver/stream/ByteBufQueueInputStream.java | 137 ++++++
.../stream/GraphBinaryStreamResponseReader.java | 105 +++++
.../gremlin/driver/stream/InputStreamBuffer.java | 311 ++++++++++++
.../handler/ByteBufQueueInputStreamTest.java | 95 ++++
.../GraphBinaryStreamResponseReaderTest.java | 226 +++++++++
.../handler/HttpStreamingResponseHandlerTest.java | 207 ++++++++
.../driver/handler/InputStreamBufferTest.java | 94 ++++
gremlin-go/driver/cucumber/cucumberSteps_test.go | 83 +++-
gremlin-go/driver/cucumber/gremlin.go | 7 +-
gremlin-go/driver/graph.go | 17 +
gremlin-go/driver/graphBinaryDeserializer.go | 187 ++++++++
gremlin-go/driver/graphBinarySerializer.go | 143 ++++++
gremlin-go/driver/graphBinarySerializer_test.go | 184 ++++++++
gremlin-go/driver/graph_test.go | 18 +
gremlin-go/driver/serializer.go | 1 +
gremlin-go/driver/traversal.go | 25 +
gremlin-go/driver/traversal_test.go | 117 +++++
gremlin-go/pom.xml | 55 +--
.../gremlin-javascript/lib/driver/connection.ts | 5 +-
gremlin-js/gremlin-javascript/lib/index.ts | 12 +
.../lib/language/translator/GoTranslateVisitor.ts | 12 +
.../gremlin-javascript/lib/process/gremlin-lang.ts | 26 +-
.../gremlin-javascript/lib/structure/graph.ts | 13 +-
.../lib/structure/io/binary/GraphBinary.js | 51 +-
.../structure/io/binary/internals/AnySerializer.js | 12 +-
.../io/binary/internals/GraphSerializer.js | 225 +++++++++
.../internals/NumberSerializationStrategy.js | 34 +-
gremlin-js/gremlin-javascript/lib/utils.ts | 156 +++++-
gremlin-js/gremlin-javascript/pom.xml | 56 +--
.../test/cucumber/feature-steps.js | 54 ++-
.../gremlin-javascript/test/cucumber/gremlin.js | 7 +-
gremlin-js/gremlin-javascript/test/helper.js | 2 +
.../test/integration/client-tests.js | 33 +-
.../gremlin-javascript/test/unit/exports-test.js | 13 +
.../test/unit/graph-serializer-test.js | 194 ++++++++
.../test/unit/graphbinary/precise-mode-test.js | 521 +++++++++++++++++++++
.../test/unit/graphbinary/typed-number-test.js | 212 +++++++++
.../test/unit/gremlin-lang-test.js | 134 +++++-
.../unit/translator/gremlin-translator-test.js | 3 +-
gremlin-python/pom.xml | 27 +-
.../main/python/gremlin_python/structure/graph.py | 2 +-
.../src/main/python/tests/feature/gremlin.py | 7 +-
.../main/python/tests/unit/structure/test_graph.py | 14 +
.../server/handler/HttpGremlinEndpointHandler.java | 51 +-
.../gremlin/server/handler/HttpHandlerUtil.java | 7 +
.../GremlinDriverTransactionIntegrateTest.java | 27 ++
.../server/GremlinServerHttpIntegrateTest.java | 91 +++-
.../GremlinServerHttpTransactionIntegrateTest.java | 14 +-
.../server/StreamingResponseIntegrateTest.java | 239 ++++++++++
.../gremlin/language/translator/translations.json | 77 +--
.../test/features/filter/IsTraversal.feature | 6 +-
.../gremlin/test/features/map/AsString.feature | 14 +-
pom.xml | 1 -
sparql-gremlin/pom.xml | 69 ---
.../apache/tinkerpop/gremlin/sparql/Prefixes.java | 65 ---
.../gremlin/sparql/SparqlToGremlinCompiler.java | 318 -------------
.../tinkerpop/gremlin/sparql/TraversalBuilder.java | 83 ----
.../gremlin/sparql/WhereTraversalBuilder.java | 128 -----
.../gremlin/sparql/jsr223/SparqlGremlinPlugin.java | 63 ---
.../dsl/sparql/DefaultSparqlTraversal.java | 55 ---
.../traversal/dsl/sparql/SparqlTraversal.java | 62 ---
.../dsl/sparql/SparqlTraversalSource.java | 182 -------
.../process/traversal/strategy/SparqlStrategy.java | 88 ----
...g.apache.tinkerpop.gremlin.jsr223.GremlinPlugin | 1 -
.../tinkerpop/gremlin/sparql/PrefixesTest.java | 67 ---
.../dsl/sparql/SparqlTraversalSourceTest.java | 189 --------
.../src/test/resources/logback-silent.xml | 26 -
sparql-gremlin/src/test/resources/logback-test.xml | 26 -
105 files changed, 5203 insertions(+), 2256 deletions(-)
delete mode 100644 docs/src/reference/compilers.asciidoc
create mode 100644 gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary4/Types/GraphSerializer.cs
create mode 100644 gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphBinary4/GraphSerializerTests.cs
create mode 100644 gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/HttpStreamingResponseHandler.java
create mode 100644 gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/stream/ByteBufQueueInputStream.java
create mode 100644 gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/stream/GraphBinaryStreamResponseReader.java
create mode 100644 gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/stream/InputStreamBuffer.java
create mode 100644 gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/handler/ByteBufQueueInputStreamTest.java
create mode 100644 gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/handler/GraphBinaryStreamResponseReaderTest.java
create mode 100644 gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/handler/HttpStreamingResponseHandlerTest.java
create mode 100644 gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/handler/InputStreamBufferTest.java
create mode 100644 gremlin-js/gremlin-javascript/lib/structure/io/binary/internals/GraphSerializer.js
create mode 100644 gremlin-js/gremlin-javascript/test/unit/graph-serializer-test.js
create mode 100644 gremlin-js/gremlin-javascript/test/unit/graphbinary/precise-mode-test.js
create mode 100644 gremlin-js/gremlin-javascript/test/unit/graphbinary/typed-number-test.js
create mode 100644 gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/StreamingResponseIntegrateTest.java
delete mode 100644 sparql-gremlin/pom.xml
delete mode 100644 sparql-gremlin/src/main/java/org/apache/tinkerpop/gremlin/sparql/Prefixes.java
delete mode 100644 sparql-gremlin/src/main/java/org/apache/tinkerpop/gremlin/sparql/SparqlToGremlinCompiler.java
delete mode 100644 sparql-gremlin/src/main/java/org/apache/tinkerpop/gremlin/sparql/TraversalBuilder.java
delete mode 100644 sparql-gremlin/src/main/java/org/apache/tinkerpop/gremlin/sparql/WhereTraversalBuilder.java
delete mode 100644 sparql-gremlin/src/main/java/org/apache/tinkerpop/gremlin/sparql/jsr223/SparqlGremlinPlugin.java
delete mode 100644 sparql-gremlin/src/main/java/org/apache/tinkerpop/gremlin/sparql/process/traversal/dsl/sparql/DefaultSparqlTraversal.java
delete mode 100644 sparql-gremlin/src/main/java/org/apache/tinkerpop/gremlin/sparql/process/traversal/dsl/sparql/SparqlTraversal.java
delete mode 100644 sparql-gremlin/src/main/java/org/apache/tinkerpop/gremlin/sparql/process/traversal/dsl/sparql/SparqlTraversalSource.java
delete mode 100644 sparql-gremlin/src/main/java/org/apache/tinkerpop/gremlin/sparql/process/traversal/strategy/SparqlStrategy.java
delete mode 100644 sparql-gremlin/src/main/resources/META-INF/services/org.apache.tinkerpop.gremlin.jsr223.GremlinPlugin
delete mode 100644 sparql-gremlin/src/test/java/org/apache/tinkerpop/gremlin/sparql/PrefixesTest.java
delete mode 100644 sparql-gremlin/src/test/java/org/apache/tinkerpop/gremlin/sparql/process/traversal/dsl/sparql/SparqlTraversalSourceTest.java
delete mode 100644 sparql-gremlin/src/test/resources/logback-silent.xml
delete mode 100644 sparql-gremlin/src/test/resources/logback-test.xml
(tinkerpop) 03/14: Add support in GLVs for steps taking traversals
Posted by xi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
xiazcy pushed a commit to branch steps-taking-traversal-poc
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit b1b02894f6e6f9af8de70588a2e8f5aee523ddfa
Author: Yang Xia <xi...@gmail.com>
AuthorDate: Wed May 20 10:14:28 2026 -0700
Add support in GLVs for steps taking traversals
---
.../translator/DotNetTranslateVisitor.java | 43 +++++++++++++++
.../Process/Traversal/GraphTraversal.cs | 10 ++++
.../Gremlin.Net/Process/Traversal/GremlinLang.cs | 13 ++++-
.../src/Gremlin.Net/Process/Traversal/P.cs | 10 ++++
.../src/Gremlin.Net/Process/Traversal/TextP.cs | 30 +++++++++++
.../src/Gremlin.Net/Process/Traversal/__.cs | 9 ++++
.../Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs | 62 +++++++++++++++-------
gremlin-go/driver/cucumber/gremlin.go | 62 +++++++++++++++-------
gremlin-go/driver/gremlinlang.go | 19 ++++++-
.../language/translator/DotNetTranslateVisitor.ts | 39 ++++++++++++++
.../gremlin-javascript/lib/process/gremlin-lang.ts | 9 +++-
.../gremlin-javascript/lib/process/traversal.ts | 6 +++
.../gremlin-javascript/test/cucumber/gremlin.js | 62 +++++++++++++++-------
.../python/gremlin_python/process/traversal.py | 27 +++++++---
.../src/main/python/tests/feature/gremlin.py | 62 +++++++++++++++-------
.../gremlin/language/translator/translations.json | 10 ++--
16 files changed, 385 insertions(+), 88 deletions(-)
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/DotNetTranslateVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/DotNetTranslateVisitor.java
index 11546c6ca2..7ce385c925 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/DotNetTranslateVisitor.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/DotNetTranslateVisitor.java
@@ -962,6 +962,49 @@ public class DotNetTranslateVisitor extends AbstractTranslateVisitor {
return handleGenerics(ctx);
}
+ @Override
+ public Void visitTraversalMethod_property_Object(final GremlinParser.TraversalMethod_property_ObjectContext ctx) {
+ // Property(null) is ambiguous with Property(ITraversal) — cast null to IDictionary to disambiguate
+ if (ctx.genericMapNullableArgument().genericMapNullableLiteral() != null &&
+ ctx.genericMapNullableArgument().genericMapNullableLiteral().nullLiteral() != null) {
+ visit(ctx.getChild(0));
+ sb.append("(");
+ sb.append("(IDictionary<object, object>) ");
+ visit(ctx.genericMapNullableArgument());
+ sb.append(")");
+ return null;
+ }
+ return super.visitTraversalMethod_property_Object(ctx);
+ }
+
+ @Override
+ public Void visitTraversalMethod_property_Cardinality_Object(final GremlinParser.TraversalMethod_property_Cardinality_ObjectContext ctx) {
+ // Property(Cardinality, null) — cast null to IDictionary to disambiguate
+ if (ctx.genericMapNullableArgument().genericMapNullableLiteral() != null &&
+ ctx.genericMapNullableArgument().genericMapNullableLiteral().nullLiteral() != null) {
+ visit(ctx.getChild(0));
+ sb.append("(");
+ visit(ctx.traversalCardinality());
+ sb.append(", ");
+ sb.append("(IDictionary<object, object>) ");
+ visit(ctx.genericMapNullableArgument());
+ sb.append(")");
+ return null;
+ }
+ return super.visitTraversalMethod_property_Cardinality_Object(ctx);
+ }
+
+ @Override
+ public Void visitTraversalMethod_property_Traversal(final GremlinParser.TraversalMethod_property_TraversalContext ctx) {
+ // Property(ITraversal) — cast to ITraversal to disambiguate
+ visit(ctx.getChild(0));
+ sb.append("(");
+ sb.append("(ITraversal) ");
+ visit(ctx.nestedTraversal());
+ sb.append(")");
+ return null;
+ }
+
@Override
public Void visitTraversalMethod_property_Cardinality_Object_Object_Object(final GremlinParser.TraversalMethod_property_Cardinality_Object_Object_ObjectContext ctx) {
if (ctx.genericArgumentVarargs() == null || ctx.genericArgumentVarargs().getChildCount() == 0) {
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs
index de01df3367..5f5852ec1d 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs
@@ -1825,6 +1825,16 @@ namespace Gremlin.Net.Process.Traversal
return Wrap<TStart, TEnd>(this);
}
+ /// <summary>
+ /// Adds the property step with a map-producing traversal to this <see cref="GraphTraversal{SType, EType}" />.
+ /// The traversal must produce a Map whose entries become properties on the element.
+ /// </summary>
+ public GraphTraversal<TStart, TEnd> Property(ITraversal propertyTraversal)
+ {
+ GremlinLang.AddStep("property", propertyTraversal);
+ return Wrap<TStart, TEnd>(this);
+ }
+
/// <summary>
/// Adds the propertyMap step to this <see cref="GraphTraversal{SType, EType}" />.
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GremlinLang.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GremlinLang.cs
index 21115a8f8f..0425f99a29 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GremlinLang.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GremlinLang.cs
@@ -25,6 +25,7 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
+using System.Linq;
using System.Numerics;
using System.Text;
using Gremlin.Net.Process.Traversal.Strategy;
@@ -417,11 +418,21 @@ namespace Gremlin.Net.Process.Traversal
}
else if (p.Value is IList listVal && (p.OperatorName == "within" || p.OperatorName == "without"))
{
- // within/without with a list value - render as [e1,e2,...]
+ // within/without with a list value
if (listVal.Count == 0)
{
// empty within() - no brackets
}
+ else if (listVal.Cast<object>().All(v => v is ITraversal))
+ {
+ // All elements are traversals - serialize as comma-separated args (no brackets)
+ // This matches the server grammar: within(trav1, trav2) via genericArgumentVarargs
+ for (int i = 0; i < listVal.Count; i++)
+ {
+ if (i > 0) sb.Append(',');
+ sb.Append(ArgAsString(listVal[i]));
+ }
+ }
else
{
sb.Append('[');
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/P.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/P.cs
index fe33aec3e8..18f827a7ea 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/P.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/P.cs
@@ -157,12 +157,22 @@ namespace Gremlin.Net.Process.Traversal
public static P Within(params object[]? args)
{
+ if (args is { Length: 1 } && args[0] is ITraversal)
+ return new P("within", args[0]);
+ // Multiple traversals - store as list preserving ITraversal type for serializer detection
+ if (args is { Length: > 1 } && args.All(a => a is ITraversal))
+ return new P("within", new List<object>(args));
var x = args is { Length: 1 } && args[0] is ICollection collection ? collection : args;
return new P("within", ToGenericList(x));
}
public static P Without(params object[]? args)
{
+ if (args is { Length: 1 } && args[0] is ITraversal)
+ return new P("without", args[0]);
+ // Multiple traversals - store as list preserving ITraversal type for serializer detection
+ if (args is { Length: > 1 } && args.All(a => a is ITraversal))
+ return new P("without", new List<object>(args));
var x = args is { Length: 1 } && args[0] is ICollection collection ? collection : args;
return new P("without", ToGenericList(x));
}
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/TextP.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/TextP.cs
index cc94f34681..8b0d81e134 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/TextP.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/TextP.cs
@@ -51,31 +51,61 @@ namespace Gremlin.Net.Process.Traversal
return new TextP("containing", value);
}
+ public static P Containing(object value)
+ {
+ return new P("containing", value);
+ }
+
public static TextP EndingWith(string value)
{
return new TextP("endingWith", value);
}
+ public static P EndingWith(object value)
+ {
+ return new P("endingWith", value);
+ }
+
public static TextP NotContaining(string value)
{
return new TextP("notContaining", value);
}
+ public static P NotContaining(object value)
+ {
+ return new P("notContaining", value);
+ }
+
public static TextP NotEndingWith(string value)
{
return new TextP("notEndingWith", value);
}
+ public static P NotEndingWith(object value)
+ {
+ return new P("notEndingWith", value);
+ }
+
public static TextP NotStartingWith(string value)
{
return new TextP("notStartingWith", value);
}
+ public static P NotStartingWith(object value)
+ {
+ return new P("notStartingWith", value);
+ }
+
public static TextP StartingWith(string value)
{
return new TextP("startingWith", value);
}
+ public static P StartingWith(object value)
+ {
+ return new P("startingWith", value);
+ }
+
public static TextP Regex(string value)
{
return new TextP("regex", value);
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs
index b16732a61b..3ccccdd839 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs
@@ -1256,6 +1256,15 @@ namespace Gremlin.Net.Process.Traversal
return new GraphTraversal<object, object>().Property(map);
}
+ /// <summary>
+ /// Spawns a <see cref="GraphTraversal{SType, EType}" /> and adds the property step with a
+ /// map-producing traversal to that traversal.
+ /// </summary>
+ public static GraphTraversal<object, object> Property(ITraversal propertyTraversal)
+ {
+ return new GraphTraversal<object, object>().Property(propertyTraversal);
+ }
+
/// <summary>
/// Spawns a <see cref="GraphTraversal{SType, EType}" /> and adds the propertyMap step to that traversal.
/// </summary>
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
index 7588da5935..e349b0f622 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
@@ -535,7 +535,6 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
{"g_V_hasXname_VXvid1X_valuesXnameXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name", __.V(p["vid1"]).Values<object>("name"))}},
{"g_V_hasXname_VXvid1X_outXknowsX_valuesXnameXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name", __.V(p["vid1"]).Out("knows").Values<object>("name"))}},
{"g_V_hasXage_VXvid1X_outXknowsX_valuesXageXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("age", __.V(p["vid1"]).Out("knows").Values<object>("age"))}},
- {"g_V_hasXname_VXvid1X_outXcreatedX_valuesXnameXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name", __.V(p["vid1"]).Out("created").Values<object>("name"))}},
{"g_V_hasXname_VXvid1X_valuesXnonexistentXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name", __.V(p["vid1"]).Values<object>("nonexistent"))}},
{"g_V_hasXname_notXidentityXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name", __.Not(__.Identity()))}},
{"g_V_hasXage_gtXVXvid1X_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("age", P.Gt(__.V(p["vid1"]).Values<object>("age")))}},
@@ -547,6 +546,14 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
{"g_V_hasXage_eqXVXvid1X_valuesXnonexistentXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("age", P.Eq(__.V(p["vid1"]).Values<object>("nonexistent")))}},
{"g_V_hasXlabel_VXvid1X_labelXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has(T.Label, __.V(p["vid1"]).Label())}},
{"g_V_hasXperson_name_VXvid1X_valuesXnameXX_age", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("person", "name", __.V(p["vid1"]).Values<object>("name")).Values<object>("age")}},
+ {"g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_constantXpeterXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name", P.Within(__.V(p["vid1"]).Out("knows").Values<object>("name"), __.Constant<object>("peter")))}},
+ {"g_V_hasXname_withinXVXvid1X_valuesXnonexistentX_constantXmarkoXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name", P.Within(__.V(p["vid1"]).Values<object>("nonexistent"), __.Constant<object>("marko")))}},
+ {"g_V_hasXname_withinXVXvid1X_valuesXnonexistentX_VXvid1X_valuesXnonexistentXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name", P.Within(__.V(p["vid1"]).Values<object>("nonexistent"), __.V(p["vid1"]).Values<object>("nonexistent")))}},
+ {"g_V_hasXname_withoutXVXvid1X_valuesXnameX_VXvid2X_valuesXnameX_VXvid3X_valuesXnameXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name", P.Without(__.V(p["vid1"]).Values<object>("name"), __.V(p["vid2"]).Values<object>("name"), __.V(p["vid3"]).Values<object>("name")))}},
+ {"g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name", P.Within(__.V(p["vid1"]).Out("knows").Values<object>("name"), __.V(p["vid3"]).Out("created").Values<object>("name")))}},
+ {"g_V_hasLabelXsoftwareX_hasXname_withoutXVXvid1X_outXcreatedX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("software").Has("name", P.Without(__.V(p["vid1"]).Out("created").Values<object>("name"), __.V(p["vid3"]).Out("created").Values<object>("name")))}},
+ {"g_V_hasLabelXpersonX_valuesXageX_isXwithinXVXvid1X_valuesXageX_V_hasXname_lopX_inXcreatedX_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Values<object>("age").Is(P.Within(__.V(p["vid1"]).Values<object>("age"), __.V().Has("name", "lop").In("created").Values<object>("age")))}},
+ {"g_VXvid1X_outEXknowsX_filterXinV_hasXname_withinXV_hasXname_lopX_inXcreatedX_valuesXnameX_V_hasXname_rippleX_inXcreatedX_valuesXnameXXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).OutE("knows").Filter(__.InV().Has("name", P.Within(__.V().Has("name", "lop").In("created").Values<object>("name"), __.V().Has("name", "ripple").In("created").Values<object>("name"))))}},
{"g_V_properties_hasValueXnullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Properties<object>().HasValue((object) null)}},
{"g_V_properties_hasValueXnull_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Properties<object>().HasValue(null, null)}},
{"g_V_properties_hasValueXnull_joshX_value", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Properties<object>().HasValue(null, "josh").Value<object>()}},
@@ -558,6 +565,26 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
{"g_V_valuesXageX_isXgte_29vaarX_isXlt_34varX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Is(P.Gte(p["xx1"])).Is(P.Lt(p["xx2"]))}},
{"g_V_whereXinXcreatedX_count_isX1XX_valuesXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Where(__.In("created").Count().Is(1)).Values<object>("name")}},
{"g_V_whereXinXcreatedX_count_isXgte_2XX_valuesXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Where(__.In("created").Count().Is(P.Gte(2))).Values<object>("name")}},
+ {"g_V_valuesXageX_isXVXvid1X_valuesXageXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Is(__.V(p["vid1"]).Values<object>("age"))}},
+ {"g_V_valuesXnameX_isXVXvid1X_valuesXnameXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name").Is(__.V(p["vid1"]).Values<object>("name"))}},
+ {"g_V_valuesXageX_isXgtXVXvid1X_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Is(P.Gt(__.V(p["vid1"]).Values<object>("age")))}},
+ {"g_V_valuesXageX_isXltXVXvid3X_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Is(P.Lt(__.V(p["vid3"]).Values<object>("age")))}},
+ {"g_V_valuesXageX_isXneqXVXvid4X_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Is(P.Neq(__.V(p["vid4"]).Values<object>("age")))}},
+ {"g_V_valuesXageX_isXwithinXVXvid1X_outXknowsX_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Is(P.Within(__.V(p["vid1"]).Out("knows").Values<object>("age")))}},
+ {"g_V_valuesXageX_isXVXvid1X_valuesXnonexistentXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Is(__.V(p["vid1"]).Values<object>("nonexistent"))}},
+ {"g_V_hasLabelXpersonX_valuesXageX_chooseXgtXVXvid1X_valuesXageXX_olderX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Values<object>("age").Choose<object>(P.Gt(__.V(p["vid1"]).Values<object>("age")), __.Constant<object>("older than marko"), __.Constant<object>("not older"))}},
+ {"g_V_hasLabelXpersonX_valuesXageX_chooseXgteXmeanAgeX_aboveX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Values<object>("age").Choose<object>(P.Gte(__.V().HasLabel("person").Values<object>("age").Mean<object>()), __.Constant<object>("above average"), __.Constant<object>("below average"))}},
+ {"g_VXvid1X_outXknowsX_valuesXageX_fold_allXgteXVXvid2X_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out("knows").Values<object>("age").Fold().All(P.Gte(__.V(p["vid2"]).Values<object>("age")))}},
+ {"g_VXvid1X_outXknowsX_valuesXageX_fold_allXgtXVXvid2X_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out("knows").Values<object>("age").Fold().All(P.Gt(__.V(p["vid2"]).Values<object>("age")))}},
+ {"g_VXvid1X_outXknowsX_valuesXageX_fold_anyXeqXVXvid3X_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out("knows").Values<object>("age").Fold().Any(P.Eq(__.V(p["vid3"]).Values<object>("age")))}},
+ {"g_VXvid1X_outXknowsX_valuesXageX_fold_noneXeqXVXvid4X_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out("knows").Values<object>("age").Fold().None(P.Eq(__.V(p["vid4"]).Values<object>("age")))}},
+ {"g_VXvid1X_outXknowsX_valuesXageX_fold_noneXeqXVXvid3X_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out("knows").Values<object>("age").Fold().None(P.Eq(__.V(p["vid3"]).Values<object>("age")))}},
+ {"g_injectXnullX_isXeqXV9999_valuesXnameXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(null).Is(P.Eq(__.V(9999).Values<object>("name")))}},
+ {"g_injectXmarkoX_isXV9999_valuesXnameXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>("marko").Is(__.V(9999).Values<object>("name"))}},
+ {"g_injectXmarkoX_chooseXeqXV9999_valuesXnameXX_matched_unmatchedX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>("marko").Choose<object>(P.Eq(__.V(9999).Values<object>("name")), __.Constant<object>("matched"), __.Constant<object>("unmatched"))}},
+ {"g_injectXlistX_noneXeqXV9999_valuesXnameXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(new List<object> { "marko", "josh" }).None(P.Eq(__.V(9999).Values<object>("name")))}},
+ {"g_V_hasXname_eqXV9999_valuesXnameXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name", P.Eq(__.V(9999).Values<object>("name")))}},
+ {"g_V_valuesXageX_isXwithoutXVXvid1X_valuesXageX_VXvid2X_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Is(P.Without(__.V(p["vid1"]).Values<object>("age"), __.V(p["vid2"]).Values<object>("age")))}},
{"g_V_valuesXageX_noneXgtX32XX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").None(P.Gt(32))}},
{"g_V_valuesXageX_whereXisXP_gtX33XXX_fold_noneXlteX33XX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Where(__.Is(P.Gt(33))).Fold().None(P.Lte(33))}},
{"g_V_valuesXageX_order_byXdescX_fold_noneXltX10XX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Order().By(Order.Desc).Fold().None(P.Lt(10))}},
@@ -1794,14 +1821,14 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
{"g_V_localXoutE_foldX_unfold", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Local<object>(__.OutE().Fold()).Unfold<object>()}},
{"g_V_valueMap_unfold_mapXselectXkeysXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ValueMap<object, object>().Unfold<object>().Map<object>(__.Select<object>(Column.Keys))}},
{"g_VX1X_repeatXboth_simplePathX_untilXhasIdX6XX_path_byXnameX_unfold", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Repeat(__.Both().SimplePath()).Until(__.HasId(p["vid6"])).Path().By("name").Unfold<object>()}},
- {"g_VXvid1X_outXcreatedX_asXsoftwareX_V_hasXname_selectXsoftwareX_valuesXnameXX_inXcreatedX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out("created").As("sw").V().Has("name", __.Select<object>("sw").Values<object>("name")).In("created").Values<object>("name")}},
+ {"g_VXvid1X_id_VXidentityX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Id().V(__.Identity()).Values<object>("name")}},
+ {"g_VXvid1_vid2X_id_VXidentityX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"], p["vid2"]).Id().V(__.Identity()).Values<object>("name")}},
+ {"g_VXvid1X_id_asXbookmarkX_V_hasXname_joshX_VXselectXbookmarkXX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Id().As("bookmark").V().Has("name", "josh").V(__.Select<object>("bookmark")).Values<object>("name")}},
{"g_VXvid1X_VXoutXknowsX_idX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).V(__.Out("knows").Id()).Values<object>("name")}},
- {"g_VXvid1X_VXoutXknowsX_hasXname_joshX_idX_valuesXageX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).V(__.Out("knows").Has("name", "josh").Id()).Values<object>("age")}},
- {"g_VXvid1X_VXoutXknowsX_outXknowsX_idX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).V(__.Out("knows").Out("knows").Id()).Values<object>("name")}},
- {"g_VXvid1X_VXoutXcreatedX_idX_valuesXlangX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).V(__.Out("created").Id()).Values<object>("lang")}},
{"g_VXvid1X_EXoutE_idX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).E(__.OutE().Id())}},
- {"g_VXvid1X_EXoutEXknowsX_hasXweight_05X_idX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).E(__.OutE("knows").Has("weight", 0.5d).Id())}},
- {"g_VXvid1X_EXoutXknowsX_outXknowsX_outE_idX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).E(__.Out("knows").Out("knows").OutE().Id())}},
+ {"g_injectX9999X_VXidentityX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(9999).V(__.Identity())}},
+ {"g_VXvid1X_outEXknowsX_hasXinV_name_vadasX_id_EXidentityX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).OutE("knows").Filter(__.InV().Has("name", "vadas")).Id().E(__.Identity())}},
+ {"g_injectX9999X_EXidentityX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(9999).E(__.Identity())}},
{"g_VXVXvid1X_idX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(__.V(p["vid1"]).Id()).Values<object>("name")}},
{"g_EXVXvid1X_outE_idX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E(__.V(p["vid1"]).OutE().Id())}},
{"g_V_valueMap", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ValueMap<object, object>()}},
@@ -2125,17 +2152,16 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
{"g_injectX1_3_100_300X_list", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(new List<object> { 1, 3, 100, 300 })}},
{"g_injectX1_3_100_300X_set", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(new HashSet<object> { 1, 3, 100, 300 })}},
{"g_injectX1_1X_set", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(new HashSet<object> { 1, 1 })}},
- {"g_VXvid2X_propertyXalias_VXvid1X_valuesXnameXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid2"]).Property("alias", __.V(p["vid1"]).Values<object>("name")), (g,p) =>g.V().Has("alias", "marko")}},
- {"g_VXvid1X_propertyXcreatorCount_VXvid1X_inXcreatedX_countX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Property("creatorCount", __.V(p["vid1"]).In("created").Count()), (g,p) =>g.V().Has("creatorCount", 3l)}},
- {"g_VXvid1X_propertyXknownCount_outXknowsX_countX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Property("knownCount", __.Out("knows").Count()), (g,p) =>g.V().Has("knownCount", 2l)}},
- {"g_VXvid1X_propertyXcreator_inXcreatedX_valuesXnameXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Property("creator", __.In("created").Values<object>("name")), (g,p) =>g.V().Has("creator")}},
- {"g_VXvid2X_propertyXVXvid1X_projectXfriendCount_softwareCreatedXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid2"]).Property(__.V(p["vid1"]).Project<object>("friendCount", "softwareCreated").By(__.Out("knows").Count()).By(__.Out("created").Values<object>("name"))), (g,p) =>g.V().Has("friendCount", 2l), (g,p) =>g.V().Has("softwareCreated", "lop")}},
- {"g_VXvid2X_propertyXVXvid1X_projectXoriginalName_originalLabelX_byXnameX_byXlabelXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid2"]).Property(__.V(p["vid1"]).Project<object>("originalName", "originalLabel").By(__.Values<object>("name")).By(__.Label())), (g,p) =>g.V(p["vid2"]).Has("originalName", "marko"), (g,p) =>g.V(p["vid2"]).Has("originalLabel", "person")}},
- {"g_VXvid1X_propertyXlist_friends_outXknowsX_valuesXnameXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Property(Cardinality.List, "friends", __.Out("knows").Values<object>("name")), (g,p) =>g.V(p["vid1"]).Properties<object>("friends")}},
- {"g_VXvid1X_propertyXlist_creators_inXcreatedX_valuesXnameXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Property(Cardinality.List, "creators", __.In("created").Values<object>("name")), (g,p) =>g.V(p["vid1"]).Properties<object>("creators")}},
- {"g_VXvid1X_propertyXset_langs_outXcreatedX_valuesXlangXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Property(Cardinality.Set, "langs", __.Out("created").Values<object>("lang")), (g,p) =>g.V(p["vid1"]).Properties<object>("langs")}},
- {"g_VXvid1X_propertyXsingle_friend_outXknowsX_valuesXnameXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Property(Cardinality.Single, "friend", __.Out("knows").Values<object>("name"))}},
- {"g_VXvid1X_propertyXVXvid1X_groupX_byXidX_byXvaluesXnameXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Property(__.V(p["vid1"]).Group<object, object>().By(__.Id()).By(__.Values<object>("name")))}},
+ {"g_VXvid2X_propertyXalias_VXvid1X_valuesXnameXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) "person").Property("name", "marko").Property("age", 29).AddV((string) "person").Property("name", "vadas").Property("age", 27).AddV((string) "software").Property("name", "lop").Property("lang", "java").AddV((string) "person").Property("name", "josh").Property("age", 32).AddV((string) "person").Property("name", "peter").Pro [...]
+ {"g_VXvid1X_propertyXcreatorCount_VXvid1X_inXcreatedX_countX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) "person").Property("name", "marko").Property("age", 29).As("marko").AddV((string) "person").Property("name", "vadas").Property("age", 27).AddV((string) "software").Property("name", "lop").Property("lang", "java").As("lop").AddV((string) "person").Property("name", "josh").Property("age", 32).As("josh").AddV((st [...]
+ {"g_VXvid1X_propertyXknownCount_outXknowsX_countX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) "person").Property("name", "marko").Property("age", 29).As("marko").AddV((string) "person").Property("name", "vadas").Property("age", 27).As("vadas").AddV((string) "software").Property("name", "lop").Property("lang", "java").AddV((string) "person").Property("name", "josh").Property("age", 32).As("josh").AddV((string) "pe [...]
+ {"g_VXvid1X_propertyXcreator_inXcreatedX_valuesXnameXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) "person").Property("name", "marko").Property("age", 29).As("marko").AddV((string) "person").Property("name", "vadas").Property("age", 27).AddV((string) "software").Property("name", "lop").Property("lang", "java").As("lop").AddV((string) "person").Property("name", "josh").Property("age", 32).As("josh").AddV((string) [...]
+ {"g_VXvid2X_propertyXVXvid1X_projectXfriendCount_softwareCreatedXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) "person").Property("name", "marko").Property("age", 29).As("marko").AddV((string) "person").Property("name", "vadas").Property("age", 27).As("vadas").AddV((string) "software").Property("name", "lop").Property("lang", "java").As("lop").AddV((string) "person").Property("name", "josh").Property("age", 32).A [...]
+ {"g_VXvid2X_propertyXVXvid1X_projectXoriginalName_originalLabelX_byXnameX_byXlabelXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) "person").Property("name", "marko").Property("age", 29).As("marko").AddV((string) "person").Property("name", "vadas").Property("age", 27).AddV((string) "software").Property("name", "lop").Property("lang", "java").As("lop").AddV((string) "person").Property("name", "josh").Property("age", [...]
+ {"g_VXvid1X_propertyXlist_friends_outXknowsX_valuesXnameXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) "person").Property("name", "marko").Property("age", 29).As("marko").AddV((string) "person").Property("name", "vadas").Property("age", 27).As("vadas").AddV((string) "software").Property("name", "lop").Property("lang", "java").AddV((string) "person").Property("name", "josh").Property("age", 32).As("josh").AddV((st [...]
+ {"g_VXvid1X_propertyXset_langs_outXcreatedX_valuesXlangXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) "person").Property("name", "marko").Property("age", 29).AddV((string) "person").Property("name", "vadas").Property("age", 27).AddV((string) "software").Property("name", "lop").Property("lang", "java").As("lop").AddV((string) "person").Property("name", "josh").Property("age", 32).As("josh").AddV((string) "person") [...]
+ {"g_VXvid1X_propertyXsingle_friend_outXknowsX_valuesXnameXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) "person").Property("name", "marko").Property("age", 29).As("marko").AddV((string) "person").Property("name", "vadas").Property("age", 27).As("vadas").AddV((string) "software").Property("name", "lop").Property("lang", "java").AddV((string) "person").Property("name", "josh").Property("age", 32).As("josh").AddV((s [...]
+ {"g_VXvid1X_propertyXVXvid1X_groupX_byXidX_byXvaluesXnameXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) "person").Property("name", "marko").Property("age", 29), (g,p) =>g.V(p["vid1"]).Property((ITraversal) __.V(p["vid1"]).Group<object, object>().By(__.Id()).By(__.Values<object>("name")))}},
{"g_io_readXkryoX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Io<object>("data/tinkerpop-modern.kryo").Read(), (g,p) =>g.V(), (g,p) =>g.E()}},
{"g_io_read_withXreader_gryoX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Io<object>("data/tinkerpop-modern.kryo").With(IO.Reader, IO.Gryo).Read(), (g,p) =>g.V(), (g,p) =>g.E()}},
{"g_io_readXgraphsonX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Io<object>("data/tinkerpop-modern.json").Read(), (g,p) =>g.V(), (g,p) =>g.E()}},
diff --git a/gremlin-go/driver/cucumber/gremlin.go b/gremlin-go/driver/cucumber/gremlin.go
index 72df59267e..1ff3d19a48 100644
--- a/gremlin-go/driver/cucumber/gremlin.go
+++ b/gremlin-go/driver/cucumber/gremlin.go
@@ -505,7 +505,6 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[
"g_V_hasXname_VXvid1X_valuesXnameXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.T__.V(p["vid1"]).Values("name"))}},
"g_V_hasXname_VXvid1X_outXknowsX_valuesXnameXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.T__.V(p["vid1"]).Out("knows").Values("name"))}},
"g_V_hasXage_VXvid1X_outXknowsX_valuesXageXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("age", gremlingo.T__.V(p["vid1"]).Out("knows").Values("age"))}},
- "g_V_hasXname_VXvid1X_outXcreatedX_valuesXnameXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.T__.V(p["vid1"]).Out("created").Values("name"))}},
"g_V_hasXname_VXvid1X_valuesXnonexistentXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.T__.V(p["vid1"]).Values("nonexistent"))}},
"g_V_hasXname_notXidentityXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.T__.Not(gremlingo.T__.Identity()))}},
"g_V_hasXage_gtXVXvid1X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("age", gremlingo.P.Gt(gremlingo.T__.V(p["vid1"]).Values("age")))}},
@@ -517,6 +516,14 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[
"g_V_hasXage_eqXVXvid1X_valuesXnonexistentXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("age", gremlingo.P.Eq(gremlingo.T__.V(p["vid1"]).Values("nonexistent")))}},
"g_V_hasXlabel_VXvid1X_labelXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has(gremlingo.T.Label, gremlingo.T__.V(p["vid1"]).Label())}},
"g_V_hasXperson_name_VXvid1X_valuesXnameXX_age": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("person", "name", gremlingo.T__.V(p["vid1"]).Values("name")).Values("age")}},
+ "g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_constantXpeterXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.P.Within(gremlingo.T__.V(p["vid1"]).Out("knows").Values("name"), gremlingo.T__.Constant("peter")))}},
+ "g_V_hasXname_withinXVXvid1X_valuesXnonexistentX_constantXmarkoXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.P.Within(gremlingo.T__.V(p["vid1"]).Values("nonexistent"), gremlingo.T__.Constant("marko")))}},
+ "g_V_hasXname_withinXVXvid1X_valuesXnonexistentX_VXvid1X_valuesXnonexistentXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.P.Within(gremlingo.T__.V(p["vid1"]).Values("nonexistent"), gremlingo.T__.V(p["vid1"]).Values("nonexistent")))}},
+ "g_V_hasXname_withoutXVXvid1X_valuesXnameX_VXvid2X_valuesXnameX_VXvid3X_valuesXnameXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.P.Without(gremlingo.T__.V(p["vid1"]).Values("name"), gremlingo.T__.V(p["vid2"]).Values("name"), gremlingo.T__.V(p["vid3"]).Values("name")))}},
+ "g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.P.Within(gremlingo.T__.V(p["vid1"]).Out("knows").Values("name"), gremlingo.T__.V(p["vid3"]).Out("created").Values("name")))}},
+ "g_V_hasLabelXsoftwareX_hasXname_withoutXVXvid1X_outXcreatedX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("software").Has("name", gremlingo.P.Without(gremlingo.T__.V(p["vid1"]).Out("created").Values("name"), gremlingo.T__.V(p["vid3"]).Out("created").Values("name")))}},
+ "g_V_hasLabelXpersonX_valuesXageX_isXwithinXVXvid1X_valuesXageX_V_hasXname_lopX_inXcreatedX_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("person").Values("age").Is(gremlingo.P.Within(gremlingo.T__.V(p["vid1"]).Values("age"), gremlingo.T__.V().Has("name", "lop").In("created").Values("age")))}},
+ "g_VXvid1X_outEXknowsX_filterXinV_hasXname_withinXV_hasXname_lopX_inXcreatedX_valuesXnameX_V_hasXname_rippleX_inXcreatedX_valuesXnameXXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).OutE("knows").Filter(gremlingo.T__.InV().Has("name", gremlingo.P.Within(gremlingo.T__.V().Has("name", "lop").In("created").Values("name"), gremlingo.T__.V().Has("name", "ripple").In("created").Values("name"))))}},
"g_V_properties_hasValueXnullX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Properties().HasValue(nil)}},
"g_V_properties_hasValueXnull_nullX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Properties().HasValue(nil, nil)}},
"g_V_properties_hasValueXnull_joshX_value": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Properties().HasValue(nil, "josh").Value()}},
@@ -528,6 +535,26 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[
"g_V_valuesXageX_isXgte_29vaarX_isXlt_34varX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Is(gremlingo.P.Gte(p["xx1"])).Is(gremlingo.P.Lt(p["xx2"]))}},
"g_V_whereXinXcreatedX_count_isX1XX_valuesXnameX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Where(gremlingo.T__.In("created").Count().Is(1)).Values("name")}},
"g_V_whereXinXcreatedX_count_isXgte_2XX_valuesXnameX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Where(gremlingo.T__.In("created").Count().Is(gremlingo.P.Gte(2))).Values("name")}},
+ "g_V_valuesXageX_isXVXvid1X_valuesXageXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Is(gremlingo.T__.V(p["vid1"]).Values("age"))}},
+ "g_V_valuesXnameX_isXVXvid1X_valuesXnameXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("name").Is(gremlingo.T__.V(p["vid1"]).Values("name"))}},
+ "g_V_valuesXageX_isXgtXVXvid1X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Is(gremlingo.P.Gt(gremlingo.T__.V(p["vid1"]).Values("age")))}},
+ "g_V_valuesXageX_isXltXVXvid3X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Is(gremlingo.P.Lt(gremlingo.T__.V(p["vid3"]).Values("age")))}},
+ "g_V_valuesXageX_isXneqXVXvid4X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Is(gremlingo.P.Neq(gremlingo.T__.V(p["vid4"]).Values("age")))}},
+ "g_V_valuesXageX_isXwithinXVXvid1X_outXknowsX_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Is(gremlingo.P.Within(gremlingo.T__.V(p["vid1"]).Out("knows").Values("age")))}},
+ "g_V_valuesXageX_isXVXvid1X_valuesXnonexistentXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Is(gremlingo.T__.V(p["vid1"]).Values("nonexistent"))}},
+ "g_V_hasLabelXpersonX_valuesXageX_chooseXgtXVXvid1X_valuesXageXX_olderX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("person").Values("age").Choose(gremlingo.P.Gt(gremlingo.T__.V(p["vid1"]).Values("age")), gremlingo.T__.Constant("older than marko"), gremlingo.T__.Constant("not older"))}},
+ "g_V_hasLabelXpersonX_valuesXageX_chooseXgteXmeanAgeX_aboveX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("person").Values("age").Choose(gremlingo.P.Gte(gremlingo.T__.V().HasLabel("person").Values("age").Mean()), gremlingo.T__.Constant("above average"), gremlingo.T__.Constant("below average"))}},
+ "g_VXvid1X_outXknowsX_valuesXageX_fold_allXgteXVXvid2X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Out("knows").Values("age").Fold().All(gremlingo.P.Gte(gremlingo.T__.V(p["vid2"]).Values("age")))}},
+ "g_VXvid1X_outXknowsX_valuesXageX_fold_allXgtXVXvid2X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Out("knows").Values("age").Fold().All(gremlingo.P.Gt(gremlingo.T__.V(p["vid2"]).Values("age")))}},
+ "g_VXvid1X_outXknowsX_valuesXageX_fold_anyXeqXVXvid3X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Out("knows").Values("age").Fold().Any(gremlingo.P.Eq(gremlingo.T__.V(p["vid3"]).Values("age")))}},
+ "g_VXvid1X_outXknowsX_valuesXageX_fold_noneXeqXVXvid4X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Out("knows").Values("age").Fold().None(gremlingo.P.Eq(gremlingo.T__.V(p["vid4"]).Values("age")))}},
+ "g_VXvid1X_outXknowsX_valuesXageX_fold_noneXeqXVXvid3X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Out("knows").Values("age").Fold().None(gremlingo.P.Eq(gremlingo.T__.V(p["vid3"]).Values("age")))}},
+ "g_injectXnullX_isXeqXV9999_valuesXnameXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(nil).Is(gremlingo.P.Eq(gremlingo.T__.V(9999).Values("name")))}},
+ "g_injectXmarkoX_isXV9999_valuesXnameXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject("marko").Is(gremlingo.T__.V(9999).Values("name"))}},
+ "g_injectXmarkoX_chooseXeqXV9999_valuesXnameXX_matched_unmatchedX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject("marko").Choose(gremlingo.P.Eq(gremlingo.T__.V(9999).Values("name")), gremlingo.T__.Constant("matched"), gremlingo.T__.Constant("unmatched"))}},
+ "g_injectXlistX_noneXeqXV9999_valuesXnameXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject([]interface{}{"marko", "josh"}).None(gremlingo.P.Eq(gremlingo.T__.V(9999).Values("name")))}},
+ "g_V_hasXname_eqXV9999_valuesXnameXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.P.Eq(gremlingo.T__.V(9999).Values("name")))}},
+ "g_V_valuesXageX_isXwithoutXVXvid1X_valuesXageX_VXvid2X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Is(gremlingo.P.Without(gremlingo.T__.V(p["vid1"]).Values("age"), gremlingo.T__.V(p["vid2"]).Values("age")))}},
"g_V_valuesXageX_noneXgtX32XX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").None(gremlingo.P.Gt(32))}},
"g_V_valuesXageX_whereXisXP_gtX33XXX_fold_noneXlteX33XX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Where(gremlingo.T__.Is(gremlingo.P.Gt(33))).Fold().None(gremlingo.P.Lte(33))}},
"g_V_valuesXageX_order_byXdescX_fold_noneXltX10XX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Order().By(gremlingo.Order.Desc).Fold().None(gremlingo.P.Lt(10))}},
@@ -1764,14 +1791,14 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[
"g_V_localXoutE_foldX_unfold": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Local(gremlingo.T__.OutE().Fold()).Unfold()}},
"g_V_valueMap_unfold_mapXselectXkeysXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().ValueMap().Unfold().Map(gremlingo.T__.Select(gremlingo.Column.Keys))}},
"g_VX1X_repeatXboth_simplePathX_untilXhasIdX6XX_path_byXnameX_unfold": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Repeat(gremlingo.T__.Both().SimplePath()).Until(gremlingo.T__.HasId(p["vid6"])).Path().By("name").Unfold()}},
- "g_VXvid1X_outXcreatedX_asXsoftwareX_V_hasXname_selectXsoftwareX_valuesXnameXX_inXcreatedX_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Out("created").As("sw").V().Has("name", gremlingo.T__.Select("sw").Values("name")).In("created").Values("name")}},
+ "g_VXvid1X_id_VXidentityX_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Id().V(gremlingo.T__.Identity()).Values("name")}},
+ "g_VXvid1_vid2X_id_VXidentityX_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"], p["vid2"]).Id().V(gremlingo.T__.Identity()).Values("name")}},
+ "g_VXvid1X_id_asXbookmarkX_V_hasXname_joshX_VXselectXbookmarkXX_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Id().As("bookmark").V().Has("name", "josh").V(gremlingo.T__.Select("bookmark")).Values("name")}},
"g_VXvid1X_VXoutXknowsX_idX_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).V(gremlingo.T__.Out("knows").Id()).Values("name")}},
- "g_VXvid1X_VXoutXknowsX_hasXname_joshX_idX_valuesXageX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).V(gremlingo.T__.Out("knows").Has("name", "josh").Id()).Values("age")}},
- "g_VXvid1X_VXoutXknowsX_outXknowsX_idX_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).V(gremlingo.T__.Out("knows").Out("knows").Id()).Values("name")}},
- "g_VXvid1X_VXoutXcreatedX_idX_valuesXlangX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).V(gremlingo.T__.Out("created").Id()).Values("lang")}},
"g_VXvid1X_EXoutE_idX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).E(gremlingo.T__.OutE().Id())}},
- "g_VXvid1X_EXoutEXknowsX_hasXweight_05X_idX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).E(gremlingo.T__.OutE("knows").Has("weight", 0.5).Id())}},
- "g_VXvid1X_EXoutXknowsX_outXknowsX_outE_idX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).E(gremlingo.T__.Out("knows").Out("knows").OutE().Id())}},
+ "g_injectX9999X_VXidentityX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(9999).V(gremlingo.T__.Identity())}},
+ "g_VXvid1X_outEXknowsX_hasXinV_name_vadasX_id_EXidentityX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).OutE("knows").Filter(gremlingo.T__.InV().Has("name", "vadas")).Id().E(gremlingo.T__.Identity())}},
+ "g_injectX9999X_EXidentityX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(9999).E(gremlingo.T__.Identity())}},
"g_VXVXvid1X_idX_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(gremlingo.T__.V(p["vid1"]).Id()).Values("name")}},
"g_EXVXvid1X_outE_idX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E(gremlingo.T__.V(p["vid1"]).OutE().Id())}},
"g_V_valueMap": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().ValueMap()}},
@@ -2095,17 +2122,16 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[
"g_injectX1_3_100_300X_list": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject([]interface{}{1, 3, 100, 300})}},
"g_injectX1_3_100_300X_set": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(gremlingo.NewSimpleSet(1, 3, 100, 300))}},
"g_injectX1_1X_set": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(gremlingo.NewSimpleSet(1, 1))}},
- "g_VXvid2X_propertyXalias_VXvid1X_valuesXnameXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid2"]).Property("alias", gremlingo.T__.V(p["vid1"]).Values("name"))}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("alias", "marko")}},
- "g_VXvid1X_propertyXcreatorCount_VXvid1X_inXcreatedX_countX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Property("creatorCount", gremlingo.T__.V(p["vid1"]).In("created").Count())}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("creatorCount", int64(3))}},
- "g_VXvid1X_propertyXknownCount_outXknowsX_countX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Property("knownCount", gremlingo.T__.Out("knows").Count())}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("knownCount", int64(2))}},
- "g_VXvid1X_propertyXcreator_inXcreatedX_valuesXnameXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Property("creator", gremlingo.T__.In("created").Values("name"))}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("creator")}},
- "g_VXvid2X_propertyXVXvid1X_projectXfriendCount_softwareCreatedXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid2"]).Property(gremlingo.T__.V(p["vid1"]).Project("friendCount", "softwareCreated").By(gremlingo.T__.Out("knows").Count()).By(gremlingo.T__.Out("created").Values("name")))}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("friendCount", int64(2))}, [...]
- "g_VXvid2X_propertyXVXvid1X_projectXoriginalName_originalLabelX_byXnameX_byXlabelXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid2"]).Property(gremlingo.T__.V(p["vid1"]).Project("originalName", "originalLabel").By(gremlingo.T__.Values("name")).By(gremlingo.T__.Label()))}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid2"]).Has("originalName", "marko")}, f [...]
- "g_VXvid1X_propertyXlist_friends_outXknowsX_valuesXnameXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Property(gremlingo.Cardinality.List, "friends", gremlingo.T__.Out("knows").Values("name"))}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Properties("friends")}},
- "g_VXvid1X_propertyXlist_creators_inXcreatedX_valuesXnameXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Property(gremlingo.Cardinality.List, "creators", gremlingo.T__.In("created").Values("name"))}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Properties("creators")}},
- "g_VXvid1X_propertyXset_langs_outXcreatedX_valuesXlangXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Property(gremlingo.Cardinality.Set, "langs", gremlingo.T__.Out("created").Values("lang"))}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Properties("langs")}},
- "g_VXvid1X_propertyXsingle_friend_outXknowsX_valuesXnameXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Property(gremlingo.Cardinality.Single, "friend", gremlingo.T__.Out("knows").Values("name"))}},
- "g_VXvid1X_propertyXVXvid1X_groupX_byXidX_byXvaluesXnameXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Property(gremlingo.T__.V(p["vid1"]).Group().By(gremlingo.T__.Id()).By(gremlingo.T__.Values("name")))}},
+ "g_VXvid2X_propertyXalias_VXvid1X_valuesXnameXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").Property("age", 29).AddV("person").Property("name", "vadas").Property("age", 27).AddV("software").Property("name", "lop").Property("lang", "java").AddV("person").Property("name", "josh").Property("age", 32).AddV("person").Property("name", "peter").Property("age", 35).AddV("software").Property( [...]
+ "g_VXvid1X_propertyXcreatorCount_VXvid1X_inXcreatedX_countX": {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).AddV("software").Property("name", "lop").Property("lang", "java").As("lop").AddV("person").Property("name", "josh").Property("age", 32).As("josh").AddV("person").Property("name", "peter").P [...]
+ "g_VXvid1X_propertyXknownCount_outXknowsX_countX": {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").AddV("person").Property("name", "josh").Property("age", 32).As("josh").AddV("person").Property("name", "peter").Property(" [...]
+ "g_VXvid1X_propertyXcreator_inXcreatedX_valuesXnameXX": {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).AddV("software").Property("name", "lop").Property("lang", "java").As("lop").AddV("person").Property("name", "josh").Property("age", 32).As("josh").AddV("person").Property("name", "peter").Propert [...]
+ "g_VXvid2X_propertyXVXvid1X_projectXfriendCount_softwareCreatedXX": {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("person").Property( [...]
+ "g_VXvid2X_propertyXVXvid1X_projectXoriginalName_originalLabelX_byXnameX_byXlabelXX": {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).AddV("software").Property("name", "lop").Property("lang", "java").As("lop").AddV("person").Property("name", "josh").Property("age", 32).AddV("person").Property("name [...]
+ "g_VXvid1X_propertyXlist_friends_outXknowsX_valuesXnameXX": {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").AddV("person").Property("name", "josh").Property("age", 32).As("josh").AddV("person").Property("name", "peter").P [...]
+ "g_VXvid1X_propertyXset_langs_outXcreatedX_valuesXlangXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").Property("age", 29).AddV("person").Property("name", "vadas").Property("age", 27).AddV("software").Property("name", "lop").Property("lang", "java").As("lop").AddV("person").Property("name", "josh").Property("age", 32).As("josh").AddV("person").Property("name", "peter").Property("age", [...]
+ "g_VXvid1X_propertyXsingle_friend_outXknowsX_valuesXnameXX": {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").AddV("person").Property("name", "josh").Property("age", 32).As("josh").AddV("person").Property("name", "peter"). [...]
+ "g_VXvid1X_propertyXVXvid1X_groupX_byXidX_byXvaluesXnameXXX": {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(p["vid1"]).Property(gremlingo.T__.V(p["vid1"]).Group().By(gremlingo.T__.Id()).By(gremlingo.T__.Values("name")))}},
"g_io_readXkryoX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Io("data/tinkerpop-modern.kryo").Read()}, 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()}},
"g_io_read_withXreader_gryoX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Io("data/tinkerpop-modern.kryo").With(gremlingo.IO.Reader, gremlingo.IO.Gryo).Read()}, 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()}},
"g_io_readXgraphsonX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Io("data/tinkerpop-modern.json").Read()}, 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()}},
diff --git a/gremlin-go/driver/gremlinlang.go b/gremlin-go/driver/gremlinlang.go
index 2625cb10e6..15ffd27a25 100644
--- a/gremlin-go/driver/gremlinlang.go
+++ b/gremlin-go/driver/gremlinlang.go
@@ -412,7 +412,22 @@ func (gl *GremlinLang) translatePValue(operator string, values []interface{}) (s
sb := strings.Builder{}
sb.WriteString(operator + "(")
- if len(values) > 1 && operator != "between" && operator != "inside" {
+ // Check if all values are traversals — if so, serialize as comma-separated args (no brackets)
+ // This matches the server grammar: within(trav1, trav2) via genericArgumentVarargs
+ allTraversals := len(values) > 1
+ if allTraversals {
+ for _, v := range values {
+ switch v.(type) {
+ case *Traversal, Traversal, *GraphTraversal, GraphTraversal:
+ // ok, it's a traversal
+ default:
+ allTraversals = false
+ break
+ }
+ }
+ }
+
+ if len(values) > 1 && !allTraversals && operator != "between" && operator != "inside" {
sb.WriteString("[")
}
@@ -427,7 +442,7 @@ func (gl *GremlinLang) translatePValue(operator string, values []interface{}) (s
}
}
- if len(values) > 1 && operator != "between" && operator != "inside" {
+ if len(values) > 1 && !allTraversals && operator != "between" && operator != "inside" {
sb.WriteString("]")
}
sb.WriteString(")")
diff --git a/gremlin-js/gremlin-javascript/lib/language/translator/DotNetTranslateVisitor.ts b/gremlin-js/gremlin-javascript/lib/language/translator/DotNetTranslateVisitor.ts
index 8cb11b125b..bfbd22c722 100644
--- a/gremlin-js/gremlin-javascript/lib/language/translator/DotNetTranslateVisitor.ts
+++ b/gremlin-js/gremlin-javascript/lib/language/translator/DotNetTranslateVisitor.ts
@@ -834,6 +834,45 @@ export default class DotNetTranslateVisitor extends TranslateVisitor {
// ─── property ────────────────────────────────────────────────────────────
+ visitTraversalMethod_property_Object(ctx: any): void {
+ // Property(null) is ambiguous with Property(ITraversal) — cast null to IDictionary to disambiguate
+ if (ctx.genericMapNullableArgument().genericMapNullableLiteral() != null &&
+ ctx.genericMapNullableArgument().genericMapNullableLiteral().nullLiteral() != null) {
+ this.visit(ctx.getChild(0));
+ this.sb.push('(');
+ this.sb.push('(IDictionary<object, object>) ');
+ this.visit(ctx.genericMapNullableArgument());
+ this.sb.push(')');
+ return;
+ }
+ this.visitChildren(ctx);
+ }
+
+ visitTraversalMethod_property_Cardinality_Object(ctx: any): void {
+ // Property(Cardinality, null) — cast null to IDictionary to disambiguate
+ if (ctx.genericMapNullableArgument().genericMapNullableLiteral() != null &&
+ ctx.genericMapNullableArgument().genericMapNullableLiteral().nullLiteral() != null) {
+ this.visit(ctx.getChild(0));
+ this.sb.push('(');
+ this.visit(ctx.traversalCardinality());
+ this.sb.push(', ');
+ this.sb.push('(IDictionary<object, object>) ');
+ this.visit(ctx.genericMapNullableArgument());
+ this.sb.push(')');
+ return;
+ }
+ this.visitChildren(ctx);
+ }
+
+ visitTraversalMethod_property_Traversal(ctx: any): void {
+ // Property(ITraversal) — cast to ITraversal to disambiguate
+ this.visit(ctx.getChild(0));
+ this.sb.push('(');
+ this.sb.push('(ITraversal) ');
+ this.visit(ctx.nestedTraversal());
+ this.sb.push(')');
+ }
+
visitTraversalMethod_property_Cardinality_Object_Object_Object(ctx: any): void {
if (ctx.genericArgumentVarargs() == null || ctx.genericArgumentVarargs().getChildCount() === 0) {
this.sb.push(capitalize(ctx.getChild(0).getText()));
diff --git a/gremlin-js/gremlin-javascript/lib/process/gremlin-lang.ts b/gremlin-js/gremlin-javascript/lib/process/gremlin-lang.ts
index 2a07ad8dec..55a43fa812 100644
--- a/gremlin-js/gremlin-javascript/lib/process/gremlin-lang.ts
+++ b/gremlin-js/gremlin-javascript/lib/process/gremlin-lang.ts
@@ -55,7 +55,14 @@ export default class GremlinLang {
let result = p.operator + '(';
if (Array.isArray(p.value)) {
- result += '[' + p.value.map(v => this._argAsString(v)).join(',') + ']';
+ // If all elements are traversals, serialize as comma-separated args (no brackets)
+ // This matches the server grammar: within(trav1, trav2) via genericArgumentVarargs
+ const allTraversals = p.value.length > 0 && p.value.every((v: any) => v != null && typeof v.getGremlinLang === 'function');
+ if (allTraversals) {
+ result += p.value.map((v: any) => this._argAsString(v)).join(',');
+ } else {
+ result += '[' + p.value.map((v: any) => this._argAsString(v)).join(',') + ']';
+ }
} else {
result += this._argAsString(p.value);
if (p.other !== undefined && p.other !== null) {
diff --git a/gremlin-js/gremlin-javascript/lib/process/traversal.ts b/gremlin-js/gremlin-javascript/lib/process/traversal.ts
index 12404b80b3..ff9932e46e 100644
--- a/gremlin-js/gremlin-javascript/lib/process/traversal.ts
+++ b/gremlin-js/gremlin-javascript/lib/process/traversal.ts
@@ -347,6 +347,9 @@ export class P<T1 = any, T2 = any> {
if (args.length === 1 && Array.isArray(args[0])) {
return new P('within', args[0], null);
}
+ if (args.length === 1 && args[0] != null && typeof args[0].getGremlinLang === 'function') {
+ return new P('within', args[0], null);
+ }
return new P('within', args, null);
}
@@ -354,6 +357,9 @@ export class P<T1 = any, T2 = any> {
if (args.length === 1 && Array.isArray(args[0])) {
return new P('without', args[0], null);
}
+ if (args.length === 1 && args[0] != null && typeof args[0].getGremlinLang === 'function') {
+ return new P('without', args[0], null);
+ }
return new P('without', args, null);
}
diff --git a/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js b/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js
index 1247cbe825..3dc2da180a 100644
--- a/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js
+++ b/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js
@@ -536,7 +536,6 @@ const gremlins = {
g_V_hasXname_VXvid1X_valuesXnameXX: [function({g, vid1}) { return g.V().has("name", __.V(vid1).values("name")) }],
g_V_hasXname_VXvid1X_outXknowsX_valuesXnameXX: [function({g, vid1}) { return g.V().has("name", __.V(vid1).out("knows").values("name")) }],
g_V_hasXage_VXvid1X_outXknowsX_valuesXageXX: [function({g, vid1}) { return g.V().has("age", __.V(vid1).out("knows").values("age")) }],
- g_V_hasXname_VXvid1X_outXcreatedX_valuesXnameXX: [function({g, vid1}) { return g.V().has("name", __.V(vid1).out("created").values("name")) }],
g_V_hasXname_VXvid1X_valuesXnonexistentXX: [function({g, vid1}) { return g.V().has("name", __.V(vid1).values("nonexistent")) }],
g_V_hasXname_notXidentityXX: [function({g}) { return g.V().has("name", __.not(__.identity())) }],
g_V_hasXage_gtXVXvid1X_valuesXageXXX: [function({g, vid1}) { return g.V().has("age", P.gt(__.V(vid1).values("age"))) }],
@@ -548,6 +547,14 @@ const gremlins = {
g_V_hasXage_eqXVXvid1X_valuesXnonexistentXXX: [function({g, vid1}) { return g.V().has("age", P.eq(__.V(vid1).values("nonexistent"))) }],
g_V_hasXlabel_VXvid1X_labelXX: [function({g, vid1}) { return g.V().has(T.label, __.V(vid1).label()) }],
g_V_hasXperson_name_VXvid1X_valuesXnameXX_age: [function({g, vid1}) { return g.V().has("person", "name", __.V(vid1).values("name")).values("age") }],
+ g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_constantXpeterXXX: [function({g, vid1}) { return g.V().has("name", P.within(__.V(vid1).out("knows").values("name"), __.constant("peter"))) }],
+ g_V_hasXname_withinXVXvid1X_valuesXnonexistentX_constantXmarkoXXX: [function({g, vid1}) { return g.V().has("name", P.within(__.V(vid1).values("nonexistent"), __.constant("marko"))) }],
+ g_V_hasXname_withinXVXvid1X_valuesXnonexistentX_VXvid1X_valuesXnonexistentXXX: [function({g, vid1}) { return g.V().has("name", P.within(__.V(vid1).values("nonexistent"), __.V(vid1).values("nonexistent"))) }],
+ g_V_hasXname_withoutXVXvid1X_valuesXnameX_VXvid2X_valuesXnameX_VXvid3X_valuesXnameXXX: [function({g, vid3, vid2, vid1}) { return g.V().has("name", P.without(__.V(vid1).values("name"), __.V(vid2).values("name"), __.V(vid3).values("name"))) }],
+ g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX: [function({g, vid3, vid1}) { return g.V().has("name", P.within(__.V(vid1).out("knows").values("name"), __.V(vid3).out("created").values("name"))) }],
+ g_V_hasLabelXsoftwareX_hasXname_withoutXVXvid1X_outXcreatedX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX: [function({g, vid3, vid1}) { return g.V().hasLabel("software").has("name", P.without(__.V(vid1).out("created").values("name"), __.V(vid3).out("created").values("name"))) }],
+ g_V_hasLabelXpersonX_valuesXageX_isXwithinXVXvid1X_valuesXageX_V_hasXname_lopX_inXcreatedX_valuesXageXXX: [function({g, vid1}) { return g.V().hasLabel("person").values("age").is(P.within(__.V(vid1).values("age"), __.V().has("name", "lop").in_("created").values("age"))) }],
+ g_VXvid1X_outEXknowsX_filterXinV_hasXname_withinXV_hasXname_lopX_inXcreatedX_valuesXnameX_V_hasXname_rippleX_inXcreatedX_valuesXnameXXXX: [function({g, vid1}) { return g.V(vid1).outE("knows").filter(__.inV().has("name", P.within(__.V().has("name", "lop").in_("created").values("name"), __.V().has("name", "ripple").in_("created").values("name")))) }],
g_V_properties_hasValueXnullX: [function({g}) { return g.V().properties().hasValue(null) }],
g_V_properties_hasValueXnull_nullX: [function({g}) { return g.V().properties().hasValue(null, null) }],
g_V_properties_hasValueXnull_joshX_value: [function({g}) { return g.V().properties().hasValue(null, "josh").value() }],
@@ -559,6 +566,26 @@ const gremlins = {
g_V_valuesXageX_isXgte_29vaarX_isXlt_34varX: [function({g, xx1, xx2}) { return g.V().values("age").is(P.gte(xx1)).is(P.lt(xx2)) }],
g_V_whereXinXcreatedX_count_isX1XX_valuesXnameX: [function({g}) { return g.V().where(__.in_("created").count().is(1)).values("name") }],
g_V_whereXinXcreatedX_count_isXgte_2XX_valuesXnameX: [function({g}) { return g.V().where(__.in_("created").count().is(P.gte(2))).values("name") }],
+ g_V_valuesXageX_isXVXvid1X_valuesXageXX: [function({g, vid1}) { return g.V().values("age").is(__.V(vid1).values("age")) }],
+ g_V_valuesXnameX_isXVXvid1X_valuesXnameXX: [function({g, vid1}) { return g.V().values("name").is(__.V(vid1).values("name")) }],
+ g_V_valuesXageX_isXgtXVXvid1X_valuesXageXXX: [function({g, vid1}) { return g.V().values("age").is(P.gt(__.V(vid1).values("age"))) }],
+ g_V_valuesXageX_isXltXVXvid3X_valuesXageXXX: [function({g, vid3}) { return g.V().values("age").is(P.lt(__.V(vid3).values("age"))) }],
+ g_V_valuesXageX_isXneqXVXvid4X_valuesXageXXX: [function({g, vid4}) { return g.V().values("age").is(P.neq(__.V(vid4).values("age"))) }],
+ g_V_valuesXageX_isXwithinXVXvid1X_outXknowsX_valuesXageXXX: [function({g, vid1}) { return g.V().values("age").is(P.within(__.V(vid1).out("knows").values("age"))) }],
+ g_V_valuesXageX_isXVXvid1X_valuesXnonexistentXX: [function({g, vid1}) { return g.V().values("age").is(__.V(vid1).values("nonexistent")) }],
+ g_V_hasLabelXpersonX_valuesXageX_chooseXgtXVXvid1X_valuesXageXX_olderX: [function({g, vid1}) { return g.V().hasLabel("person").values("age").choose(P.gt(__.V(vid1).values("age")), __.constant("older than marko"), __.constant("not older")) }],
+ g_V_hasLabelXpersonX_valuesXageX_chooseXgteXmeanAgeX_aboveX: [function({g}) { return g.V().hasLabel("person").values("age").choose(P.gte(__.V().hasLabel("person").values("age").mean()), __.constant("above average"), __.constant("below average")) }],
+ g_VXvid1X_outXknowsX_valuesXageX_fold_allXgteXVXvid2X_valuesXageXXX: [function({g, vid2, vid1}) { return g.V(vid1).out("knows").values("age").fold().all(P.gte(__.V(vid2).values("age"))) }],
+ g_VXvid1X_outXknowsX_valuesXageX_fold_allXgtXVXvid2X_valuesXageXXX: [function({g, vid2, vid1}) { return g.V(vid1).out("knows").values("age").fold().all(P.gt(__.V(vid2).values("age"))) }],
+ g_VXvid1X_outXknowsX_valuesXageX_fold_anyXeqXVXvid3X_valuesXageXXX: [function({g, vid3, vid1}) { return g.V(vid1).out("knows").values("age").fold().any(P.eq(__.V(vid3).values("age"))) }],
+ g_VXvid1X_outXknowsX_valuesXageX_fold_noneXeqXVXvid4X_valuesXageXXX: [function({g, vid4, vid1}) { return g.V(vid1).out("knows").values("age").fold().none(P.eq(__.V(vid4).values("age"))) }],
+ g_VXvid1X_outXknowsX_valuesXageX_fold_noneXeqXVXvid3X_valuesXageXXX: [function({g, vid3, vid1}) { return g.V(vid1).out("knows").values("age").fold().none(P.eq(__.V(vid3).values("age"))) }],
+ g_injectXnullX_isXeqXV9999_valuesXnameXXX: [function({g}) { return g.inject(null).is(P.eq(__.V(9999).values("name"))) }],
+ g_injectXmarkoX_isXV9999_valuesXnameXX: [function({g}) { return g.inject("marko").is(__.V(9999).values("name")) }],
+ g_injectXmarkoX_chooseXeqXV9999_valuesXnameXX_matched_unmatchedX: [function({g}) { return g.inject("marko").choose(P.eq(__.V(9999).values("name")), __.constant("matched"), __.constant("unmatched")) }],
+ g_injectXlistX_noneXeqXV9999_valuesXnameXXX: [function({g}) { return g.inject(["marko", "josh"]).none(P.eq(__.V(9999).values("name"))) }],
+ g_V_hasXname_eqXV9999_valuesXnameXXX: [function({g}) { return g.V().has("name", P.eq(__.V(9999).values("name"))) }],
+ g_V_valuesXageX_isXwithoutXVXvid1X_valuesXageX_VXvid2X_valuesXageXXX: [function({g, vid2, vid1}) { return g.V().values("age").is(P.without(__.V(vid1).values("age"), __.V(vid2).values("age"))) }],
g_V_valuesXageX_noneXgtX32XX: [function({g}) { return g.V().values("age").none(P.gt(32)) }],
g_V_valuesXageX_whereXisXP_gtX33XXX_fold_noneXlteX33XX: [function({g}) { return g.V().values("age").where(__.is(P.gt(33))).fold().none(P.lte(33)) }],
g_V_valuesXageX_order_byXdescX_fold_noneXltX10XX: [function({g}) { return g.V().values("age").order().by(Order.desc).fold().none(P.lt(10)) }],
@@ -1795,14 +1822,14 @@ const gremlins = {
g_V_localXoutE_foldX_unfold: [function({g}) { return g.V().local(__.outE().fold()).unfold() }],
g_V_valueMap_unfold_mapXselectXkeysXX: [function({g}) { return g.V().valueMap().unfold().map(__.select(Column.keys)) }],
g_VX1X_repeatXboth_simplePathX_untilXhasIdX6XX_path_byXnameX_unfold: [function({g, vid6, vid1}) { return g.V(vid1).repeat(__.both().simplePath()).until(__.hasId(vid6)).path().by("name").unfold() }],
- g_VXvid1X_outXcreatedX_asXsoftwareX_V_hasXname_selectXsoftwareX_valuesXnameXX_inXcreatedX_name: [function({g, vid1}) { return g.V(vid1).out("created").as("sw").V().has("name", __.select("sw").values("name")).in_("created").values("name") }],
+ g_VXvid1X_id_VXidentityX_name: [function({g, vid1}) { return g.V(vid1).id().V(__.identity()).values("name") }],
+ g_VXvid1_vid2X_id_VXidentityX_name: [function({g, vid2, vid1}) { return g.V(vid1, vid2).id().V(__.identity()).values("name") }],
+ g_VXvid1X_id_asXbookmarkX_V_hasXname_joshX_VXselectXbookmarkXX_name: [function({g, vid1}) { return g.V(vid1).id().as("bookmark").V().has("name", "josh").V(__.select("bookmark")).values("name") }],
g_VXvid1X_VXoutXknowsX_idX_name: [function({g, vid1}) { return g.V(vid1).V(__.out("knows").id()).values("name") }],
- g_VXvid1X_VXoutXknowsX_hasXname_joshX_idX_valuesXageX: [function({g, vid1}) { return g.V(vid1).V(__.out("knows").has("name", "josh").id()).values("age") }],
- g_VXvid1X_VXoutXknowsX_outXknowsX_idX_name: [function({g, vid1}) { return g.V(vid1).V(__.out("knows").out("knows").id()).values("name") }],
- g_VXvid1X_VXoutXcreatedX_idX_valuesXlangX: [function({g, vid1}) { return g.V(vid1).V(__.out("created").id()).values("lang") }],
g_VXvid1X_EXoutE_idX: [function({g, vid1}) { return g.V(vid1).E(__.outE().id()) }],
- g_VXvid1X_EXoutEXknowsX_hasXweight_05X_idX: [function({g, vid1}) { return g.V(vid1).E(__.outE("knows").has("weight", 0.5).id()) }],
- g_VXvid1X_EXoutXknowsX_outXknowsX_outE_idX: [function({g, vid1}) { return g.V(vid1).E(__.out("knows").out("knows").outE().id()) }],
+ g_injectX9999X_VXidentityX: [function({g}) { return g.inject(9999).V(__.identity()) }],
+ g_VXvid1X_outEXknowsX_hasXinV_name_vadasX_id_EXidentityX: [function({g, vid1}) { return g.V(vid1).outE("knows").filter(__.inV().has("name", "vadas")).id().E(__.identity()) }],
+ g_injectX9999X_EXidentityX: [function({g}) { return g.inject(9999).E(__.identity()) }],
g_VXVXvid1X_idX_name: [function({g, vid1}) { return g.V(__.V(vid1).id()).values("name") }],
g_EXVXvid1X_outE_idX: [function({g, vid1}) { return g.E(__.V(vid1).outE().id()) }],
g_V_valueMap: [function({g}) { return g.V().valueMap() }],
@@ -2126,17 +2153,16 @@ const gremlins = {
g_injectX1_3_100_300X_list: [function({g}) { return g.inject([1, 3, 100, 300]) }],
g_injectX1_3_100_300X_set: [function({g}) { return g.inject(new Set([1, 3, 100, 300])) }],
g_injectX1_1X_set: [function({g}) { return g.inject(new Set([1, 1])) }],
- g_VXvid2X_propertyXalias_VXvid1X_valuesXnameXX: [function({g, vid2, vid1}) { return g.V(vid2).property("alias", __.V(vid1).values("name")) }, function({g, vid2, vid1}) { return g.V().has("alias", "marko") }],
- g_VXvid1X_propertyXcreatorCount_VXvid1X_inXcreatedX_countX: [function({g, vid1}) { return g.V(vid1).property("creatorCount", __.V(vid1).in_("created").count()) }, function({g, vid1}) { return g.V().has("creatorCount", 3) }],
- g_VXvid1X_propertyXknownCount_outXknowsX_countX: [function({g, vid1}) { return g.V(vid1).property("knownCount", __.out("knows").count()) }, function({g, vid1}) { return g.V().has("knownCount", 2) }],
- g_VXvid1X_propertyXcreator_inXcreatedX_valuesXnameXX: [function({g, vid1}) { return g.V(vid1).property("creator", __.in_("created").values("name")) }, function({g, vid1}) { return g.V().has("creator") }],
- g_VXvid2X_propertyXVXvid1X_projectXfriendCount_softwareCreatedXX: [function({g, vid2, vid1}) { return g.V(vid2).property(__.V(vid1).project("friendCount", "softwareCreated").by(__.out("knows").count()).by(__.out("created").values("name"))) }, function({g, vid2, vid1}) { return g.V().has("friendCount", 2) }, function({g, vid2, vid1}) { return g.V().has("softwareCreated", "lop") }],
- g_VXvid2X_propertyXVXvid1X_projectXoriginalName_originalLabelX_byXnameX_byXlabelXX: [function({g, vid2, vid1}) { return g.V(vid2).property(__.V(vid1).project("originalName", "originalLabel").by(__.values("name")).by(__.label())) }, function({g, vid2, vid1}) { return g.V(vid2).has("originalName", "marko") }, function({g, vid2, vid1}) { return g.V(vid2).has("originalLabel", "person") }],
- g_VXvid1X_propertyXlist_friends_outXknowsX_valuesXnameXX: [function({g, vid1}) { return g.V(vid1).property(Cardinality.list, "friends", __.out("knows").values("name")) }, function({g, vid1}) { return g.V(vid1).properties("friends") }],
- g_VXvid1X_propertyXlist_creators_inXcreatedX_valuesXnameXX: [function({g, vid1}) { return g.V(vid1).property(Cardinality.list, "creators", __.in_("created").values("name")) }, function({g, vid1}) { return g.V(vid1).properties("creators") }],
- g_VXvid1X_propertyXset_langs_outXcreatedX_valuesXlangXX: [function({g, vid1}) { return g.V(vid1).property(Cardinality.set, "langs", __.out("created").values("lang")) }, function({g, vid1}) { return g.V(vid1).properties("langs") }],
- g_VXvid1X_propertyXsingle_friend_outXknowsX_valuesXnameXX: [function({g, vid1}) { return g.V(vid1).property(Cardinality.single, "friend", __.out("knows").values("name")) }],
- g_VXvid1X_propertyXVXvid1X_groupX_byXidX_byXvaluesXnameXXX: [function({g, vid1}) { return g.V(vid1).property(__.V(vid1).group().by(__.id()).by(__.values("name"))) }],
+ g_VXvid2X_propertyXalias_VXvid1X_valuesXnameXX: [function({g, vid2, vid1}) { return g.addV("person").property("name", "marko").property("age", 29).addV("person").property("name", "vadas").property("age", 27).addV("software").property("name", "lop").property("lang", "java").addV("person").property("name", "josh").property("age", 32).addV("person").property("name", "peter").property("age", 35).addV("software").property("name", "ripple").property("lang", "java") }, function({g, vid2, vi [...]
+ g_VXvid1X_propertyXcreatorCount_VXvid1X_inXcreatedX_countX: [function({g, vid1}) { return g.addV("person").property("name", "marko").property("age", 29).as("marko").addV("person").property("name", "vadas").property("age", 27).addV("software").property("name", "lop").property("lang", "java").as("lop").addV("person").property("name", "josh").property("age", 32).as("josh").addV("person").property("name", "peter").property("age", 35).as("peter").addV("software").property("name", "ripple" [...]
+ g_VXvid1X_propertyXknownCount_outXknowsX_countX: [function({g, vid1}) { 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").addV("person").property("name", "josh").property("age", 32).as("josh").addV("person").property("name", "peter").property("age", 35).addV("software").property("name", "ripple").property("lang", "j [...]
+ g_VXvid1X_propertyXcreator_inXcreatedX_valuesXnameXX: [function({g, vid1}) { return g.addV("person").property("name", "marko").property("age", 29).as("marko").addV("person").property("name", "vadas").property("age", 27).addV("software").property("name", "lop").property("lang", "java").as("lop").addV("person").property("name", "josh").property("age", 32).as("josh").addV("person").property("name", "peter").property("age", 35).as("peter").addV("software").property("name", "ripple").prop [...]
+ g_VXvid2X_propertyXVXvid1X_projectXfriendCount_softwareCreatedXX: [function({g, vid2, vid1}) { 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("person").property("name", "peter").property("age", 35).as("peter").addV("software").p [...]
+ g_VXvid2X_propertyXVXvid1X_projectXoriginalName_originalLabelX_byXnameX_byXlabelXX: [function({g, vid2, vid1}) { return g.addV("person").property("name", "marko").property("age", 29).as("marko").addV("person").property("name", "vadas").property("age", 27).addV("software").property("name", "lop").property("lang", "java").as("lop").addV("person").property("name", "josh").property("age", 32).addV("person").property("name", "peter").property("age", 35).addV("software").property("name", " [...]
+ g_VXvid1X_propertyXlist_friends_outXknowsX_valuesXnameXX: [function({g, vid1}) { 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").addV("person").property("name", "josh").property("age", 32).as("josh").addV("person").property("name", "peter").property("age", 35).addV("software").property("name", "ripple").property(" [...]
+ g_VXvid1X_propertyXset_langs_outXcreatedX_valuesXlangXX: [function({g, vid1}) { return g.addV("person").property("name", "marko").property("age", 29).addV("person").property("name", "vadas").property("age", 27).addV("software").property("name", "lop").property("lang", "java").as("lop").addV("person").property("name", "josh").property("age", 32).as("josh").addV("person").property("name", "peter").property("age", 35).addV("software").property("name", "ripple").property("lang", "java"). [...]
+ g_VXvid1X_propertyXsingle_friend_outXknowsX_valuesXnameXX: [function({g, vid1}) { 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").addV("person").property("name", "josh").property("age", 32).as("josh").addV("person").property("name", "peter").property("age", 35).addV("software").property("name", "ripple").property( [...]
+ g_VXvid1X_propertyXVXvid1X_groupX_byXidX_byXvaluesXnameXXX: [function({g, vid1}) { return g.addV("person").property("name", "marko").property("age", 29) }, function({g, vid1}) { return g.V(vid1).property(__.V(vid1).group().by(__.id()).by(__.values("name"))) }],
g_io_readXkryoX: [function({g}) { return g.io("data/tinkerpop-modern.kryo").read() }, function({g}) { return g.V() }, function({g}) { return g.E() }],
g_io_read_withXreader_gryoX: [function({g}) { return g.io("data/tinkerpop-modern.kryo").with_(IO.reader, IO.gryo).read() }, function({g}) { return g.V() }, function({g}) { return g.E() }],
g_io_readXgraphsonX: [function({g}) { return g.io("data/tinkerpop-modern.json").read() }, function({g}) { return g.V() }, function({g}) { return g.E() }],
diff --git a/gremlin-python/src/main/python/gremlin_python/process/traversal.py b/gremlin-python/src/main/python/gremlin_python/process/traversal.py
index 76c91822e7..894684f098 100644
--- a/gremlin-python/src/main/python/gremlin_python/process/traversal.py
+++ b/gremlin-python/src/main/python/gremlin_python/process/traversal.py
@@ -359,6 +359,8 @@ class P(object):
return P("within", args[0])
elif len(args) == 1 and type(args[0]) == set:
return P("within", list(args[0]))
+ elif len(args) == 1 and isinstance(args[0], Traversal):
+ return P("within", args[0])
else:
return P("within", list(args))
@@ -368,6 +370,8 @@ class P(object):
return P("without", args[0])
elif len(args) == 1 and type(args[0]) == set:
return P("without", list(args[0]))
+ elif len(args) == 1 and isinstance(args[0], Traversal):
+ return P("without", args[0])
else:
return P("without", list(args))
@@ -964,13 +968,22 @@ class GremlinLang(object):
c = 0
res = [str(p).split('(')[0] + '(']
if isinstance(p.value, list):
- res.append('[')
- for v in p.value:
- if c > 0:
- res.append(',')
- res.append(self._arg_as_string(v))
- c += 1
- res.append(']')
+ # If all elements are Traversals, serialize as comma-separated args (no brackets)
+ # This matches the server grammar: within(trav1, trav2) via genericArgumentVarargs
+ if len(p.value) > 0 and all(isinstance(v, Traversal) for v in p.value):
+ for v in p.value:
+ if c > 0:
+ res.append(',')
+ res.append(self._arg_as_string(v))
+ c += 1
+ else:
+ res.append('[')
+ for v in p.value:
+ if c > 0:
+ res.append(',')
+ res.append(self._arg_as_string(v))
+ c += 1
+ res.append(']')
else:
res.append(self._arg_as_string(p.value))
if p.other is not None:
diff --git a/gremlin-python/src/main/python/tests/feature/gremlin.py b/gremlin-python/src/main/python/tests/feature/gremlin.py
index 5d33607174..c5b2e09b1e 100644
--- a/gremlin-python/src/main/python/tests/feature/gremlin.py
+++ b/gremlin-python/src/main/python/tests/feature/gremlin.py
@@ -510,7 +510,6 @@ world.gremlins = {
'g_V_hasXname_VXvid1X_valuesXnameXX': [(lambda g, vid1=None:g.V().has('name', __.V(vid1).values('name')))],
'g_V_hasXname_VXvid1X_outXknowsX_valuesXnameXX': [(lambda g, vid1=None:g.V().has('name', __.V(vid1).out('knows').values('name')))],
'g_V_hasXage_VXvid1X_outXknowsX_valuesXageXX': [(lambda g, vid1=None:g.V().has('age', __.V(vid1).out('knows').values('age')))],
- 'g_V_hasXname_VXvid1X_outXcreatedX_valuesXnameXX': [(lambda g, vid1=None:g.V().has('name', __.V(vid1).out('created').values('name')))],
'g_V_hasXname_VXvid1X_valuesXnonexistentXX': [(lambda g, vid1=None:g.V().has('name', __.V(vid1).values('nonexistent')))],
'g_V_hasXname_notXidentityXX': [(lambda g:g.V().has('name', __.not_(__.identity())))],
'g_V_hasXage_gtXVXvid1X_valuesXageXXX': [(lambda g, vid1=None:g.V().has('age', P.gt(__.V(vid1).values('age'))))],
@@ -522,6 +521,14 @@ world.gremlins = {
'g_V_hasXage_eqXVXvid1X_valuesXnonexistentXXX': [(lambda g, vid1=None:g.V().has('age', P.eq(__.V(vid1).values('nonexistent'))))],
'g_V_hasXlabel_VXvid1X_labelXX': [(lambda g, vid1=None:g.V().has(T.label, __.V(vid1).label()))],
'g_V_hasXperson_name_VXvid1X_valuesXnameXX_age': [(lambda g, vid1=None:g.V().has('person', 'name', __.V(vid1).values('name')).values('age'))],
+ 'g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_constantXpeterXXX': [(lambda g, vid1=None:g.V().has('name', P.within(__.V(vid1).out('knows').values('name'), __.constant('peter'))))],
+ 'g_V_hasXname_withinXVXvid1X_valuesXnonexistentX_constantXmarkoXXX': [(lambda g, vid1=None:g.V().has('name', P.within(__.V(vid1).values('nonexistent'), __.constant('marko'))))],
+ 'g_V_hasXname_withinXVXvid1X_valuesXnonexistentX_VXvid1X_valuesXnonexistentXXX': [(lambda g, vid1=None:g.V().has('name', P.within(__.V(vid1).values('nonexistent'), __.V(vid1).values('nonexistent'))))],
+ 'g_V_hasXname_withoutXVXvid1X_valuesXnameX_VXvid2X_valuesXnameX_VXvid3X_valuesXnameXXX': [(lambda g, vid3=None,vid2=None,vid1=None:g.V().has('name', P.without(__.V(vid1).values('name'), __.V(vid2).values('name'), __.V(vid3).values('name'))))],
+ 'g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX': [(lambda g, vid3=None,vid1=None:g.V().has('name', P.within(__.V(vid1).out('knows').values('name'), __.V(vid3).out('created').values('name'))))],
+ 'g_V_hasLabelXsoftwareX_hasXname_withoutXVXvid1X_outXcreatedX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX': [(lambda g, vid3=None,vid1=None:g.V().has_label('software').has('name', P.without(__.V(vid1).out('created').values('name'), __.V(vid3).out('created').values('name'))))],
+ 'g_V_hasLabelXpersonX_valuesXageX_isXwithinXVXvid1X_valuesXageX_V_hasXname_lopX_inXcreatedX_valuesXageXXX': [(lambda g, vid1=None:g.V().has_label('person').values('age').is_(P.within(__.V(vid1).values('age'), __.V().has('name', 'lop').in_('created').values('age'))))],
+ 'g_VXvid1X_outEXknowsX_filterXinV_hasXname_withinXV_hasXname_lopX_inXcreatedX_valuesXnameX_V_hasXname_rippleX_inXcreatedX_valuesXnameXXXX': [(lambda g, vid1=None:g.V(vid1).out_e('knows').filter_(__.in_v().has('name', P.within(__.V().has('name', 'lop').in_('created').values('name'), __.V().has('name', 'ripple').in_('created').values('name')))))],
'g_V_properties_hasValueXnullX': [(lambda g:g.V().properties().has_value(None))],
'g_V_properties_hasValueXnull_nullX': [(lambda g:g.V().properties().has_value(None, None))],
'g_V_properties_hasValueXnull_joshX_value': [(lambda g:g.V().properties().has_value(None, 'josh').value())],
@@ -533,6 +540,26 @@ world.gremlins = {
'g_V_valuesXageX_isXgte_29vaarX_isXlt_34varX': [(lambda g, xx1=None,xx2=None:g.V().values('age').is_(P.gte(xx1)).is_(P.lt(xx2)))],
'g_V_whereXinXcreatedX_count_isX1XX_valuesXnameX': [(lambda g:g.V().where(__.in_('created').count().is_(1)).values('name'))],
'g_V_whereXinXcreatedX_count_isXgte_2XX_valuesXnameX': [(lambda g:g.V().where(__.in_('created').count().is_(P.gte(2))).values('name'))],
+ 'g_V_valuesXageX_isXVXvid1X_valuesXageXX': [(lambda g, vid1=None:g.V().values('age').is_(__.V(vid1).values('age')))],
+ 'g_V_valuesXnameX_isXVXvid1X_valuesXnameXX': [(lambda g, vid1=None:g.V().values('name').is_(__.V(vid1).values('name')))],
+ 'g_V_valuesXageX_isXgtXVXvid1X_valuesXageXXX': [(lambda g, vid1=None:g.V().values('age').is_(P.gt(__.V(vid1).values('age'))))],
+ 'g_V_valuesXageX_isXltXVXvid3X_valuesXageXXX': [(lambda g, vid3=None:g.V().values('age').is_(P.lt(__.V(vid3).values('age'))))],
+ 'g_V_valuesXageX_isXneqXVXvid4X_valuesXageXXX': [(lambda g, vid4=None:g.V().values('age').is_(P.neq(__.V(vid4).values('age'))))],
+ 'g_V_valuesXageX_isXwithinXVXvid1X_outXknowsX_valuesXageXXX': [(lambda g, vid1=None:g.V().values('age').is_(P.within(__.V(vid1).out('knows').values('age'))))],
+ 'g_V_valuesXageX_isXVXvid1X_valuesXnonexistentXX': [(lambda g, vid1=None:g.V().values('age').is_(__.V(vid1).values('nonexistent')))],
+ 'g_V_hasLabelXpersonX_valuesXageX_chooseXgtXVXvid1X_valuesXageXX_olderX': [(lambda g, vid1=None:g.V().has_label('person').values('age').choose(P.gt(__.V(vid1).values('age')), __.constant('older than marko'), __.constant('not older')))],
+ 'g_V_hasLabelXpersonX_valuesXageX_chooseXgteXmeanAgeX_aboveX': [(lambda g:g.V().has_label('person').values('age').choose(P.gte(__.V().has_label('person').values('age').mean()), __.constant('above average'), __.constant('below average')))],
+ 'g_VXvid1X_outXknowsX_valuesXageX_fold_allXgteXVXvid2X_valuesXageXXX': [(lambda g, vid2=None,vid1=None:g.V(vid1).out('knows').values('age').fold().all_(P.gte(__.V(vid2).values('age'))))],
+ 'g_VXvid1X_outXknowsX_valuesXageX_fold_allXgtXVXvid2X_valuesXageXXX': [(lambda g, vid2=None,vid1=None:g.V(vid1).out('knows').values('age').fold().all_(P.gt(__.V(vid2).values('age'))))],
+ 'g_VXvid1X_outXknowsX_valuesXageX_fold_anyXeqXVXvid3X_valuesXageXXX': [(lambda g, vid3=None,vid1=None:g.V(vid1).out('knows').values('age').fold().any_(P.eq(__.V(vid3).values('age'))))],
+ 'g_VXvid1X_outXknowsX_valuesXageX_fold_noneXeqXVXvid4X_valuesXageXXX': [(lambda g, vid4=None,vid1=None:g.V(vid1).out('knows').values('age').fold().none(P.eq(__.V(vid4).values('age'))))],
+ 'g_VXvid1X_outXknowsX_valuesXageX_fold_noneXeqXVXvid3X_valuesXageXXX': [(lambda g, vid3=None,vid1=None:g.V(vid1).out('knows').values('age').fold().none(P.eq(__.V(vid3).values('age'))))],
+ 'g_injectXnullX_isXeqXV9999_valuesXnameXXX': [(lambda g:g.inject(None).is_(P.eq(__.V(9999).values('name'))))],
+ 'g_injectXmarkoX_isXV9999_valuesXnameXX': [(lambda g:g.inject('marko').is_(__.V(9999).values('name')))],
+ 'g_injectXmarkoX_chooseXeqXV9999_valuesXnameXX_matched_unmatchedX': [(lambda g:g.inject('marko').choose(P.eq(__.V(9999).values('name')), __.constant('matched'), __.constant('unmatched')))],
+ 'g_injectXlistX_noneXeqXV9999_valuesXnameXXX': [(lambda g:g.inject(['marko', 'josh']).none(P.eq(__.V(9999).values('name'))))],
+ 'g_V_hasXname_eqXV9999_valuesXnameXXX': [(lambda g:g.V().has('name', P.eq(__.V(9999).values('name'))))],
+ 'g_V_valuesXageX_isXwithoutXVXvid1X_valuesXageX_VXvid2X_valuesXageXXX': [(lambda g, vid2=None,vid1=None:g.V().values('age').is_(P.without(__.V(vid1).values('age'), __.V(vid2).values('age'))))],
'g_V_valuesXageX_noneXgtX32XX': [(lambda g:g.V().values('age').none(P.gt(32)))],
'g_V_valuesXageX_whereXisXP_gtX33XXX_fold_noneXlteX33XX': [(lambda g:g.V().values('age').where(__.is_(P.gt(33))).fold().none(P.lte(33)))],
'g_V_valuesXageX_order_byXdescX_fold_noneXltX10XX': [(lambda g:g.V().values('age').order().by(Order.desc).fold().none(P.lt(10)))],
@@ -1769,14 +1796,14 @@ world.gremlins = {
'g_V_localXoutE_foldX_unfold': [(lambda g:g.V().local(__.out_e().fold()).unfold())],
'g_V_valueMap_unfold_mapXselectXkeysXX': [(lambda g:g.V().value_map().unfold().map(__.select(Column.keys)))],
'g_VX1X_repeatXboth_simplePathX_untilXhasIdX6XX_path_byXnameX_unfold': [(lambda g, vid6=None,vid1=None:g.V(vid1).repeat(__.both().simple_path()).until(__.has_id(vid6)).path().by('name').unfold())],
- 'g_VXvid1X_outXcreatedX_asXsoftwareX_V_hasXname_selectXsoftwareX_valuesXnameXX_inXcreatedX_name': [(lambda g, vid1=None:g.V(vid1).out('created').as_('sw').V().has('name', __.select('sw').values('name')).in_('created').values('name'))],
+ 'g_VXvid1X_id_VXidentityX_name': [(lambda g, vid1=None:g.V(vid1).id_().V(__.identity()).values('name'))],
+ 'g_VXvid1_vid2X_id_VXidentityX_name': [(lambda g, vid2=None,vid1=None:g.V(vid1, vid2).id_().V(__.identity()).values('name'))],
+ 'g_VXvid1X_id_asXbookmarkX_V_hasXname_joshX_VXselectXbookmarkXX_name': [(lambda g, vid1=None:g.V(vid1).id_().as_('bookmark').V().has('name', 'josh').V(__.select('bookmark')).values('name'))],
'g_VXvid1X_VXoutXknowsX_idX_name': [(lambda g, vid1=None:g.V(vid1).V(__.out('knows').id_()).values('name'))],
- 'g_VXvid1X_VXoutXknowsX_hasXname_joshX_idX_valuesXageX': [(lambda g, vid1=None:g.V(vid1).V(__.out('knows').has('name', 'josh').id_()).values('age'))],
- 'g_VXvid1X_VXoutXknowsX_outXknowsX_idX_name': [(lambda g, vid1=None:g.V(vid1).V(__.out('knows').out('knows').id_()).values('name'))],
- 'g_VXvid1X_VXoutXcreatedX_idX_valuesXlangX': [(lambda g, vid1=None:g.V(vid1).V(__.out('created').id_()).values('lang'))],
'g_VXvid1X_EXoutE_idX': [(lambda g, vid1=None:g.V(vid1).E(__.out_e().id_()))],
- 'g_VXvid1X_EXoutEXknowsX_hasXweight_05X_idX': [(lambda g, vid1=None:g.V(vid1).E(__.out_e('knows').has('weight', 0.5).id_()))],
- 'g_VXvid1X_EXoutXknowsX_outXknowsX_outE_idX': [(lambda g, vid1=None:g.V(vid1).E(__.out('knows').out('knows').out_e().id_()))],
+ 'g_injectX9999X_VXidentityX': [(lambda g:g.inject(9999).V(__.identity()))],
+ 'g_VXvid1X_outEXknowsX_hasXinV_name_vadasX_id_EXidentityX': [(lambda g, vid1=None:g.V(vid1).out_e('knows').filter_(__.in_v().has('name', 'vadas')).id_().E(__.identity()))],
+ 'g_injectX9999X_EXidentityX': [(lambda g:g.inject(9999).E(__.identity()))],
'g_VXVXvid1X_idX_name': [(lambda g, vid1=None:g.V(__.V(vid1).id_()).values('name'))],
'g_EXVXvid1X_outE_idX': [(lambda g, vid1=None:g.E(__.V(vid1).out_e().id_()))],
'g_V_valueMap': [(lambda g:g.V().value_map())],
@@ -2100,17 +2127,16 @@ world.gremlins = {
'g_injectX1_3_100_300X_list': [(lambda g:g.inject([1, 3, 100, 300]))],
'g_injectX1_3_100_300X_set': [(lambda g:g.inject({1, 3, 100, 300}))],
'g_injectX1_1X_set': [(lambda g:g.inject({1, 1}))],
- 'g_VXvid2X_propertyXalias_VXvid1X_valuesXnameXX': [(lambda g, vid2=None,vid1=None:g.V(vid2).property('alias', __.V(vid1).values('name'))), (lambda g, vid2=None,vid1=None:g.V().has('alias', 'marko'))],
- 'g_VXvid1X_propertyXcreatorCount_VXvid1X_inXcreatedX_countX': [(lambda g, vid1=None:g.V(vid1).property('creatorCount', __.V(vid1).in_('created').count())), (lambda g, vid1=None:g.V().has('creatorCount', long(3)))],
- 'g_VXvid1X_propertyXknownCount_outXknowsX_countX': [(lambda g, vid1=None:g.V(vid1).property('knownCount', __.out('knows').count())), (lambda g, vid1=None:g.V().has('knownCount', long(2)))],
- 'g_VXvid1X_propertyXcreator_inXcreatedX_valuesXnameXX': [(lambda g, vid1=None:g.V(vid1).property('creator', __.in_('created').values('name'))), (lambda g, vid1=None:g.V().has('creator'))],
- 'g_VXvid2X_propertyXVXvid1X_projectXfriendCount_softwareCreatedXX': [(lambda g, vid2=None,vid1=None:g.V(vid2).property(__.V(vid1).project('friendCount', 'softwareCreated').by(__.out('knows').count()).by(__.out('created').values('name')))), (lambda g, vid2=None,vid1=None:g.V().has('friendCount', long(2))), (lambda g, vid2=None,vid1=None:g.V().has('softwareCreated', 'lop'))],
- 'g_VXvid2X_propertyXVXvid1X_projectXoriginalName_originalLabelX_byXnameX_byXlabelXX': [(lambda g, vid2=None,vid1=None:g.V(vid2).property(__.V(vid1).project('originalName', 'originalLabel').by(__.values('name')).by(__.label()))), (lambda g, vid2=None,vid1=None:g.V(vid2).has('originalName', 'marko')), (lambda g, vid2=None,vid1=None:g.V(vid2).has('originalLabel', 'person'))],
- 'g_VXvid1X_propertyXlist_friends_outXknowsX_valuesXnameXX': [(lambda g, vid1=None:g.V(vid1).property(Cardinality.list_, 'friends', __.out('knows').values('name'))), (lambda g, vid1=None:g.V(vid1).properties('friends'))],
- 'g_VXvid1X_propertyXlist_creators_inXcreatedX_valuesXnameXX': [(lambda g, vid1=None:g.V(vid1).property(Cardinality.list_, 'creators', __.in_('created').values('name'))), (lambda g, vid1=None:g.V(vid1).properties('creators'))],
- 'g_VXvid1X_propertyXset_langs_outXcreatedX_valuesXlangXX': [(lambda g, vid1=None:g.V(vid1).property(Cardinality.set_, 'langs', __.out('created').values('lang'))), (lambda g, vid1=None:g.V(vid1).properties('langs'))],
- 'g_VXvid1X_propertyXsingle_friend_outXknowsX_valuesXnameXX': [(lambda g, vid1=None:g.V(vid1).property(Cardinality.single, 'friend', __.out('knows').values('name')))],
- 'g_VXvid1X_propertyXVXvid1X_groupX_byXidX_byXvaluesXnameXXX': [(lambda g, vid1=None:g.V(vid1).property(__.V(vid1).group().by(__.id_()).by(__.values('name'))))],
+ 'g_VXvid2X_propertyXalias_VXvid1X_valuesXnameXX': [(lambda g, vid2=None,vid1=None:g.add_v('person').property('name', 'marko').property('age', 29).add_v('person').property('name', 'vadas').property('age', 27).add_v('software').property('name', 'lop').property('lang', 'java').add_v('person').property('name', 'josh').property('age', 32).add_v('person').property('name', 'peter').property('age', 35).add_v('software').property('name', 'ripple').property('lang', 'java')), (lambda g, vid2=No [...]
+ 'g_VXvid1X_propertyXcreatorCount_VXvid1X_inXcreatedX_countX': [(lambda g, vid1=None:g.add_v('person').property('name', 'marko').property('age', 29).as_('marko').add_v('person').property('name', 'vadas').property('age', 27).add_v('software').property('name', 'lop').property('lang', 'java').as_('lop').add_v('person').property('name', 'josh').property('age', 32).as_('josh').add_v('person').property('name', 'peter').property('age', 35).as_('peter').add_v('software').property('name', 'rip [...]
+ 'g_VXvid1X_propertyXknownCount_outXknowsX_countX': [(lambda g, vid1=None:g.add_v('person').property('name', 'marko').property('age', 29).as_('marko').add_v('person').property('name', 'vadas').property('age', 27).as_('vadas').add_v('software').property('name', 'lop').property('lang', 'java').add_v('person').property('name', 'josh').property('age', 32).as_('josh').add_v('person').property('name', 'peter').property('age', 35).add_v('software').property('name', 'ripple').property('lang', [...]
+ 'g_VXvid1X_propertyXcreator_inXcreatedX_valuesXnameXX': [(lambda g, vid1=None:g.add_v('person').property('name', 'marko').property('age', 29).as_('marko').add_v('person').property('name', 'vadas').property('age', 27).add_v('software').property('name', 'lop').property('lang', 'java').as_('lop').add_v('person').property('name', 'josh').property('age', 32).as_('josh').add_v('person').property('name', 'peter').property('age', 35).as_('peter').add_v('software').property('name', 'ripple'). [...]
+ 'g_VXvid2X_propertyXVXvid1X_projectXfriendCount_softwareCreatedXX': [(lambda g, vid2=None,vid1=None:g.add_v('person').property('name', 'marko').property('age', 29).as_('marko').add_v('person').property('name', 'vadas').property('age', 27).as_('vadas').add_v('software').property('name', 'lop').property('lang', 'java').as_('lop').add_v('person').property('name', 'josh').property('age', 32).as_('josh').add_v('person').property('name', 'peter').property('age', 35).as_('peter').add_v('sof [...]
+ 'g_VXvid2X_propertyXVXvid1X_projectXoriginalName_originalLabelX_byXnameX_byXlabelXX': [(lambda g, vid2=None,vid1=None:g.add_v('person').property('name', 'marko').property('age', 29).as_('marko').add_v('person').property('name', 'vadas').property('age', 27).add_v('software').property('name', 'lop').property('lang', 'java').as_('lop').add_v('person').property('name', 'josh').property('age', 32).add_v('person').property('name', 'peter').property('age', 35).add_v('software').property('na [...]
+ 'g_VXvid1X_propertyXlist_friends_outXknowsX_valuesXnameXX': [(lambda g, vid1=None:g.add_v('person').property('name', 'marko').property('age', 29).as_('marko').add_v('person').property('name', 'vadas').property('age', 27).as_('vadas').add_v('software').property('name', 'lop').property('lang', 'java').add_v('person').property('name', 'josh').property('age', 32).as_('josh').add_v('person').property('name', 'peter').property('age', 35).add_v('software').property('name', 'ripple').propert [...]
+ 'g_VXvid1X_propertyXset_langs_outXcreatedX_valuesXlangXX': [(lambda g, vid1=None:g.add_v('person').property('name', 'marko').property('age', 29).add_v('person').property('name', 'vadas').property('age', 27).add_v('software').property('name', 'lop').property('lang', 'java').as_('lop').add_v('person').property('name', 'josh').property('age', 32).as_('josh').add_v('person').property('name', 'peter').property('age', 35).add_v('software').property('name', 'ripple').property('lang', 'java' [...]
+ 'g_VXvid1X_propertyXsingle_friend_outXknowsX_valuesXnameXX': [(lambda g, vid1=None:g.add_v('person').property('name', 'marko').property('age', 29).as_('marko').add_v('person').property('name', 'vadas').property('age', 27).as_('vadas').add_v('software').property('name', 'lop').property('lang', 'java').add_v('person').property('name', 'josh').property('age', 32).as_('josh').add_v('person').property('name', 'peter').property('age', 35).add_v('software').property('name', 'ripple').proper [...]
+ 'g_VXvid1X_propertyXVXvid1X_groupX_byXidX_byXvaluesXnameXXX': [(lambda g, vid1=None:g.add_v('person').property('name', 'marko').property('age', 29)), (lambda g, vid1=None:g.V(vid1).property(__.V(vid1).group().by(__.id_()).by(__.values('name'))))],
'g_io_readXkryoX': [(lambda g:g.io('data/tinkerpop-modern.kryo').read()), (lambda g:g.V()), (lambda g:g.E())],
'g_io_read_withXreader_gryoX': [(lambda g:g.io('data/tinkerpop-modern.kryo').with_(IO.reader, IO.gryo).read()), (lambda g:g.V()), (lambda g:g.E())],
'g_io_readXgraphsonX': [(lambda g:g.io('data/tinkerpop-modern.json').read()), (lambda g:g.V()), (lambda g:g.E())],
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json
index 856a610026..b19cdfa20f 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json
@@ -19698,7 +19698,7 @@
"language": "g.addV(\"person\").property(null)",
"canonical": "g.addV(\"person\").property(null)",
"anonymized": "g.addV(string0).property(map0)",
- "dotnet": "g.AddV((string) \"person\").Property(null)",
+ "dotnet": "g.AddV((string) \"person\").Property((IDictionary<object, object>) null)",
"go": "g.AddV(\"person\").Property(nil)",
"groovy": "g.addV(\"person\").property(null)",
"java": "g.addV(\"person\").property(null)",
@@ -19756,7 +19756,7 @@
"language": "g.addV(\"foo\").property(Cardinality.set, null)",
"canonical": "g.addV(\"foo\").property(Cardinality.set, null)",
"anonymized": "g.addV(string0).property(Cardinality.set, map0)",
- "dotnet": "g.AddV((string) \"foo\").Property(Cardinality.Set, null)",
+ "dotnet": "g.AddV((string) \"foo\").Property(Cardinality.Set, (IDictionary<object, object>) null)",
"go": "g.AddV(\"foo\").Property(gremlingo.Cardinality.Set, nil)",
"groovy": "g.addV(\"foo\").property(Cardinality.set, null)",
"java": "g.addV(\"foo\").property(Cardinality.set, null)",
@@ -43982,7 +43982,7 @@
"language": "g.V(vid2).property(__.V(vid1).project(\"friendCount\", \"softwareCreated\").by(__.out(\"knows\").count()).by(__.out(\"created\").values(\"name\")))",
"canonical": "g.V(vid2).property(__.V(vid1).project(\"friendCount\", \"softwareCreated\").by(__.out(\"knows\").count()).by(__.out(\"created\").values(\"name\")))",
"anonymized": "g.V(vid2).property(__.V(vid1).project(string0, string1).by(__.out(string2).count()).by(__.out(string3).values(string4)))",
- "dotnet": "g.V(vid2).Property(__.V(vid1).Project<object>(\"friendCount\", \"softwareCreated\").By(__.Out(\"knows\").Count()).By(__.Out(\"created\").Values<object>(\"name\")))",
+ "dotnet": "g.V(vid2).Property((ITraversal) __.V(vid1).Project<object>(\"friendCount\", \"softwareCreated\").By(__.Out(\"knows\").Count()).By(__.Out(\"created\").Values<object>(\"name\")))",
"go": "g.V(vid2).Property(gremlingo.T__.V(vid1).Project(\"friendCount\", \"softwareCreated\").By(gremlingo.T__.Out(\"knows\").Count()).By(gremlingo.T__.Out(\"created\").Values(\"name\")))",
"groovy": "g.V(vid2).property(__.V(vid1).project(\"friendCount\", \"softwareCreated\").by(__.out(\"knows\").count()).by(__.out(\"created\").values(\"name\")))",
"java": "g.V(vid2).property(__.V(vid1).project(\"friendCount\", \"softwareCreated\").by(__.out(\"knows\").count()).by(__.out(\"created\").values(\"name\")))",
@@ -44035,7 +44035,7 @@
"language": "g.V(vid2).property(__.V(vid1).project(\"originalName\", \"originalLabel\").by(__.values(\"name\")).by(__.label()))",
"canonical": "g.V(vid2).property(__.V(vid1).project(\"originalName\", \"originalLabel\").by(__.values(\"name\")).by(__.label()))",
"anonymized": "g.V(vid2).property(__.V(vid1).project(string0, string1).by(__.values(string2)).by(__.label()))",
- "dotnet": "g.V(vid2).Property(__.V(vid1).Project<object>(\"originalName\", \"originalLabel\").By(__.Values<object>(\"name\")).By(__.Label()))",
+ "dotnet": "g.V(vid2).Property((ITraversal) __.V(vid1).Project<object>(\"originalName\", \"originalLabel\").By(__.Values<object>(\"name\")).By(__.Label()))",
"go": "g.V(vid2).Property(gremlingo.T__.V(vid1).Project(\"originalName\", \"originalLabel\").By(gremlingo.T__.Values(\"name\")).By(gremlingo.T__.Label()))",
"groovy": "g.V(vid2).property(__.V(vid1).project(\"originalName\", \"originalLabel\").by(__.values(\"name\")).by(__.label()))",
"java": "g.V(vid2).property(__.V(vid1).project(\"originalName\", \"originalLabel\").by(__.values(\"name\")).by(__.label()))",
@@ -44199,7 +44199,7 @@
"language": "g.V(vid1).property(__.V(vid1).group().by(__.id()).by(__.values(\"name\")))",
"canonical": "g.V(vid1).property(__.V(vid1).group().by(__.id()).by(__.values(\"name\")))",
"anonymized": "g.V(vid1).property(__.V(vid1).group().by(__.id()).by(__.values(string0)))",
- "dotnet": "g.V(vid1).Property(__.V(vid1).Group<object, object>().By(__.Id()).By(__.Values<object>(\"name\")))",
+ "dotnet": "g.V(vid1).Property((ITraversal) __.V(vid1).Group<object, object>().By(__.Id()).By(__.Values<object>(\"name\")))",
"go": "g.V(vid1).Property(gremlingo.T__.V(vid1).Group().By(gremlingo.T__.Id()).By(gremlingo.T__.Values(\"name\")))",
"groovy": "g.V(vid1).property(__.V(vid1).group().by(__.id()).by(__.values(\"name\")))",
"java": "g.V(vid1).property(__.V(vid1).group().by(__.id()).by(__.values(\"name\")))",
(tinkerpop) 10/14: update to restrict mutations in all traversal taking steps.
Posted by xi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
xiazcy pushed a commit to branch steps-taking-traversal-poc
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit 0b6985881e2459b3f224ac8035c42d90b3dab21f
Author: Yang Xia <xi...@gmail.com>
AuthorDate: Wed May 27 13:57:15 2026 -0700
update to restrict mutations in all traversal taking steps.
---
.../process/traversal/util/ChildTraversalValidator.java | 14 +++-----------
.../traversal/util/ChildTraversalValidatorTest.java | 7 ++++---
.../features/filter/ChildTraversalVerification.feature | 14 ++++++++++++--
3 files changed, 19 insertions(+), 16 deletions(-)
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ChildTraversalValidator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ChildTraversalValidator.java
index 95c422eabe..18b35759a2 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ChildTraversalValidator.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ChildTraversalValidator.java
@@ -22,7 +22,6 @@ import org.apache.tinkerpop.gremlin.process.traversal.Step;
import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.process.traversal.step.Mutating;
import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
-import org.apache.tinkerpop.gremlin.process.traversal.step.filter.DropStep;
/**
* Validates child traversals to ensure they do not contain disallowed steps based on the context
@@ -31,8 +30,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.filter.DropStep;
* <p>
* Validation rules:
* <ul>
- * <li><b>FILTER / LOOKUP context:</b> No steps implementing {@link Mutating} are allowed at any nesting depth.</li>
- * <li><b>MUTATION context:</b> Only {@link DropStep} is blocked; other mutating steps are permitted.</li>
+ * <li><b>FILTER / LOOKUP / MUTATION context:</b> No steps implementing {@link Mutating} are allowed at any nesting depth.</li>
* </ul>
* <p>
* Recursion walks both {@link TraversalParent#getLocalChildren()} and
@@ -63,7 +61,7 @@ public final class ChildTraversalValidator {
/**
* Validates a child traversal used in mutation context (property(traversal)).
- * Throws {@link IllegalArgumentException} if a {@link DropStep} is found.
+ * Throws {@link IllegalArgumentException} if any {@link Mutating} step is found.
*/
public static void validateMutationContext(final Traversal.Admin<?, ?> child) {
validateRecursive(child, ChildTraversalContext.MUTATION);
@@ -91,19 +89,13 @@ public final class ChildTraversalValidator {
switch (context) {
case FILTER:
case LOOKUP:
+ case MUTATION:
if (step instanceof Mutating) {
throw new IllegalArgumentException(
"Child traversal in " + context.name().toLowerCase() + " context contains mutating step " +
step.getClass().getSimpleName() + ". Mutating steps are not allowed in this context.");
}
break;
- case MUTATION:
- if (step instanceof DropStep) {
- throw new IllegalArgumentException(
- "Child traversal in mutation context contains DropStep. " +
- "Destructive steps are not allowed inside property(traversal).");
- }
- break;
default:
break;
}
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/ChildTraversalValidatorTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/ChildTraversalValidatorTest.java
index e3b385dd48..b731900276 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/ChildTraversalValidatorTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/ChildTraversalValidatorTest.java
@@ -215,9 +215,10 @@ public class ChildTraversalValidatorTest {
}
@Test
- public void shouldAllowAddVInMutationContext() {
- // addV is allowed in property(traversal) — only DropStep is blocked
- g.V().property(__.V().addV("temp").project("k").by("name"));
+ public void shouldRejectAddVInMutationContext() {
+ // addV is now blocked in property(traversal) — all mutating steps are blocked in all contexts
+ assertThrows(IllegalArgumentException.class, () ->
+ g.V().property(__.V().addV("temp").project("k").by("name")));
}
@Test
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/ChildTraversalVerification.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/ChildTraversalVerification.feature
index 1bd57ef418..eacf7a972a 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/ChildTraversalVerification.feature
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/ChildTraversalVerification.feature
@@ -146,7 +146,7 @@ Feature: Child Traversal Verification - mutating steps blocked in filter/lookup
When iterated to list
Then the traversal will raise an error with message containing text of "mutating step"
- # ===== MUTATION CONTEXT: property(traversal) blocks DropStep but allows other mutations =====
+ # ===== MUTATION CONTEXT: property(traversal) blocks ALL mutating steps =====
@GraphComputerVerificationMidVNotSupported
Scenario: g_V_propertyXV_mapXdropX_projectXxX_byXnameXX_rejected
@@ -156,7 +156,17 @@ Feature: Child Traversal Verification - mutating steps blocked in filter/lookup
g.V().property(__.V().map(__.drop()).project("x").by("name"))
"""
When iterated to list
- Then the traversal will raise an error with message containing text of "DropStep"
+ Then the traversal will raise an error with message containing text of "mutating step"
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_propertyXaddVXtempX_projectXkX_byXnameXX_rejected
+ Given the modern graph
+ And the traversal of
+ """
+ g.V().property(__.addV("temp").project("k").by("name"))
+ """
+ When iterated to list
+ Then the traversal will raise an error with message containing text of "mutating step"
# ===== VALID TRAVERSALS: should NOT be rejected =====
(tinkerpop) 09/14: update to implement where(P)
Posted by xi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
xiazcy pushed a commit to branch steps-taking-traversal-poc
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit 6aac8a0401193f40f476391002b75d8234c2e2f4
Author: Yang Xia <xi...@gmail.com>
AuthorDate: Wed May 27 13:56:25 2026 -0700
update to implement where(P)
---
.../traversal/step/filter/WherePredicateStep.java | 33 ++++-
.../Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs | 7 ++
gremlin-go/driver/cucumber/gremlin.go | 7 ++
.../gremlin-javascript/test/cucumber/gremlin.js | 7 ++
.../src/main/python/tests/feature/gremlin.py | 7 ++
.../gremlin/language/translator/translations.json | 136 +++++++++++++++++++++
.../test/features/filter/WhereTraversal.feature | 122 ++++++++++++++++++
7 files changed, 317 insertions(+), 2 deletions(-)
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WherePredicateStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WherePredicateStep.java
index 77c3f4abc9..ce47519ea7 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WherePredicateStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WherePredicateStep.java
@@ -63,12 +63,15 @@ public final class WherePredicateStep<S> extends FilterStep<S> implements Scopin
this.predicate = (P) predicate;
this.selectKeys = new ArrayList<>();
this.configurePredicates(this.predicate);
+ // Integrate child traversals from the predicate so they participate in cloning/strategy application
+ P.integrateTraversals(this.predicate, this);
}
private void configurePredicates(final P<Object> predicate) {
if (predicate instanceof ConnectiveP)
((ConnectiveP<Object>) predicate).getPredicates().forEach(this::configurePredicates);
- else {
+ else if (!predicate.hasTraversal()) {
+ // Only configure scope keys for non-traversal predicates (string label references)
final String selectKey = getSelectKey(predicate);
this.selectKeys.add(selectKey);
this.scopeKeys.add(selectKey);
@@ -112,6 +115,27 @@ public final class WherePredicateStep<S> extends FilterStep<S> implements Scopin
@Override
protected boolean filter(final Traverser.Admin<S> traverser) {
+ // If the predicate has a child traversal, resolve it and test directly against the
+ // current value (or startKey scope value). This bypasses the scope-label mechanism.
+ if (this.predicate.hasTraversal()) {
+ final Object leftValue;
+ if (null == this.startKey) {
+ final TraversalProduct product = TraversalUtil.produce(traverser, this.traversalRing.next());
+ this.traversalRing.reset();
+ if (!product.isProductive()) return false;
+ leftValue = product.get();
+ } else {
+ final TraversalProduct product = TraversalUtil.produce((S) this.getSafeScopeValue(Pop.last, this.startKey, traverser), this.traversalRing.next());
+ this.traversalRing.reset();
+ if (!product.isProductive()) return false;
+ leftValue = product.get();
+ }
+ this.predicate.resolve(traverser);
+ if (this.predicate.isResolvedEmpty()) return false;
+ return this.predicate.test(leftValue);
+ }
+
+ // Standard scope-label path for non-traversal predicates
final TraversalProduct product = null == this.startKey ?
TraversalUtil.produce(traverser, this.traversalRing.next()) :
TraversalUtil.produce((S) this.getSafeScopeValue(Pop.last, this.startKey, traverser), this.traversalRing.next());
@@ -166,7 +190,12 @@ public final class WherePredicateStep<S> extends FilterStep<S> implements Scopin
@Override
public List<Traversal.Admin<S, ?>> getLocalChildren() {
- return (List) this.traversalRing.getTraversals();
+ final List<Traversal.Admin<S, ?>> children = new ArrayList<>((List) this.traversalRing.getTraversals());
+ // Also expose predicate child traversals for strategy application and cloning
+ final List<Traversal.Admin<?, ?>> predicateTraversals = new ArrayList<>();
+ P.collectTraversals(this.predicate, predicateTraversals);
+ children.addAll((List) predicateTraversals);
+ return children;
}
@Override
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
index d460dcadeb..e54133e1f0 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
@@ -773,6 +773,13 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
{"get_g_V_whereXage_isXgt_30XX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Where(__.Values<object>("age").Is(P.Gt(30)))}},
{"g_V_whereXlabel_isXsoftwareXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Where(__.Label().Is("software"))}},
{"g_V_whereXlabel_isXpersonXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Where(__.Label().Is("person"))}},
+ {"g_V_valuesXageX_whereXgtXVXvid1X_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Where(P.Gt(__.V(p["vid1"]).Values<object>("age")))}},
+ {"g_V_valuesXageX_whereXltXVXvid3X_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Where(P.Lt(__.V(p["vid3"]).Values<object>("age")))}},
+ {"g_V_valuesXageX_whereXeqXVXvid1X_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Where(P.Eq(__.V(p["vid1"]).Values<object>("age")))}},
+ {"g_V_valuesXageX_whereXwithinXVXvid1X_outXknowsX_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Where(P.Within(__.V(p["vid1"]).Out("knows").Values<object>("age")))}},
+ {"g_V_valuesXnameX_whereXneqXVXvid1X_valuesXnameXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name").Where(P.Neq(__.V(p["vid1"]).Values<object>("name")))}},
+ {"g_V_valuesXageX_whereXeqXV9999_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Where(P.Eq(__.V(9999).Values<object>("age")))}},
+ {"g_V_whereXgtXVXvid1X_valuesXageXXX_byXageX_valuesXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Where(P.Gt(__.V(p["vid1"]).Values<object>("age"))).By("age").Values<object>("name")}},
{"g_withStrategiesXAdjacentToIncidentStrategyX_V", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new AdjacentToIncidentStrategy()).V()}},
{"g_withoutStrategiesXAdjacentToIncidentStrategyX_V", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithoutStrategies(typeof(AdjacentToIncidentStrategy)).V()}},
{"g_withStrategiesXAdjacentToIncidentStrategyX_V_out_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new AdjacentToIncidentStrategy()).V().Out().Count()}},
diff --git a/gremlin-go/driver/cucumber/gremlin.go b/gremlin-go/driver/cucumber/gremlin.go
index 60808e97d4..9003f7b3f8 100644
--- a/gremlin-go/driver/cucumber/gremlin.go
+++ b/gremlin-go/driver/cucumber/gremlin.go
@@ -743,6 +743,13 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[
"get_g_V_whereXage_isXgt_30XX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Where(gremlingo.T__.Values("age").Is(gremlingo.P.Gt(30)))}},
"g_V_whereXlabel_isXsoftwareXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Where(gremlingo.T__.Label().Is("software"))}},
"g_V_whereXlabel_isXpersonXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Where(gremlingo.T__.Label().Is("person"))}},
+ "g_V_valuesXageX_whereXgtXVXvid1X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Where(gremlingo.P.Gt(gremlingo.T__.V(p["vid1"]).Values("age")))}},
+ "g_V_valuesXageX_whereXltXVXvid3X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Where(gremlingo.P.Lt(gremlingo.T__.V(p["vid3"]).Values("age")))}},
+ "g_V_valuesXageX_whereXeqXVXvid1X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Where(gremlingo.P.Eq(gremlingo.T__.V(p["vid1"]).Values("age")))}},
+ "g_V_valuesXageX_whereXwithinXVXvid1X_outXknowsX_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Where(gremlingo.P.Within(gremlingo.T__.V(p["vid1"]).Out("knows").Values("age")))}},
+ "g_V_valuesXnameX_whereXneqXVXvid1X_valuesXnameXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("name").Where(gremlingo.P.Neq(gremlingo.T__.V(p["vid1"]).Values("name")))}},
+ "g_V_valuesXageX_whereXeqXV9999_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Where(gremlingo.P.Eq(gremlingo.T__.V(9999).Values("age")))}},
+ "g_V_whereXgtXVXvid1X_valuesXageXXX_byXageX_valuesXnameX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Where(gremlingo.P.Gt(gremlingo.T__.V(p["vid1"]).Values("age"))).By("age").Values("name")}},
"g_withStrategiesXAdjacentToIncidentStrategyX_V": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.WithStrategies(gremlingo.AdjacentToIncidentStrategy()).V()}},
"g_withoutStrategiesXAdjacentToIncidentStrategyX_V": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.WithoutStrategies(gremlingo.AdjacentToIncidentStrategy()).V()}},
"g_withStrategiesXAdjacentToIncidentStrategyX_V_out_count": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.WithStrategies(gremlingo.AdjacentToIncidentStrategy()).V().Out().Count()}},
diff --git a/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js b/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js
index c2a1640ae4..1d705754b8 100644
--- a/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js
+++ b/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js
@@ -774,6 +774,13 @@ const gremlins = {
get_g_V_whereXage_isXgt_30XX: [function({g}) { return g.V().where(__.values("age").is(P.gt(30))) }],
g_V_whereXlabel_isXsoftwareXX: [function({g}) { return g.V().where(__.label().is("software")) }],
g_V_whereXlabel_isXpersonXX: [function({g}) { return g.V().where(__.label().is("person")) }],
+ g_V_valuesXageX_whereXgtXVXvid1X_valuesXageXXX: [function({g, vid1}) { return g.V().values("age").where(P.gt(__.V(vid1).values("age"))) }],
+ g_V_valuesXageX_whereXltXVXvid3X_valuesXageXXX: [function({g, vid3}) { return g.V().values("age").where(P.lt(__.V(vid3).values("age"))) }],
+ g_V_valuesXageX_whereXeqXVXvid1X_valuesXageXXX: [function({g, vid1}) { return g.V().values("age").where(P.eq(__.V(vid1).values("age"))) }],
+ g_V_valuesXageX_whereXwithinXVXvid1X_outXknowsX_valuesXageXXX: [function({g, vid1}) { return g.V().values("age").where(P.within(__.V(vid1).out("knows").values("age"))) }],
+ g_V_valuesXnameX_whereXneqXVXvid1X_valuesXnameXXX: [function({g, vid1}) { return g.V().values("name").where(P.neq(__.V(vid1).values("name"))) }],
+ g_V_valuesXageX_whereXeqXV9999_valuesXageXXX: [function({g}) { return g.V().values("age").where(P.eq(__.V(9999).values("age"))) }],
+ g_V_whereXgtXVXvid1X_valuesXageXXX_byXageX_valuesXnameX: [function({g, vid1}) { return g.V().where(P.gt(__.V(vid1).values("age"))).by("age").values("name") }],
g_withStrategiesXAdjacentToIncidentStrategyX_V: [function({g}) { return g.withStrategies(new AdjacentToIncidentStrategy()).V() }],
g_withoutStrategiesXAdjacentToIncidentStrategyX_V: [function({g}) { return g.withoutStrategies(AdjacentToIncidentStrategy).V() }],
g_withStrategiesXAdjacentToIncidentStrategyX_V_out_count: [function({g}) { return g.withStrategies(new AdjacentToIncidentStrategy()).V().out().count() }],
diff --git a/gremlin-python/src/main/python/tests/feature/gremlin.py b/gremlin-python/src/main/python/tests/feature/gremlin.py
index aa4358cfe7..5928aaedc4 100644
--- a/gremlin-python/src/main/python/tests/feature/gremlin.py
+++ b/gremlin-python/src/main/python/tests/feature/gremlin.py
@@ -748,6 +748,13 @@ world.gremlins = {
'get_g_V_whereXage_isXgt_30XX': [(lambda g:g.V().where(__.values('age').is_(P.gt(30))))],
'g_V_whereXlabel_isXsoftwareXX': [(lambda g:g.V().where(__.label().is_('software')))],
'g_V_whereXlabel_isXpersonXX': [(lambda g:g.V().where(__.label().is_('person')))],
+ 'g_V_valuesXageX_whereXgtXVXvid1X_valuesXageXXX': [(lambda g, vid1=None:g.V().values('age').where(P.gt(__.V(vid1).values('age'))))],
+ 'g_V_valuesXageX_whereXltXVXvid3X_valuesXageXXX': [(lambda g, vid3=None:g.V().values('age').where(P.lt(__.V(vid3).values('age'))))],
+ 'g_V_valuesXageX_whereXeqXVXvid1X_valuesXageXXX': [(lambda g, vid1=None:g.V().values('age').where(P.eq(__.V(vid1).values('age'))))],
+ 'g_V_valuesXageX_whereXwithinXVXvid1X_outXknowsX_valuesXageXXX': [(lambda g, vid1=None:g.V().values('age').where(P.within(__.V(vid1).out('knows').values('age'))))],
+ 'g_V_valuesXnameX_whereXneqXVXvid1X_valuesXnameXXX': [(lambda g, vid1=None:g.V().values('name').where(P.neq(__.V(vid1).values('name'))))],
+ 'g_V_valuesXageX_whereXeqXV9999_valuesXageXXX': [(lambda g:g.V().values('age').where(P.eq(__.V(9999).values('age'))))],
+ 'g_V_whereXgtXVXvid1X_valuesXageXXX_byXageX_valuesXnameX': [(lambda g, vid1=None:g.V().where(P.gt(__.V(vid1).values('age'))).by('age').values('name'))],
'g_withStrategiesXAdjacentToIncidentStrategyX_V': [(lambda g:g.with_strategies(AdjacentToIncidentStrategy()).V())],
'g_withoutStrategiesXAdjacentToIncidentStrategyX_V': [(lambda g:g.without_strategies(AdjacentToIncidentStrategy).V())],
'g_withStrategiesXAdjacentToIncidentStrategyX_V_out_count': [(lambda g:g.with_strategies(AdjacentToIncidentStrategy()).V().out().count())],
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json
index 99148d3a53..1340ec569c 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json
@@ -6516,6 +6516,23 @@
}
]
},
+ {
+ "scenario": "g_V_propertyXaddVXtempX_projectXkX_byXnameXX_rejected",
+ "traversals": [
+ {
+ "original": "g.V().property(__.addV(\"temp\").project(\"k\").by(\"name\"))",
+ "language": "g.V().property(__.addV(\"temp\").project(\"k\").by(\"name\"))",
+ "canonical": "g.V().property(__.addV(\"temp\").project(\"k\").by(\"name\"))",
+ "anonymized": "g.V().property(__.addV(string0).project(string1).by(string2))",
+ "dotnet": "g.V().Property((ITraversal) __.AddV((string) \"temp\").Project<object>(\"k\").By(\"name\"))",
+ "go": "g.V().Property(gremlingo.T__.AddV(\"temp\").Project(\"k\").By(\"name\"))",
+ "groovy": "g.V().property(__.addV(\"temp\").project(\"k\").by(\"name\"))",
+ "java": "g.V().property(__.addV(\"temp\").project(\"k\").by(\"name\"))",
+ "javascript": "g.V().property(__.addV(\"temp\").project(\"k\").by(\"name\"))",
+ "python": "g.V().property(__.add_v('temp').project('k').by('name'))"
+ }
+ ]
+ },
{
"scenario": "g_V_hasXname_VXvid1X_valuesXnameXX_passes_verification",
"traversals": [
@@ -13359,6 +13376,125 @@
}
]
},
+ {
+ "scenario": "g_V_valuesXageX_whereXgtXVXvid1X_valuesXageXXX",
+ "traversals": [
+ {
+ "original": "g.V().values(\"age\").where(P.gt(__.V(vid1).values(\"age\")))",
+ "language": "g.V().values(\"age\").where(P.gt(__.V(vid1).values(\"age\")))",
+ "canonical": "g.V().values(\"age\").where(P.gt(__.V(vid1).values(\"age\")))",
+ "anonymized": "g.V().values(string0).where(P.gt(__.V(vid1).values(string0)))",
+ "dotnet": "g.V().Values<object>(\"age\").Where(P.Gt(__.V(vid1).Values<object>(\"age\")))",
+ "go": "g.V().Values(\"age\").Where(gremlingo.P.Gt(gremlingo.T__.V(vid1).Values(\"age\")))",
+ "groovy": "g.V().values(\"age\").where(P.gt(__.V(vid1).values(\"age\")))",
+ "java": "g.V().values(\"age\").where(P.gt(__.V(vid1).values(\"age\")))",
+ "javascript": "g.V().values(\"age\").where(P.gt(__.V(vid1).values(\"age\")))",
+ "python": "g.V().values('age').where(P.gt(__.V(vid1).values('age')))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_valuesXageX_whereXltXVXvid3X_valuesXageXXX",
+ "traversals": [
+ {
+ "original": "g.V().values(\"age\").where(P.lt(__.V(vid3).values(\"age\")))",
+ "language": "g.V().values(\"age\").where(P.lt(__.V(vid3).values(\"age\")))",
+ "canonical": "g.V().values(\"age\").where(P.lt(__.V(vid3).values(\"age\")))",
+ "anonymized": "g.V().values(string0).where(P.lt(__.V(vid3).values(string0)))",
+ "dotnet": "g.V().Values<object>(\"age\").Where(P.Lt(__.V(vid3).Values<object>(\"age\")))",
+ "go": "g.V().Values(\"age\").Where(gremlingo.P.Lt(gremlingo.T__.V(vid3).Values(\"age\")))",
+ "groovy": "g.V().values(\"age\").where(P.lt(__.V(vid3).values(\"age\")))",
+ "java": "g.V().values(\"age\").where(P.lt(__.V(vid3).values(\"age\")))",
+ "javascript": "g.V().values(\"age\").where(P.lt(__.V(vid3).values(\"age\")))",
+ "python": "g.V().values('age').where(P.lt(__.V(vid3).values('age')))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_valuesXageX_whereXeqXVXvid1X_valuesXageXXX",
+ "traversals": [
+ {
+ "original": "g.V().values(\"age\").where(P.eq(__.V(vid1).values(\"age\")))",
+ "language": "g.V().values(\"age\").where(P.eq(__.V(vid1).values(\"age\")))",
+ "canonical": "g.V().values(\"age\").where(P.eq(__.V(vid1).values(\"age\")))",
+ "anonymized": "g.V().values(string0).where(P.eq(__.V(vid1).values(string0)))",
+ "dotnet": "g.V().Values<object>(\"age\").Where(P.Eq(__.V(vid1).Values<object>(\"age\")))",
+ "go": "g.V().Values(\"age\").Where(gremlingo.P.Eq(gremlingo.T__.V(vid1).Values(\"age\")))",
+ "groovy": "g.V().values(\"age\").where(P.eq(__.V(vid1).values(\"age\")))",
+ "java": "g.V().values(\"age\").where(P.eq(__.V(vid1).values(\"age\")))",
+ "javascript": "g.V().values(\"age\").where(P.eq(__.V(vid1).values(\"age\")))",
+ "python": "g.V().values('age').where(P.eq(__.V(vid1).values('age')))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_valuesXageX_whereXwithinXVXvid1X_outXknowsX_valuesXageXXX",
+ "traversals": [
+ {
+ "original": "g.V().values(\"age\").where(P.within(__.V(vid1).out(\"knows\").values(\"age\")))",
+ "language": "g.V().values(\"age\").where(P.within(__.V(vid1).out(\"knows\").values(\"age\")))",
+ "canonical": "g.V().values(\"age\").where(P.within(__.V(vid1).out(\"knows\").values(\"age\")))",
+ "anonymized": "g.V().values(string0).where(P.within(__.V(vid1).out(string1).values(string0)))",
+ "dotnet": "g.V().Values<object>(\"age\").Where(P.Within(__.V(vid1).Out(\"knows\").Values<object>(\"age\")))",
+ "go": "g.V().Values(\"age\").Where(gremlingo.P.Within(gremlingo.T__.V(vid1).Out(\"knows\").Values(\"age\")))",
+ "groovy": "g.V().values(\"age\").where(P.within(__.V(vid1).out(\"knows\").values(\"age\")))",
+ "java": "g.V().values(\"age\").where(P.within(__.V(vid1).out(\"knows\").values(\"age\")))",
+ "javascript": "g.V().values(\"age\").where(P.within(__.V(vid1).out(\"knows\").values(\"age\")))",
+ "python": "g.V().values('age').where(P.within(__.V(vid1).out('knows').values('age')))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_valuesXnameX_whereXneqXVXvid1X_valuesXnameXXX",
+ "traversals": [
+ {
+ "original": "g.V().values(\"name\").where(P.neq(__.V(vid1).values(\"name\")))",
+ "language": "g.V().values(\"name\").where(P.neq(__.V(vid1).values(\"name\")))",
+ "canonical": "g.V().values(\"name\").where(P.neq(__.V(vid1).values(\"name\")))",
+ "anonymized": "g.V().values(string0).where(P.neq(__.V(vid1).values(string0)))",
+ "dotnet": "g.V().Values<object>(\"name\").Where(P.Neq(__.V(vid1).Values<object>(\"name\")))",
+ "go": "g.V().Values(\"name\").Where(gremlingo.P.Neq(gremlingo.T__.V(vid1).Values(\"name\")))",
+ "groovy": "g.V().values(\"name\").where(P.neq(__.V(vid1).values(\"name\")))",
+ "java": "g.V().values(\"name\").where(P.neq(__.V(vid1).values(\"name\")))",
+ "javascript": "g.V().values(\"name\").where(P.neq(__.V(vid1).values(\"name\")))",
+ "python": "g.V().values('name').where(P.neq(__.V(vid1).values('name')))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_valuesXageX_whereXeqXV9999_valuesXageXXX",
+ "traversals": [
+ {
+ "original": "g.V().values(\"age\").where(P.eq(__.V(9999).values(\"age\")))",
+ "language": "g.V().values(\"age\").where(P.eq(__.V(9999).values(\"age\")))",
+ "canonical": "g.V().values(\"age\").where(P.eq(__.V(9999).values(\"age\")))",
+ "anonymized": "g.V().values(string0).where(P.eq(__.V(number0).values(string0)))",
+ "dotnet": "g.V().Values<object>(\"age\").Where(P.Eq(__.V(9999).Values<object>(\"age\")))",
+ "go": "g.V().Values(\"age\").Where(gremlingo.P.Eq(gremlingo.T__.V(9999).Values(\"age\")))",
+ "groovy": "g.V().values(\"age\").where(P.eq(__.V(9999).values(\"age\")))",
+ "java": "g.V().values(\"age\").where(P.eq(__.V(9999).values(\"age\")))",
+ "javascript": "g.V().values(\"age\").where(P.eq(__.V(9999).values(\"age\")))",
+ "python": "g.V().values('age').where(P.eq(__.V(9999).values('age')))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_whereXgtXVXvid1X_valuesXageXXX_byXageX_valuesXnameX",
+ "traversals": [
+ {
+ "original": "g.V().where(P.gt(__.V(vid1).values(\"age\"))).by(\"age\").values(\"name\")",
+ "language": "g.V().where(P.gt(__.V(vid1).values(\"age\"))).by(\"age\").values(\"name\")",
+ "canonical": "g.V().where(P.gt(__.V(vid1).values(\"age\"))).by(\"age\").values(\"name\")",
+ "anonymized": "g.V().where(P.gt(__.V(vid1).values(string0))).by(string0).values(string1)",
+ "dotnet": "g.V().Where(P.Gt(__.V(vid1).Values<object>(\"age\"))).By(\"age\").Values<object>(\"name\")",
+ "go": "g.V().Where(gremlingo.P.Gt(gremlingo.T__.V(vid1).Values(\"age\"))).By(\"age\").Values(\"name\")",
+ "groovy": "g.V().where(P.gt(__.V(vid1).values(\"age\"))).by(\"age\").values(\"name\")",
+ "java": "g.V().where(P.gt(__.V(vid1).values(\"age\"))).by(\"age\").values(\"name\")",
+ "javascript": "g.V().where(P.gt(__.V(vid1).values(\"age\"))).by(\"age\").values(\"name\")",
+ "python": "g.V().where(P.gt(__.V(vid1).values('age'))).by('age').values('name')"
+ }
+ ]
+ },
{
"scenario": "g_withStrategiesXAdjacentToIncidentStrategyX_V",
"traversals": [
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/WhereTraversal.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/WhereTraversal.feature
new file mode 100644
index 0000000000..cf9628883a
--- /dev/null
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/WhereTraversal.feature
@@ -0,0 +1,122 @@
+# 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.
+
+@StepClassFilter @StepWhere
+Feature: Step - where(P) with traversal-bearing predicates
+
+ # where(P.gt(traversal)) — compare current traverser value against resolved traversal result
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_valuesXageX_whereXgtXVXvid1X_valuesXageXXX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V().values("age").where(P.gt(__.V(vid1).values("age")))
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | d[32].i |
+ | d[35].i |
+
+ # where(P.lt(traversal)) — filter ages less than josh's age
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_valuesXageX_whereXltXVXvid3X_valuesXageXXX
+ Given the modern graph
+ And using the parameter vid3 defined as "v[josh].id"
+ And the traversal of
+ """
+ g.V().values("age").where(P.lt(__.V(vid3).values("age")))
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | d[29].i |
+ | d[27].i |
+
+ # where(P.eq(traversal)) — exact match against resolved value
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_valuesXageX_whereXeqXVXvid1X_valuesXageXXX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V().values("age").where(P.eq(__.V(vid1).values("age")))
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | d[29].i |
+
+ # where(P.within(traversal)) — collection membership against resolved traversal results
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_valuesXageX_whereXwithinXVXvid1X_outXknowsX_valuesXageXXX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V().values("age").where(P.within(__.V(vid1).out("knows").values("age")))
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | d[27].i |
+ | d[32].i |
+
+ # where(P.neq(traversal)) — not equal to resolved value
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_valuesXnameX_whereXneqXVXvid1X_valuesXnameXXX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V().values("name").where(P.neq(__.V(vid1).values("name")))
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | vadas |
+ | lop |
+ | josh |
+ | ripple |
+ | peter |
+
+ # Empty traversal result — filters out (no match)
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_valuesXageX_whereXeqXV9999_valuesXageXXX
+ Given the modern graph
+ And the traversal of
+ """
+ g.V().values("age").where(P.eq(__.V(9999).values("age")))
+ """
+ When iterated to list
+ Then the result should be empty
+
+ # where(P.gt(traversal)) with by() modulator — compare property values
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_whereXgtXVXvid1X_valuesXageXXX_byXageX_valuesXnameX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V().where(P.gt(__.V(vid1).values("age"))).by("age").values("name")
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | josh |
+ | peter |
(tinkerpop) 07/14: Add error throwing for mixed cases instead of silent failure
Posted by xi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
xiazcy pushed a commit to branch steps-taking-traversal-poc
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit 96e921c5ea4e7775f95b5e70f193810c6e092793
Author: Yang Xia <xi...@gmail.com>
AuthorDate: Mon May 25 15:10:35 2026 -0700
Add error throwing for mixed cases instead of silent failure
---
.../tinkerpop/gremlin/process/traversal/P.java | 25 ++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java
index 29d882fa9b..24b7016ae1 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java
@@ -636,6 +636,12 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
}
return new P(Contains.within, traversals);
}
+ // Reject mixed traversals and literals — would silently produce wrong results.
+ if (values != null && values.length > 1 && anyTraversals(values)) {
+ throw new IllegalArgumentException(
+ "Cannot mix traversals and literal values in within(). " +
+ "Use within(__.constant(val1), __.constant(val2)) to wrap all values as traversals.");
+ }
final V[] v = null == values ? (V[]) new Object[] { null } : (V[]) values;
return P.within(Arrays.asList(v));
}
@@ -681,6 +687,12 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
}
return new P(Contains.without, traversals);
}
+ // Reject mixed traversals and literals
+ if (values != null && values.length > 1 && anyTraversals(values)) {
+ throw new IllegalArgumentException(
+ "Cannot mix traversals and literal values in without(). " +
+ "Use without(__.constant(val1), __.constant(val2)) to wrap all values as traversals.");
+ }
final V[] v = null == values ? (V[]) new Object[] { null } : values;
return P.without(Arrays.asList(v));
}
@@ -872,4 +884,17 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
}
return true;
}
+
+ /**
+ * Checks if any element in the array is a {@link Traversal} instance (specifically
+ * {@link org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.DefaultGraphTraversal}).
+ */
+ private static <V> boolean anyTraversals(final V[] values) {
+ for (final V v : values) {
+ if (v instanceof org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.DefaultGraphTraversal) {
+ return true;
+ }
+ }
+ return false;
+ }
}
(tinkerpop) 02/14: Add multi-traversal within()/without() support, fix HasContainer folding to continue past traversal-bearing steps, and reject V(traversal)/E(traversal) at parse time for start steps
Posted by xi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
xiazcy pushed a commit to branch steps-taking-traversal-poc
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit a9b52b44c6c875e8af1d9734569105b44b8a14b6
Author: Yang Xia <xi...@gmail.com>
AuthorDate: Wed May 13 20:12:24 2026 -0700
Add multi-traversal within()/without() support, fix HasContainer folding to continue past traversal-bearing steps, and reject V(traversal)/E(traversal) at parse time for start steps
---
.../grammar/TraversalSourceSpawnMethodVisitor.java | 22 +--
.../gremlin/process/traversal/GremlinLang.java | 11 +-
.../tinkerpop/gremlin/process/traversal/P.java | 149 ++++++++++++++++++-
.../gremlin/process/traversal/PTraversalTest.java | 160 +++++++++++++++++++++
gremlin-language/src/main/antlr4/Gremlin.g4 | 2 -
.../gremlin/language/translator/translations.json | 153 ++++++++++++++++++++
.../test/features/filter/HasTraversal.feature | 121 ++++++++++++++++
.../test/features/filter/IsTraversal.feature | 16 +++
.../optimization/TinkerGraphStepStrategy.java | 9 +-
.../TinkerGraphStepStrategyTraversalTest.java | 55 ++++++-
10 files changed, 678 insertions(+), 20 deletions(-)
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalSourceSpawnMethodVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalSourceSpawnMethodVisitor.java
index bed196c29e..f2ca8b7299 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalSourceSpawnMethodVisitor.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalSourceSpawnMethodVisitor.java
@@ -99,12 +99,13 @@ public class TraversalSourceSpawnMethodVisitor extends DefaultGremlinBaseVisitor
*/
@Override
public GraphTraversal visitTraversalSourceSpawnMethod_E(final GremlinParser.TraversalSourceSpawnMethod_EContext ctx) {
- if (ctx.nestedTraversal() != null) {
- return this.traversalSource.E((Traversal<?, ?>) anonymousVisitor.visitNestedTraversal(ctx.nestedTraversal()));
- }
final Object[] args = antlr.argumentVisitor.parseObjectVarargs(ctx.genericArgumentVarargs());
- if (args.length == 1 && args[0] instanceof Traversal) {
- return this.traversalSource.E((Traversal<?, ?>) args[0]);
+ for (final Object arg : args) {
+ if (arg instanceof Traversal) {
+ throw new IllegalArgumentException(
+ "E(traversal) cannot be used as a start step because there is no Traverser context " +
+ "available to evaluate the child traversal. Use E(traversal) as a mid-traversal step instead.");
+ }
}
return this.traversalSource.E(args);
}
@@ -114,12 +115,13 @@ public class TraversalSourceSpawnMethodVisitor extends DefaultGremlinBaseVisitor
*/
@Override
public GraphTraversal visitTraversalSourceSpawnMethod_V(final GremlinParser.TraversalSourceSpawnMethod_VContext ctx) {
- if (ctx.nestedTraversal() != null) {
- return this.traversalSource.V((Traversal<?, ?>) anonymousVisitor.visitNestedTraversal(ctx.nestedTraversal()));
- }
final Object[] args = antlr.argumentVisitor.parseObjectVarargs(ctx.genericArgumentVarargs());
- if (args.length == 1 && args[0] instanceof Traversal) {
- return this.traversalSource.V((Traversal<?, ?>) args[0]);
+ for (final Object arg : args) {
+ if (arg instanceof Traversal) {
+ throw new IllegalArgumentException(
+ "V(traversal) cannot be used as a start step because there is no Traverser context " +
+ "available to evaluate the child traversal. Use V(traversal) as a mid-traversal step instead.");
+ }
}
return this.traversalSource.V(args);
}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/GremlinLang.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/GremlinLang.java
index 5fd67b617e..f38bb01c4f 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/GremlinLang.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/GremlinLang.java
@@ -314,7 +314,16 @@ public class GremlinLang implements Cloneable, Serializable {
} else if (p.hasTraversal()) {
// Traversal-bearing predicate: serialize as P.op(traversalGremlinLang)
sb.append("P.").append(p.getPredicateName()).append("(");
- sb.append(argAsString(p.getTraversalValue()));
+ if (p.getTraversalValues() != null) {
+ // Multi-traversal predicate (within/without with multiple traversals)
+ final List<Traversal.Admin<?, ?>> traversals = p.getTraversalValues();
+ for (int i = 0; i < traversals.size(); i++) {
+ if (i > 0) sb.append(",");
+ sb.append(argAsString(traversals.get(i)));
+ }
+ } else {
+ sb.append(argAsString(p.getTraversalValue()));
+ }
} else {
sb.append("P.").append(p.getPredicateName()).append("(");
sb.append(argAsString(p.getValue()));
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java
index 4c05bc0135..dbaa10f7da 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java
@@ -56,6 +56,7 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
private boolean isCollection = false;
private boolean resolvedEmpty = false;
private Traversal.Admin<?, ?> traversalValue;
+ private List<Traversal.Admin<?, ?>> traversalValues;
public P(final PBiPredicate<V, V> biPredicate, final V value) {
this.biPredicate = biPredicate;
@@ -108,6 +109,19 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
this.traversalValue = traversalValue;
}
+ /**
+ * Constructs a {@code P} with multiple child traversals whose results are unioned at runtime against the
+ * current traverser. Only valid for collection predicates ({@link Contains#within}, {@link Contains#without}).
+ * The literals and variables are left at their defaults and will be populated when
+ * {@link #resolve(Traverser.Admin)} is called.
+ *
+ * @since 4.0.0
+ */
+ public P(final PBiPredicate<V, V> biPredicate, final List<Traversal.Admin<?, ?>> traversalValues) {
+ this.biPredicate = biPredicate;
+ this.traversalValues = traversalValues;
+ }
+
public PBiPredicate<V, V> getBiPredicate() {
return this.biPredicate;
}
@@ -191,6 +205,8 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
result ^= this.literals.hashCode();
if (null != this.traversalValue)
result ^= this.traversalValue.hashCode();
+ if (null != this.traversalValues)
+ result ^= this.traversalValues.hashCode();
return result;
}
@@ -201,7 +217,8 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
((P) other).getBiPredicate().equals(this.biPredicate) &&
((((P) other).variables == null && this.variables == null) || (((P) other).variables != null && ((P) other).variables.equals(this.variables))) &&
((((P) other).literals == null && this.literals == null) || (((P) other).literals != null && CollectionUtils.isEqualCollection(((P) other).literals, this.literals))) &&
- Objects.equals(((P) other).traversalValue, this.traversalValue);
+ Objects.equals(((P) other).traversalValue, this.traversalValue) &&
+ Objects.equals(((P) other).traversalValues, this.traversalValues);
}
@Override
@@ -234,6 +251,12 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
if (this.traversalValue != null) {
clone.traversalValue = this.traversalValue.clone();
}
+ if (this.traversalValues != null) {
+ clone.traversalValues = new ArrayList<>(this.traversalValues.size());
+ for (final Traversal.Admin<?, ?> tv : this.traversalValues) {
+ clone.traversalValues.add(tv.clone());
+ }
+ }
return clone;
} catch (final CloneNotSupportedException e) {
throw new IllegalStateException(e.getMessage(), e);
@@ -262,7 +285,7 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
* Determines if this predicate holds a child traversal whose result is resolved at runtime.
*/
public boolean hasTraversal() {
- return this.traversalValue != null;
+ return this.traversalValue != null || (this.traversalValues != null && !this.traversalValues.isEmpty());
}
/**
@@ -282,6 +305,16 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
return this.traversalValue;
}
+ /**
+ * Gets the list of child traversal values for multi-traversal predicates (e.g., {@code within(trav1, trav2)}).
+ * Returns {@code null} when this predicate uses a single traversal or literal values.
+ *
+ * @since 4.0.0
+ */
+ public List<Traversal.Admin<?, ?>> getTraversalValues() {
+ return this.traversalValues;
+ }
+
/**
* Resolves the child traversal against the given traverser, replacing the traversal value with the
* resolved literal(s) for this test cycle. If no traversal is present, this method returns immediately.
@@ -289,9 +322,18 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
* <p>For collection predicates ({@link Contains}), all results are collected into the literals
* collection. For all other predicates ({@link Compare}, {@link Text}, etc.), the traversal must
* produce exactly one result or an {@link IllegalArgumentException} is thrown.</p>
+ *
+ * <p>When multiple traversals are present (via {@link #traversalValues}), each traversal is evaluated
+ * independently and results are unioned into a single collection. This is only valid for collection
+ * predicates ({@link Contains#within}, {@link Contains#without}).</p>
*/
@SuppressWarnings("unchecked")
public void resolve(final Traverser.Admin<?> traverser) {
+ if (this.traversalValues != null && !this.traversalValues.isEmpty()) {
+ resolveMultipleTraversals(traverser);
+ return;
+ }
+
if (this.traversalValue == null) return;
// Use prepare + iteration directly to avoid ambiguous overload resolution of applyAll
@@ -329,6 +371,38 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
}
}
+ /**
+ * Resolves multiple child traversals, unioning their results into a single collection.
+ * Only valid for collection predicates ({@link Contains}).
+ */
+ @SuppressWarnings("unchecked")
+ private void resolveMultipleTraversals(final Traverser.Admin<?> traverser) {
+ final List<Object> allResults = new ArrayList<>();
+
+ for (final Traversal.Admin<?, ?> tv : this.traversalValues) {
+ final Traversal.Admin<Object, Object> trav = (Traversal.Admin<Object, Object>) (Traversal.Admin) tv;
+ final Traverser.Admin<Object> split = (Traverser.Admin<Object>) traverser.split();
+ split.setSideEffects(trav.getSideEffects());
+ split.setBulk(1L);
+ trav.reset();
+ trav.addStart(split);
+
+ while (trav.hasNext()) {
+ allResults.add(trav.next());
+ }
+ }
+
+ this.resolvedEmpty = allResults.isEmpty();
+
+ if (allResults.isEmpty()) {
+ this.literals = Collections.emptyList();
+ this.isCollection = false;
+ } else {
+ this.literals = (Collection<V>) (Collection<?>) allResults;
+ this.isCollection = true;
+ }
+ }
+
//////////////// predicate traversal utilities
/**
@@ -344,6 +418,10 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
integrateTraversals(((NotP<?>) p).negate(), parent);
} else if (p.getTraversalValue() != null) {
parent.integrateChild(p.getTraversalValue());
+ } else if (p.getTraversalValues() != null) {
+ for (final Traversal.Admin<?, ?> tv : p.getTraversalValues()) {
+ parent.integrateChild(tv);
+ }
}
}
@@ -360,6 +438,8 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
collectTraversals(((NotP<?>) p).negate(), traversals);
} else if (p.getTraversalValue() != null) {
traversals.add(p.getTraversalValue());
+ } else if (p.getTraversalValues() != null) {
+ traversals.addAll(p.getTraversalValues());
}
}
@@ -539,6 +619,14 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
if (values != null && values.length == 1 && values[0] instanceof Traversal) {
return P.within((Traversal<?, ?>) values[0]);
}
+ // If multiple Traversals are passed, redirect to the multi-traversal overload.
+ if (values != null && values.length > 1 && allTraversals(values)) {
+ final List<Traversal.Admin<?, ?>> traversals = new ArrayList<>(values.length);
+ for (final V v : values) {
+ traversals.add(((Traversal<?, ?>) v).asAdmin());
+ }
+ return new P(Contains.within, traversals);
+ }
final V[] v = null == values ? (V[]) new Object[] { null } : (V[]) values;
return P.within(Arrays.asList(v));
}
@@ -576,6 +664,14 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
if (values != null && values.length == 1 && values[0] instanceof Traversal) {
return P.without((Traversal<?, ?>) values[0]);
}
+ // If multiple Traversals are passed, redirect to the multi-traversal overload.
+ if (values != null && values.length > 1 && allTraversals(values)) {
+ final List<Traversal.Admin<?, ?>> traversals = new ArrayList<>(values.length);
+ for (final V v : values) {
+ traversals.add(((Traversal<?, ?>) v).asAdmin());
+ }
+ return new P(Contains.without, traversals);
+ }
final V[] v = null == values ? (V[]) new Object[] { null } : values;
return P.without(Arrays.asList(v));
}
@@ -665,6 +761,24 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
return new P(Contains.within, traversalValue.asAdmin());
}
+ /**
+ * Determines if a value is within the union of results from multiple child traversals resolved at runtime.
+ * Each traversal is evaluated independently and results are combined into a single collection.
+ *
+ * @since 4.0.0
+ */
+ public static <V> P<V> within(final Traversal<?, ?> first, final Traversal<?, ?> second, final Traversal<?, ?>... more) {
+ final List<Traversal.Admin<?, ?>> traversals = new ArrayList<>(2 + (more != null ? more.length : 0));
+ traversals.add(first.asAdmin());
+ traversals.add(second.asAdmin());
+ if (more != null) {
+ for (final Traversal<?, ?> tv : more) {
+ traversals.add(tv.asAdmin());
+ }
+ }
+ return new P(Contains.within, traversals);
+ }
+
/**
* Determines if a value is not within the results of a child traversal resolved at runtime.
*
@@ -674,6 +788,24 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
return new P(Contains.without, traversalValue.asAdmin());
}
+ /**
+ * Determines if a value is not within the union of results from multiple child traversals resolved at runtime.
+ * Each traversal is evaluated independently and results are combined into a single collection.
+ *
+ * @since 4.0.0
+ */
+ public static <V> P<V> without(final Traversal<?, ?> first, final Traversal<?, ?> second, final Traversal<?, ?>... more) {
+ final List<Traversal.Admin<?, ?>> traversals = new ArrayList<>(2 + (more != null ? more.length : 0));
+ traversals.add(first.asAdmin());
+ traversals.add(second.asAdmin());
+ if (more != null) {
+ for (final Traversal<?, ?> tv : more) {
+ traversals.add(tv.asAdmin());
+ }
+ }
+ return new P(Contains.without, traversals);
+ }
+
/**
* Determines if a value is of a type denoted by {@code GType}.
*
@@ -718,4 +850,17 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
public static <V> P<V> not(final P<V> predicate) {
return predicate.negate();
}
+
+ /**
+ * Checks if all elements in the array are {@link Traversal} instances (specifically
+ * {@link org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.DefaultGraphTraversal}).
+ */
+ private static <V> boolean allTraversals(final V[] values) {
+ for (final V v : values) {
+ if (!(v instanceof org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.DefaultGraphTraversal)) {
+ return false;
+ }
+ }
+ return true;
+ }
}
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTraversalTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTraversalTest.java
index 0485f9e509..3e7af19d8b 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTraversalTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTraversalTest.java
@@ -215,4 +215,164 @@ public class PTraversalTest {
assertThat(p.test(99), is(false));
}
}
+
+ /**
+ * Tests for multi-traversal support in within() and without().
+ * <p>
+ * When multiple traversals are passed to within(trav1, trav2, ...), each traversal is evaluated
+ * independently and results are unioned into a single collection for the Contains test.
+ */
+ public static class MultiTraversalTest {
+
+ private Traverser.Admin<?> createTraverser(final Object value) {
+ return new B_O_Traverser<>(value, 1L);
+ }
+
+ // --- Detection ---
+
+ @Test
+ public void shouldDetectMultipleTraversalsInWithin() {
+ final P<Object> p = P.within(__.constant(1).asAdmin(), __.constant(2).asAdmin());
+ assertThat(p.hasTraversal(), is(true));
+ }
+
+ @Test
+ public void shouldDetectMultipleTraversalsInWithout() {
+ final P<Object> p = P.without(__.constant(1).asAdmin(), __.constant(2).asAdmin());
+ assertThat(p.hasTraversal(), is(true));
+ }
+
+ @Test
+ public void shouldReturnTraversalValuesListForMultiTraversal() {
+ final P<Object> p = P.within(__.constant(1).asAdmin(), __.constant(2).asAdmin());
+ assertThat(p.getTraversalValues() != null, is(true));
+ assertThat(p.getTraversalValues().size(), is(2));
+ }
+
+ @Test
+ public void shouldReturnNullTraversalValueForMultiTraversal() {
+ // Single traversalValue should be null when using multi-traversal form
+ final P<Object> p = P.within(__.constant(1).asAdmin(), __.constant(2).asAdmin());
+ assertThat(p.getTraversalValue() == null, is(true));
+ }
+
+ // --- Resolution and testing ---
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void shouldResolveMultipleTraversalsForWithin() {
+ // within(__.constant(1), __.constant(2)) should union results: [1, 2]
+ final P<Object> p = P.within(__.constant(1).asAdmin(), __.constant(2).asAdmin());
+ p.resolve(createTraverser("start"));
+ assertThat(p.test(1), is(true));
+ assertThat(p.test(2), is(true));
+ assertThat(p.test(3), is(false));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void shouldResolveMultipleTraversalsForWithout() {
+ // without(__.constant(1), __.constant(2)) should union results: [1, 2]
+ final P<Object> p = P.without(__.constant(1).asAdmin(), __.constant(2).asAdmin());
+ p.resolve(createTraverser("start"));
+ assertThat(p.test(1), is(false));
+ assertThat(p.test(2), is(false));
+ assertThat(p.test(3), is(true));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void shouldResolveMultipleTraversalsWithMultipleResultsEach() {
+ // within(__.inject(1,2), __.inject(3,4)) should union: [1, 2, 3, 4]
+ final P<Object> p = P.within(__.inject(1, 2).asAdmin(), __.inject(3, 4).asAdmin());
+ p.resolve(createTraverser("start"));
+ assertThat(p.test(1), is(true));
+ assertThat(p.test(2), is(true));
+ assertThat(p.test(3), is(true));
+ assertThat(p.test(4), is(true));
+ assertThat(p.test(5), is(false));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void shouldHandleEmptyResultFromOneTraversal() {
+ // within(__.inject(1,2), __.limit(0)) where second produces nothing
+ // Should still match on results from first traversal
+ final P<Object> p = P.within(__.inject(1, 2).asAdmin(), __.limit(0).asAdmin());
+ p.resolve(createTraverser("start"));
+ assertThat(p.isResolvedEmpty(), is(false));
+ assertThat(p.test(1), is(true));
+ assertThat(p.test(2), is(true));
+ assertThat(p.test(3), is(false));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void shouldHandleAllEmptyResults() {
+ // within(__.limit(0), __.limit(0)) where both produce nothing
+ final P<Object> p = P.within(__.limit(0).asAdmin(), __.limit(0).asAdmin());
+ p.resolve(createTraverser("start"));
+ assertThat(p.isResolvedEmpty(), is(true));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void shouldResolveThreeTraversals() {
+ // within(__.constant("a"), __.constant("b"), __.constant("c"))
+ final P<Object> p = P.within(__.constant("a").asAdmin(), __.constant("b").asAdmin(), __.constant("c").asAdmin());
+ p.resolve(createTraverser("start"));
+ assertThat(p.test("a"), is(true));
+ assertThat(p.test("b"), is(true));
+ assertThat(p.test("c"), is(true));
+ assertThat(p.test("d"), is(false));
+ }
+
+ // --- Clone independence ---
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void shouldCloneMultiTraversalPredicate() {
+ final P<Object> original = P.within(__.constant(1).asAdmin(), __.constant(2).asAdmin());
+ final P<Object> clone = original.clone();
+
+ // Clone should have independent traversal values
+ assertThat(clone.hasTraversal(), is(true));
+ assertThat(clone.getTraversalValues() != null, is(true));
+ assertThat(clone.getTraversalValues().size(), is(2));
+
+ // Modifying clone should not affect original
+ clone.resolve(createTraverser("start"));
+ assertThat(clone.test(1), is(true));
+ // Original should still be unresolved (literals empty)
+ assertThat(original.getTraversalValues().size(), is(2));
+ }
+
+ // --- Varargs detection ---
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void shouldDetectMultipleTraversalsInVarargs() {
+ // This tests the varargs path: P.within(trav1, trav2) going through within(V... values)
+ final Traversal<?, ?> trav1 = __.constant(10);
+ final Traversal<?, ?> trav2 = __.constant(20);
+ final P<Object> p = (P<Object>) P.within(trav1, trav2);
+ assertThat(p.hasTraversal(), is(true));
+ assertThat(p.getTraversalValues() != null, is(true));
+ assertThat(p.getTraversalValues().size(), is(2));
+ p.resolve(createTraverser("start"));
+ assertThat(p.test(10), is(true));
+ assertThat(p.test(20), is(true));
+ assertThat(p.test(30), is(false));
+ }
+
+ // --- collectTraversals and integrateTraversals ---
+
+ @Test
+ public void shouldCollectTraversalsFromMultiTraversalPredicate() {
+ final P<Object> p = P.within(__.constant(1).asAdmin(), __.constant(2).asAdmin(), __.constant(3).asAdmin());
+ final java.util.List<Traversal.Admin<?, ?>> collected = new java.util.ArrayList<>();
+ P.collectTraversals(p, collected);
+ assertThat(collected.size(), is(3));
+ }
+ }
}
diff --git a/gremlin-language/src/main/antlr4/Gremlin.g4 b/gremlin-language/src/main/antlr4/Gremlin.g4
index 822cb59481..b161a271d3 100644
--- a/gremlin-language/src/main/antlr4/Gremlin.g4
+++ b/gremlin-language/src/main/antlr4/Gremlin.g4
@@ -123,12 +123,10 @@ traversalSourceSpawnMethod_addV
traversalSourceSpawnMethod_E
: K_E LPAREN genericArgumentVarargs RPAREN
- | K_E LPAREN nestedTraversal RPAREN
;
traversalSourceSpawnMethod_V
: K_V LPAREN genericArgumentVarargs RPAREN
- | K_V LPAREN nestedTraversal RPAREN
;
traversalSourceSpawnMethod_inject
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json
index d1305a85ce..856a610026 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json
@@ -9500,6 +9500,142 @@
}
]
},
+ {
+ "scenario": "g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_constantXpeterXXX",
+ "traversals": [
+ {
+ "original": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\"), __.constant(\"peter\")))",
+ "language": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\"), __.constant(\"peter\")))",
+ "canonical": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\"), __.constant(\"peter\")))",
+ "anonymized": "g.V().has(string0, P.within(__.V(vid1).out(string1).values(string0), __.constant(string2)))",
+ "dotnet": "g.V().Has(\"name\", P.Within(__.V(vid1).Out(\"knows\").Values<object>(\"name\"), __.Constant<object>(\"peter\")))",
+ "go": "g.V().Has(\"name\", gremlingo.P.Within(gremlingo.T__.V(vid1).Out(\"knows\").Values(\"name\"), gremlingo.T__.Constant(\"peter\")))",
+ "groovy": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\"), __.constant(\"peter\")))",
+ "java": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\"), __.constant(\"peter\")))",
+ "javascript": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\"), __.constant(\"peter\")))",
+ "python": "g.V().has('name', P.within(__.V(vid1).out('knows').values('name'), __.constant('peter')))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_hasXname_withinXVXvid1X_valuesXnonexistentX_constantXmarkoXXX",
+ "traversals": [
+ {
+ "original": "g.V().has(\"name\", P.within(__.V(vid1).values(\"nonexistent\"), __.constant(\"marko\")))",
+ "language": "g.V().has(\"name\", P.within(__.V(vid1).values(\"nonexistent\"), __.constant(\"marko\")))",
+ "canonical": "g.V().has(\"name\", P.within(__.V(vid1).values(\"nonexistent\"), __.constant(\"marko\")))",
+ "anonymized": "g.V().has(string0, P.within(__.V(vid1).values(string1), __.constant(string2)))",
+ "dotnet": "g.V().Has(\"name\", P.Within(__.V(vid1).Values<object>(\"nonexistent\"), __.Constant<object>(\"marko\")))",
+ "go": "g.V().Has(\"name\", gremlingo.P.Within(gremlingo.T__.V(vid1).Values(\"nonexistent\"), gremlingo.T__.Constant(\"marko\")))",
+ "groovy": "g.V().has(\"name\", P.within(__.V(vid1).values(\"nonexistent\"), __.constant(\"marko\")))",
+ "java": "g.V().has(\"name\", P.within(__.V(vid1).values(\"nonexistent\"), __.constant(\"marko\")))",
+ "javascript": "g.V().has(\"name\", P.within(__.V(vid1).values(\"nonexistent\"), __.constant(\"marko\")))",
+ "python": "g.V().has('name', P.within(__.V(vid1).values('nonexistent'), __.constant('marko')))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_hasXname_withinXVXvid1X_valuesXnonexistentX_VXvid1X_valuesXnonexistentXXX",
+ "traversals": [
+ {
+ "original": "g.V().has(\"name\", P.within(__.V(vid1).values(\"nonexistent\"), __.V(vid1).values(\"nonexistent\")))",
+ "language": "g.V().has(\"name\", P.within(__.V(vid1).values(\"nonexistent\"), __.V(vid1).values(\"nonexistent\")))",
+ "canonical": "g.V().has(\"name\", P.within(__.V(vid1).values(\"nonexistent\"), __.V(vid1).values(\"nonexistent\")))",
+ "anonymized": "g.V().has(string0, P.within(__.V(vid1).values(string1), __.V(vid1).values(string1)))",
+ "dotnet": "g.V().Has(\"name\", P.Within(__.V(vid1).Values<object>(\"nonexistent\"), __.V(vid1).Values<object>(\"nonexistent\")))",
+ "go": "g.V().Has(\"name\", gremlingo.P.Within(gremlingo.T__.V(vid1).Values(\"nonexistent\"), gremlingo.T__.V(vid1).Values(\"nonexistent\")))",
+ "groovy": "g.V().has(\"name\", P.within(__.V(vid1).values(\"nonexistent\"), __.V(vid1).values(\"nonexistent\")))",
+ "java": "g.V().has(\"name\", P.within(__.V(vid1).values(\"nonexistent\"), __.V(vid1).values(\"nonexistent\")))",
+ "javascript": "g.V().has(\"name\", P.within(__.V(vid1).values(\"nonexistent\"), __.V(vid1).values(\"nonexistent\")))",
+ "python": "g.V().has('name', P.within(__.V(vid1).values('nonexistent'), __.V(vid1).values('nonexistent')))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_hasXname_withoutXVXvid1X_valuesXnameX_VXvid2X_valuesXnameX_VXvid3X_valuesXnameXXX",
+ "traversals": [
+ {
+ "original": "g.V().has(\"name\", P.without(__.V(vid1).values(\"name\"), __.V(vid2).values(\"name\"), __.V(vid3).values(\"name\")))",
+ "language": "g.V().has(\"name\", P.without(__.V(vid1).values(\"name\"), __.V(vid2).values(\"name\"), __.V(vid3).values(\"name\")))",
+ "canonical": "g.V().has(\"name\", P.without(__.V(vid1).values(\"name\"), __.V(vid2).values(\"name\"), __.V(vid3).values(\"name\")))",
+ "anonymized": "g.V().has(string0, P.without(__.V(vid1).values(string0), __.V(vid2).values(string0), __.V(vid3).values(string0)))",
+ "dotnet": "g.V().Has(\"name\", P.Without(__.V(vid1).Values<object>(\"name\"), __.V(vid2).Values<object>(\"name\"), __.V(vid3).Values<object>(\"name\")))",
+ "go": "g.V().Has(\"name\", gremlingo.P.Without(gremlingo.T__.V(vid1).Values(\"name\"), gremlingo.T__.V(vid2).Values(\"name\"), gremlingo.T__.V(vid3).Values(\"name\")))",
+ "groovy": "g.V().has(\"name\", P.without(__.V(vid1).values(\"name\"), __.V(vid2).values(\"name\"), __.V(vid3).values(\"name\")))",
+ "java": "g.V().has(\"name\", P.without(__.V(vid1).values(\"name\"), __.V(vid2).values(\"name\"), __.V(vid3).values(\"name\")))",
+ "javascript": "g.V().has(\"name\", P.without(__.V(vid1).values(\"name\"), __.V(vid2).values(\"name\"), __.V(vid3).values(\"name\")))",
+ "python": "g.V().has('name', P.without(__.V(vid1).values('name'), __.V(vid2).values('name'), __.V(vid3).values('name')))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX",
+ "traversals": [
+ {
+ "original": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\"), __.V(vid3).out(\"created\").values(\"name\")))",
+ "language": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\"), __.V(vid3).out(\"created\").values(\"name\")))",
+ "canonical": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\"), __.V(vid3).out(\"created\").values(\"name\")))",
+ "anonymized": "g.V().has(string0, P.within(__.V(vid1).out(string1).values(string0), __.V(vid3).out(string2).values(string0)))",
+ "dotnet": "g.V().Has(\"name\", P.Within(__.V(vid1).Out(\"knows\").Values<object>(\"name\"), __.V(vid3).Out(\"created\").Values<object>(\"name\")))",
+ "go": "g.V().Has(\"name\", gremlingo.P.Within(gremlingo.T__.V(vid1).Out(\"knows\").Values(\"name\"), gremlingo.T__.V(vid3).Out(\"created\").Values(\"name\")))",
+ "groovy": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\"), __.V(vid3).out(\"created\").values(\"name\")))",
+ "java": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\"), __.V(vid3).out(\"created\").values(\"name\")))",
+ "javascript": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\"), __.V(vid3).out(\"created\").values(\"name\")))",
+ "python": "g.V().has('name', P.within(__.V(vid1).out('knows').values('name'), __.V(vid3).out('created').values('name')))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_hasLabelXsoftwareX_hasXname_withoutXVXvid1X_outXcreatedX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX",
+ "traversals": [
+ {
+ "original": "g.V().hasLabel(\"software\").has(\"name\", P.without(__.V(vid1).out(\"created\").values(\"name\"), __.V(vid3).out(\"created\").values(\"name\")))",
+ "language": "g.V().hasLabel(\"software\").has(\"name\", P.without(__.V(vid1).out(\"created\").values(\"name\"), __.V(vid3).out(\"created\").values(\"name\")))",
+ "canonical": "g.V().hasLabel(\"software\").has(\"name\", P.without(__.V(vid1).out(\"created\").values(\"name\"), __.V(vid3).out(\"created\").values(\"name\")))",
+ "anonymized": "g.V().hasLabel(string0).has(string1, P.without(__.V(vid1).out(string2).values(string1), __.V(vid3).out(string2).values(string1)))",
+ "dotnet": "g.V().HasLabel(\"software\").Has(\"name\", P.Without(__.V(vid1).Out(\"created\").Values<object>(\"name\"), __.V(vid3).Out(\"created\").Values<object>(\"name\")))",
+ "go": "g.V().HasLabel(\"software\").Has(\"name\", gremlingo.P.Without(gremlingo.T__.V(vid1).Out(\"created\").Values(\"name\"), gremlingo.T__.V(vid3).Out(\"created\").Values(\"name\")))",
+ "groovy": "g.V().hasLabel(\"software\").has(\"name\", P.without(__.V(vid1).out(\"created\").values(\"name\"), __.V(vid3).out(\"created\").values(\"name\")))",
+ "java": "g.V().hasLabel(\"software\").has(\"name\", P.without(__.V(vid1).out(\"created\").values(\"name\"), __.V(vid3).out(\"created\").values(\"name\")))",
+ "javascript": "g.V().hasLabel(\"software\").has(\"name\", P.without(__.V(vid1).out(\"created\").values(\"name\"), __.V(vid3).out(\"created\").values(\"name\")))",
+ "python": "g.V().has_label('software').has('name', P.without(__.V(vid1).out('created').values('name'), __.V(vid3).out('created').values('name')))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_hasLabelXpersonX_valuesXageX_isXwithinXVXvid1X_valuesXageX_V_hasXname_lopX_inXcreatedX_valuesXageXXX",
+ "traversals": [
+ {
+ "original": "g.V().hasLabel(\"person\").values(\"age\").is(P.within(__.V(vid1).values(\"age\"), __.V().has(\"name\",\"lop\").in(\"created\").values(\"age\")))",
+ "language": "g.V().hasLabel(\"person\").values(\"age\").is(P.within(__.V(vid1).values(\"age\"), __.V().has(\"name\", \"lop\").in(\"created\").values(\"age\")))",
+ "canonical": "g.V().hasLabel(\"person\").values(\"age\").is(P.within(__.V(vid1).values(\"age\"), __.V().has(\"name\", \"lop\").in(\"created\").values(\"age\")))",
+ "anonymized": "g.V().hasLabel(string0).values(string1).is(P.within(__.V(vid1).values(string1), __.V().has(string2, string3).in(string4).values(string1)))",
+ "dotnet": "g.V().HasLabel(\"person\").Values<object>(\"age\").Is(P.Within(__.V(vid1).Values<object>(\"age\"), __.V().Has(\"name\", \"lop\").In(\"created\").Values<object>(\"age\")))",
+ "go": "g.V().HasLabel(\"person\").Values(\"age\").Is(gremlingo.P.Within(gremlingo.T__.V(vid1).Values(\"age\"), gremlingo.T__.V().Has(\"name\", \"lop\").In(\"created\").Values(\"age\")))",
+ "groovy": "g.V().hasLabel(\"person\").values(\"age\").is(P.within(__.V(vid1).values(\"age\"), __.V().has(\"name\", \"lop\").in(\"created\").values(\"age\")))",
+ "java": "g.V().hasLabel(\"person\").values(\"age\").is(P.within(__.V(vid1).values(\"age\"), __.V().has(\"name\", \"lop\").in(\"created\").values(\"age\")))",
+ "javascript": "g.V().hasLabel(\"person\").values(\"age\").is(P.within(__.V(vid1).values(\"age\"), __.V().has(\"name\", \"lop\").in_(\"created\").values(\"age\")))",
+ "python": "g.V().has_label('person').values('age').is_(P.within(__.V(vid1).values('age'), __.V().has('name', 'lop').in_('created').values('age')))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_VXvid1X_outEXknowsX_filterXinV_hasXname_withinXV_hasXname_lopX_inXcreatedX_valuesXnameX_V_hasXname_rippleX_inXcreatedX_valuesXnameXXXX",
+ "traversals": [
+ {
+ "original": "g.V(vid1).outE(\"knows\").filter(__.inV().has(\"name\", P.within(__.V().has(\"name\",\"lop\").in(\"created\").values(\"name\"), __.V().has(\"name\",\"ripple\").in(\"created\").values(\"name\"))))",
+ "language": "g.V(vid1).outE(\"knows\").filter(__.inV().has(\"name\", P.within(__.V().has(\"name\", \"lop\").in(\"created\").values(\"name\"), __.V().has(\"name\", \"ripple\").in(\"created\").values(\"name\"))))",
+ "canonical": "g.V(vid1).outE(\"knows\").filter(__.inV().has(\"name\", P.within(__.V().has(\"name\", \"lop\").in(\"created\").values(\"name\"), __.V().has(\"name\", \"ripple\").in(\"created\").values(\"name\"))))",
+ "anonymized": "g.V(vid1).outE(string0).filter(__.inV().has(string1, P.within(__.V().has(string1, string2).in(string3).values(string1), __.V().has(string1, string4).in(string3).values(string1))))",
+ "dotnet": "g.V(vid1).OutE(\"knows\").Filter(__.InV().Has(\"name\", P.Within(__.V().Has(\"name\", \"lop\").In(\"created\").Values<object>(\"name\"), __.V().Has(\"name\", \"ripple\").In(\"created\").Values<object>(\"name\"))))",
+ "go": "g.V(vid1).OutE(\"knows\").Filter(gremlingo.T__.InV().Has(\"name\", gremlingo.P.Within(gremlingo.T__.V().Has(\"name\", \"lop\").In(\"created\").Values(\"name\"), gremlingo.T__.V().Has(\"name\", \"ripple\").In(\"created\").Values(\"name\"))))",
+ "groovy": "g.V(vid1).outE(\"knows\").filter(__.inV().has(\"name\", P.within(__.V().has(\"name\", \"lop\").in(\"created\").values(\"name\"), __.V().has(\"name\", \"ripple\").in(\"created\").values(\"name\"))))",
+ "java": "g.V(vid1).outE(\"knows\").filter(__.inV().has(\"name\", P.within(__.V().has(\"name\", \"lop\").in(\"created\").values(\"name\"), __.V().has(\"name\", \"ripple\").in(\"created\").values(\"name\"))))",
+ "javascript": "g.V(vid1).outE(\"knows\").filter(__.inV().has(\"name\", P.within(__.V().has(\"name\", \"lop\").in_(\"created\").values(\"name\"), __.V().has(\"name\", \"ripple\").in_(\"created\").values(\"name\"))))",
+ "python": "g.V(vid1).out_e('knows').filter_(__.in_v().has('name', P.within(__.V().has('name', 'lop').in_('created').values('name'), __.V().has('name', 'ripple').in_('created').values('name'))))"
+ }
+ ]
+ },
{
"scenario": "g_V_properties_hasValueXnullX",
"traversals": [
@@ -10010,6 +10146,23 @@
}
]
},
+ {
+ "scenario": "g_V_valuesXageX_isXwithoutXVXvid1X_valuesXageX_VXvid2X_valuesXageXXX",
+ "traversals": [
+ {
+ "original": "g.V().values(\"age\").is(P.without(__.V(vid1).values(\"age\"), __.V(vid2).values(\"age\")))",
+ "language": "g.V().values(\"age\").is(P.without(__.V(vid1).values(\"age\"), __.V(vid2).values(\"age\")))",
+ "canonical": "g.V().values(\"age\").is(P.without(__.V(vid1).values(\"age\"), __.V(vid2).values(\"age\")))",
+ "anonymized": "g.V().values(string0).is(P.without(__.V(vid1).values(string0), __.V(vid2).values(string0)))",
+ "dotnet": "g.V().Values<object>(\"age\").Is(P.Without(__.V(vid1).Values<object>(\"age\"), __.V(vid2).Values<object>(\"age\")))",
+ "go": "g.V().Values(\"age\").Is(gremlingo.P.Without(gremlingo.T__.V(vid1).Values(\"age\"), gremlingo.T__.V(vid2).Values(\"age\")))",
+ "groovy": "g.V().values(\"age\").is(P.without(__.V(vid1).values(\"age\"), __.V(vid2).values(\"age\")))",
+ "java": "g.V().values(\"age\").is(P.without(__.V(vid1).values(\"age\"), __.V(vid2).values(\"age\")))",
+ "javascript": "g.V().values(\"age\").is(P.without(__.V(vid1).values(\"age\"), __.V(vid2).values(\"age\")))",
+ "python": "g.V().values('age').is_(P.without(__.V(vid1).values('age'), __.V(vid2).values('age')))"
+ }
+ ]
+ },
{
"scenario": "g_V_valuesXageX_noneXgtX32XX",
"traversals": [
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/HasTraversal.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/HasTraversal.feature
index 4d38167e4d..a0fb83ae23 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/HasTraversal.feature
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/HasTraversal.feature
@@ -201,3 +201,124 @@ Feature: Step - has() with traversal arguments
Then the result should be unordered
| result |
| d[29].i |
+
+ # Multi-traversal within() where one traversal produces multiple results
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_constantXpeterXXX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V().has("name", P.within(__.V(vid1).out("knows").values("name"), __.constant("peter")))
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | v[vadas] |
+ | v[josh] |
+ | v[peter] |
+
+ # Multi-traversal within() where one traversal produces no results — still matches on the other
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_hasXname_withinXVXvid1X_valuesXnonexistentX_constantXmarkoXXX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V().has("name", P.within(__.V(vid1).values("nonexistent"), __.constant("marko")))
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | v[marko] |
+
+ # Multi-traversal within() where all traversals produce no results — filters everything
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_hasXname_withinXVXvid1X_valuesXnonexistentX_VXvid1X_valuesXnonexistentXXX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V().has("name", P.within(__.V(vid1).values("nonexistent"), __.V(vid1).values("nonexistent")))
+ """
+ When iterated to list
+ Then the result should be empty
+
+ # Multi-traversal without() with three traversals
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_hasXname_withoutXVXvid1X_valuesXnameX_VXvid2X_valuesXnameX_VXvid3X_valuesXnameXXX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And using the parameter vid2 defined as "v[vadas].id"
+ And using the parameter vid3 defined as "v[peter].id"
+ And the traversal of
+ """
+ g.V().has("name", P.without(__.V(vid1).values("name"), __.V(vid2).values("name"), __.V(vid3).values("name")))
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | v[josh] |
+ | v[lop] |
+ | v[ripple] |
+
+ # Multi-traversal within() — union of relationship traversals from different sources
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And using the parameter vid3 defined as "v[josh].id"
+ And the traversal of
+ """
+ g.V().has("name", P.within(__.V(vid1).out("knows").values("name"), __.V(vid3).out("created").values("name")))
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | v[vadas] |
+ | v[josh] |
+ | v[ripple] |
+ | v[lop] |
+
+ # Multi-traversal without() — exclusion from multiple relationship sources
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_hasLabelXsoftwareX_hasXname_withoutXVXvid1X_outXcreatedX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And using the parameter vid3 defined as "v[josh].id"
+ And the traversal of
+ """
+ g.V().hasLabel("software").has("name", P.without(__.V(vid1).out("created").values("name"), __.V(vid3).out("created").values("name")))
+ """
+ When iterated to list
+ Then the result should be empty
+
+ # Multi-traversal within() with is() — cross-label dynamic filtering
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_hasLabelXpersonX_valuesXageX_isXwithinXVXvid1X_valuesXageX_V_hasXname_lopX_inXcreatedX_valuesXageXXX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V().hasLabel("person").values("age").is(P.within(__.V(vid1).values("age"), __.V().has("name","lop").in("created").values("age")))
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | d[29].i |
+ | d[32].i |
+ | d[35].i |
+
+ # Multi-traversal within() — dynamic edge filtering via inV property check
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_VXvid1X_outEXknowsX_filterXinV_hasXname_withinXV_hasXname_lopX_inXcreatedX_valuesXnameX_V_hasXname_rippleX_inXcreatedX_valuesXnameXXXX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V(vid1).outE("knows").filter(__.inV().has("name", P.within(__.V().has("name","lop").in("created").values("name"), __.V().has("name","ripple").in("created").values("name"))))
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | e[marko-knows->josh] |
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/IsTraversal.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/IsTraversal.feature
index 495067b6cb..42b1eb898b 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/IsTraversal.feature
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/IsTraversal.feature
@@ -255,3 +255,19 @@ Feature: Step - is() with traversal-bearing predicates
"""
When iterated to list
Then the result should be empty
+
+ # Multi-traversal without() in is() context
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_valuesXageX_isXwithoutXVXvid1X_valuesXageX_VXvid2X_valuesXageXXX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And using the parameter vid2 defined as "v[josh].id"
+ And the traversal of
+ """
+ g.V().values("age").is(P.without(__.V(vid1).values("age"), __.V(vid2).values("age")))
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | d[27].i |
+ | d[35].i |
diff --git a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/optimization/TinkerGraphStepStrategy.java b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/optimization/TinkerGraphStepStrategy.java
index 8194adc4e0..7b0774eaf7 100644
--- a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/optimization/TinkerGraphStepStrategy.java
+++ b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/optimization/TinkerGraphStepStrategy.java
@@ -56,10 +56,13 @@ public final class TinkerGraphStepStrategy extends AbstractTraversalStrategy<Tra
if (currentStep instanceof HasStep) {
final List<HasContainer> hasContainers = ((HasContainerHolder) currentStep).getHasContainers();
- // skip folding if any HasContainer holds a child traversal — its value
- // is dynamic (resolved per-traverser) and cannot be pushed into TinkerGraphStep
+ // skip folding this HasStep if any HasContainer holds a child traversal —
+ // its value is dynamic (resolved per-traverser) and cannot be pushed into
+ // TinkerGraphStep. Continue to the next step so that subsequent literal
+ // HasSteps can still be folded.
if (hasContainers.stream().anyMatch(HasContainer::hasTraversal)) {
- break;
+ currentStep = currentStep.getNextStep();
+ continue;
}
for (final HasContainer hasContainer : hasContainers) {
diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/optimization/TinkerGraphStepStrategyTraversalTest.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/optimization/TinkerGraphStepStrategyTraversalTest.java
index 5fdfa6fdfd..c7db04b280 100644
--- a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/optimization/TinkerGraphStepStrategyTraversalTest.java
+++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/optimization/TinkerGraphStepStrategyTraversalTest.java
@@ -135,15 +135,44 @@ public class TinkerGraphStepStrategyTraversalTest {
@Test
public void shouldFoldLiteralHasButNotTraversalHasInMixedTraversal() {
// g.V().has("name", "marko").has("age", __.constant(29))
- // The literal has("name", "marko") should be folded, but has("age", traversal) should not
+ // Both containers end up in the same HasStep (TraversalHelper.addHasContainer merges).
+ // The strategy skips the entire HasStep because it contains a traversal-bearing container.
final GraphTraversal<Vertex, Vertex> traversal =
g.V().has("name", "marko").has("age", __.constant(29));
final List<Step> steps = applyStrategy(traversal.asAdmin());
+ // TinkerGraphStep should have NO folded HasContainers (the merged HasStep is skipped)
+ assertThat(steps.get(0), instanceOf(TinkerGraphStep.class));
+ final TinkerGraphStep<?, ?> tinkerGraphStep = (TinkerGraphStep<?, ?>) steps.get(0);
+
+ // The HasStep with both containers should remain as a separate step
+ final boolean hasStepPresent = steps.stream().anyMatch(s -> s instanceof HasStep);
+ assertThat("HasStep with mixed containers should remain as separate step",
+ hasStepPresent, is(true));
+ }
+
+ @Test
+ public void shouldFoldLiteralHasAfterBarrierAndTraversalHas() {
+ // g.V().has("age", __.constant(29)).barrier().has("name", "marko")
+ // The barrier separates the two HasSteps. The strategy should:
+ // - Skip the traversal-bearing HasStep (has("age", traversal))
+ // - Stop at the barrier (not a HasStep or NoOpBarrierStep... actually NoOpBarrierStep IS handled)
+ // Let's use a different separator. Actually NoOpBarrierStep is handled by the while loop.
+ // The key test is: after skipping a traversal-bearing HasStep, the strategy continues
+ // and can fold subsequent literal HasSteps.
+ //
+ // With separate HasSteps (not merged), the strategy should fold the literal one.
+ // We can force separate HasSteps by inserting a NoOpBarrierStep between them.
+ final GraphTraversal<Vertex, Vertex> traversal =
+ g.V().has("age", __.constant(29)).barrier().has("name", "marko");
+ final List<Step> steps = applyStrategy(traversal.asAdmin());
+
// TinkerGraphStep should have the literal "name" HasContainer folded
assertThat(steps.get(0), instanceOf(TinkerGraphStep.class));
final TinkerGraphStep<?, ?> tinkerGraphStep = (TinkerGraphStep<?, ?>) steps.get(0);
- assertThat(tinkerGraphStep.getHasContainers(), hasSize(1));
+ assertThat("Literal HasContainer after barrier should be folded even when preceded by traversal-bearing HasStep",
+ tinkerGraphStep.getHasContainers(), hasSize(1));
+ assertThat(tinkerGraphStep.getHasContainers().get(0).getKey(), is("name"));
// The traversal-bearing HasStep for "age" should remain
final boolean hasStepPresent = steps.stream().anyMatch(s -> s instanceof HasStep);
@@ -151,4 +180,26 @@ public class TinkerGraphStepStrategyTraversalTest {
hasStepPresent, is(true));
}
+ @Test
+ public void shouldFoldMultipleLiteralHasStepsSeparatedByTraversalHas() {
+ // g.V().has("name", "marko").has("age", __.constant(29)).barrier().has("lang", "java")
+ // has("name") is a separate literal HasStep, has("age") is a separate traversal HasStep,
+ // has("lang") is a separate literal HasStep after the barrier.
+ // Strategy should fold both literal HasSteps and skip the traversal one.
+ final GraphTraversal<Vertex, Vertex> traversal =
+ g.V().has("name", "marko").has("age", __.constant(29)).barrier().has("lang", "java");
+ final List<Step> steps = applyStrategy(traversal.asAdmin());
+
+ // TinkerGraphStep should have both literal HasContainers folded ("name" and "lang")
+ assertThat(steps.get(0), instanceOf(TinkerGraphStep.class));
+ final TinkerGraphStep<?, ?> tinkerGraphStep = (TinkerGraphStep<?, ?>) steps.get(0);
+ assertThat("Both literal HasContainers should be folded",
+ tinkerGraphStep.getHasContainers(), hasSize(2));
+
+ // The traversal-bearing HasStep (age) should remain
+ final boolean hasStepPresent = steps.stream().anyMatch(s -> s instanceof HasStep);
+ assertThat("Traversal-bearing HasStep should remain as separate step",
+ hasStepPresent, is(true));
+ }
+
}
(tinkerpop) 04/14: use P.eq() semantics instead of P.with() for has(key, traversal)
Posted by xi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
xiazcy pushed a commit to branch steps-taking-traversal-poc
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit 8e87651de4a633c95c943e7238a22e94c663a4e7
Author: Yang Xia <xi...@gmail.com>
AuthorDate: Wed May 20 16:39:12 2026 -0700
use P.eq() semantics instead of P.with() for has(key, traversal)
---
.../tinkerpop/gremlin/process/traversal/step/filter/HasStep.java | 9 +++++----
.../tinkerpop/gremlin/test/features/filter/HasTraversal.feature | 2 --
2 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/HasStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/HasStep.java
index 07e15f5fd7..65b7eebc89 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/HasStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/HasStep.java
@@ -110,9 +110,9 @@ public class HasStep<S extends Element> extends FilterStep<S> implements HasCont
if (hc.getTraversalValue() != null) {
final List<Object> results = collectTraversalResults(traverser, hc.getTraversalValue());
if (results.isEmpty()) return false;
- // Get the property value to test against
+ // Get the property value to test against — takes first result, ignores extras
final Object propertyValue = getPropertyValueFromProperty(property, hc.getKey());
- if (!P.within(results).test(propertyValue)) return false;
+ if (!P.eq(results.get(0)).test(propertyValue)) return false;
} else if (hc.getPredicate() != null && hc.getPredicate().hasTraversal()) {
hc.getPredicate().resolve(traverser);
if (hc.getPredicate().isResolvedEmpty()) return false;
@@ -133,12 +133,13 @@ public class HasStep<S extends Element> extends FilterStep<S> implements HasCont
private boolean testHasContainer(final Traverser.Admin<S> traverser, final HasContainer hc, final Element element) {
if (hc.hasTraversal()) {
if (hc.getTraversalValue() != null) {
- // Direct traversal value: evaluate and use P.within(results)
+ // Direct traversal value: evaluate and use P.eq(first result) — takes first, ignores extras
+ // Consistent with by(traversal) which also takes the first result silently.
final List<Object> results = collectTraversalResults(traverser, hc.getTraversalValue());
if (results.isEmpty()) return false;
final Object propertyValue = getPropertyValue(element, hc.getKey());
if (propertyValue == null) return false;
- return P.within(results).test(propertyValue);
+ return P.eq(results.get(0)).test(propertyValue);
} else if (hc.getPredicate() != null && hc.getPredicate().hasTraversal()) {
// Predicate with embedded traversal: resolve then test normally
hc.getPredicate().resolve(traverser);
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/HasTraversal.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/HasTraversal.feature
index a0fb83ae23..3f2f924af2 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/HasTraversal.feature
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/HasTraversal.feature
@@ -43,7 +43,6 @@ Feature: Step - has() with traversal arguments
Then the result should be unordered
| result |
| v[vadas] |
- | v[josh] |
@GraphComputerVerificationMidVNotSupported
Scenario: g_V_hasXage_VXvid1X_outXknowsX_valuesXageXX
@@ -57,7 +56,6 @@ Feature: Step - has() with traversal arguments
Then the result should be unordered
| result |
| v[vadas] |
- | v[josh] |
@GraphComputerVerificationMidVNotSupported
Scenario: g_V_hasXname_VXvid1X_valuesXnonexistentXX
(tinkerpop) 12/14: update within() to take first result
Posted by xi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
xiazcy pushed a commit to branch steps-taking-traversal-poc
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit 54e04f6d2f51b8dba13bcd64e50098a424d9aee3
Author: Yang Xia <xi...@gmail.com>
AuthorDate: Wed Jun 3 10:25:25 2026 -0700
update within() to take first result
---
.../tinkerpop/gremlin/process/traversal/P.java | 60 ++++-----
.../gremlin/process/traversal/PTraversalTest.java | 14 ++-
.../Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs | 14 +--
gremlin-go/driver/cucumber/gremlin.go | 14 +--
.../gremlin-javascript/test/cucumber/gremlin.js | 14 +--
.../src/main/python/tests/feature/gremlin.py | 14 +--
.../gremlin/language/translator/translations.json | 140 ++++++++++-----------
.../test/features/filter/HasTraversal.feature | 14 +--
.../test/features/filter/IsTraversal.feature | 2 +-
.../test/features/filter/WhereTraversal.feature | 2 +-
10 files changed, 147 insertions(+), 141 deletions(-)
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java
index 80779cd56a..72cd3bcc5d 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java
@@ -321,13 +321,14 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
* Resolves the child traversal against the given traverser, replacing the traversal value with the
* resolved literal(s) for this test cycle. If no traversal is present, this method returns immediately.
*
- * <p>For collection predicates ({@link Contains}), all results are collected into the literals
- * collection. For all other predicates ({@link Compare}, {@link Text}, etc.), the traversal must
- * produce exactly one result or an {@link IllegalArgumentException} is thrown.</p>
+ * <p>For all predicates, only the first result from the child traversal is used,
+ * consistent with {@code by(traversal)} semantics. For collection predicates
+ * ({@link Contains#within}, {@link Contains#without}), the first result should be a
+ * {@link Collection} (e.g., produced by {@code fold()}).</p>
*
* <p>When multiple traversals are present (via {@link #traversalValues}), each traversal is evaluated
- * independently and results are unioned into a single collection. This is only valid for collection
- * predicates ({@link Contains#within}, {@link Contains#without}).</p>
+ * independently, the first result from each is taken, and results are combined into a single collection.
+ * This is only valid for collection predicates ({@link Contains#within}, {@link Contains#without}).</p>
*/
@SuppressWarnings("unchecked")
public void resolve(final Traverser.Admin<?> traverser) {
@@ -348,28 +349,24 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
this.isCollection = false;
try {
- if (this.biPredicate instanceof Contains) {
- // Collection predicates (within, without) need all results
- final List<Object> results = new ArrayList<>();
- while (trav.hasNext()) {
- results.add(trav.next());
- }
- this.resolvedEmpty = results.isEmpty();
- if (!results.isEmpty()) {
- this.literals = (Collection<V>) (Collection<?>) results;
- this.isCollection = true;
- } else {
- this.literals = Collections.emptyList();
- }
+ // All predicates take only the first result — consistent with by(traversal).
+ // For within/without, the first result should be a Collection (e.g., from fold()).
+ if (!trav.hasNext()) {
+ this.resolvedEmpty = true;
+ this.literals = Collections.emptyList();
} else {
- // Single-value predicates (Compare, Text, etc.) only need the first result.
- // Stop immediately — consistent with by(traversal) and has(key, traversal).
- if (!trav.hasNext()) {
- this.resolvedEmpty = true;
- this.literals = Collections.emptyList();
+ this.resolvedEmpty = false;
+ final Object firstResult = trav.next();
+ if (this.biPredicate instanceof Contains && firstResult instanceof Collection) {
+ // The traversal produced a Collection as its first result — use it directly
+ this.literals = (Collection<V>) firstResult;
+ this.isCollection = true;
+ } else if (this.biPredicate instanceof Contains) {
+ // Single non-Collection value for within/without — wrap in a singleton list
+ this.literals = Collections.singletonList((V) firstResult);
+ this.isCollection = true;
} else {
- this.resolvedEmpty = false;
- this.literals = Collections.singleton((V) trav.next());
+ this.literals = Collections.singleton((V) firstResult);
}
}
} finally {
@@ -378,7 +375,7 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
}
/**
- * Resolves multiple child traversals, unioning their results into a single collection.
+ * Resolves multiple child traversals, taking the first result from each and combining into a collection.
* Only valid for collection predicates ({@link Contains}).
*/
@SuppressWarnings("unchecked")
@@ -394,8 +391,15 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
trav.addStart(split);
try {
- while (trav.hasNext()) {
- allResults.add(trav.next());
+ // Take only the first result from each traversal — consistent with by(traversal).
+ // If the first result is a Collection (from fold()), unpack it into the results.
+ if (trav.hasNext()) {
+ final Object firstResult = trav.next();
+ if (firstResult instanceof Collection) {
+ allResults.addAll((Collection<?>) firstResult);
+ } else {
+ allResults.add(firstResult);
+ }
}
} finally {
CloseableIterator.closeIterator(trav);
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTraversalTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTraversalTest.java
index 40200c8eaa..010965c3f9 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTraversalTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTraversalTest.java
@@ -163,7 +163,8 @@ public class PTraversalTest {
@SuppressWarnings("unchecked")
@Test
public void shouldAcceptMultipleResultsForWithin() {
- final P<Object> p = P.within(__.inject(1, 2, 3).asAdmin());
+ // within(traversal) takes first result only. Use fold() to get a collection.
+ final P<Object> p = P.within(__.inject(1, 2, 3).fold().asAdmin());
p.resolve(createTraverser("start"));
// After resolve, the predicate should have the collection value and be testable
assertThat(p.test(1), is(true));
@@ -175,7 +176,8 @@ public class PTraversalTest {
@SuppressWarnings("unchecked")
@Test
public void shouldAcceptMultipleResultsForWithout() {
- final P<Object> p = P.without(__.inject(1, 2, 3).asAdmin());
+ // without(traversal) takes first result only. Use fold() to get a collection.
+ final P<Object> p = P.without(__.inject(1, 2, 3).fold().asAdmin());
p.resolve(createTraverser("start"));
// After resolve, without should exclude the resolved values
assertThat(p.test(1), is(false));
@@ -303,8 +305,8 @@ public class PTraversalTest {
@SuppressWarnings("unchecked")
@Test
public void shouldResolveMultipleTraversalsWithMultipleResultsEach() {
- // within(__.inject(1,2), __.inject(3,4)) should union: [1, 2, 3, 4]
- final P<Object> p = P.within(__.inject(1, 2).asAdmin(), __.inject(3, 4).asAdmin());
+ // within(__.inject(1,2).fold(), __.inject(3,4).fold()) — each fold() produces a list, unpacked into union
+ final P<Object> p = P.within(__.inject(1, 2).fold().asAdmin(), __.inject(3, 4).fold().asAdmin());
p.resolve(createTraverser("start"));
assertThat(p.test(1), is(true));
assertThat(p.test(2), is(true));
@@ -316,9 +318,9 @@ public class PTraversalTest {
@SuppressWarnings("unchecked")
@Test
public void shouldHandleEmptyResultFromOneTraversal() {
- // within(__.inject(1,2), __.limit(0)) where second produces nothing
+ // within(__.inject(1,2).fold(), __.limit(0)) where second produces nothing
// Should still match on results from first traversal
- final P<Object> p = P.within(__.inject(1, 2).asAdmin(), __.limit(0).asAdmin());
+ final P<Object> p = P.within(__.inject(1, 2).fold().asAdmin(), __.limit(0).asAdmin());
p.resolve(createTraverser("start"));
assertThat(p.isResolvedEmpty(), is(false));
assertThat(p.test(1), is(true));
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
index c99098cfce..e6040f7ba8 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
@@ -563,14 +563,14 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
{"g_V_hasXage_eqXVXvid1X_valuesXnonexistentXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("age", P.Eq(__.V(p["vid1"]).Values<object>("nonexistent")))}},
{"g_V_hasXlabel_VXvid1X_labelXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has(T.Label, __.V(p["vid1"]).Label())}},
{"g_V_hasXperson_name_VXvid1X_valuesXnameXX_age", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("person", "name", __.V(p["vid1"]).Values<object>("name")).Values<object>("age")}},
- {"g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_constantXpeterXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name", P.Within(__.V(p["vid1"]).Out("knows").Values<object>("name"), __.Constant<object>("peter")))}},
+ {"g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_constantXpeterXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name", P.Within(__.V(p["vid1"]).Out("knows").Values<object>("name").Fold(), __.Constant<object>("peter")))}},
{"g_V_hasXname_withinXVXvid1X_valuesXnonexistentX_constantXmarkoXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name", P.Within(__.V(p["vid1"]).Values<object>("nonexistent"), __.Constant<object>("marko")))}},
{"g_V_hasXname_withinXVXvid1X_valuesXnonexistentX_VXvid1X_valuesXnonexistentXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name", P.Within(__.V(p["vid1"]).Values<object>("nonexistent"), __.V(p["vid1"]).Values<object>("nonexistent")))}},
{"g_V_hasXname_withoutXVXvid1X_valuesXnameX_VXvid2X_valuesXnameX_VXvid3X_valuesXnameXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name", P.Without(__.V(p["vid1"]).Values<object>("name"), __.V(p["vid2"]).Values<object>("name"), __.V(p["vid3"]).Values<object>("name")))}},
- {"g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name", P.Within(__.V(p["vid1"]).Out("knows").Values<object>("name"), __.V(p["vid3"]).Out("created").Values<object>("name")))}},
- {"g_V_hasLabelXsoftwareX_hasXname_withoutXVXvid1X_outXcreatedX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("software").Has("name", P.Without(__.V(p["vid1"]).Out("created").Values<object>("name"), __.V(p["vid3"]).Out("created").Values<object>("name")))}},
- {"g_V_hasLabelXpersonX_valuesXageX_isXwithinXVXvid1X_valuesXageX_V_hasXname_lopX_inXcreatedX_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Values<object>("age").Is(P.Within(__.V(p["vid1"]).Values<object>("age"), __.V().Has("name", "lop").In("created").Values<object>("age")))}},
- {"g_VXvid1X_outEXknowsX_filterXinV_hasXname_withinXV_hasXname_lopX_inXcreatedX_valuesXnameX_V_hasXname_rippleX_inXcreatedX_valuesXnameXXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).OutE("knows").Filter(__.InV().Has("name", P.Within(__.V().Has("name", "lop").In("created").Values<object>("name"), __.V().Has("name", "ripple").In("created").Values<object>("name"))))}},
+ {"g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name", P.Within(__.V(p["vid1"]).Out("knows").Values<object>("name").Fold(), __.V(p["vid3"]).Out("created").Values<object>("name").Fold()))}},
+ {"g_V_hasLabelXsoftwareX_hasXname_withoutXVXvid1X_outXcreatedX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("software").Has("name", P.Without(__.V(p["vid1"]).Out("created").Values<object>("name").Fold(), __.V(p["vid3"]).Out("created").Values<object>("name").Fold()))}},
+ {"g_V_hasLabelXpersonX_valuesXageX_isXwithinXVXvid1X_valuesXageX_V_hasXname_lopX_inXcreatedX_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Values<object>("age").Is(P.Within(__.V(p["vid1"]).Values<object>("age").Fold(), __.V().Has("name", "lop").In("created").Values<object>("age").Fold()))}},
+ {"g_VXvid1X_outEXknowsX_filterXinV_hasXname_withinXV_hasXname_lopX_inXcreatedX_valuesXnameX_V_hasXname_rippleX_inXcreatedX_valuesXnameXXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).OutE("knows").Filter(__.InV().Has("name", P.Within(__.V().Has("name", "lop").In("created").Values<object>("name").Fold(), __.V().Has("name", "ripple").In("created").Values<object>("name").Fold())))}},
{"g_V_properties_hasValueXnullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Properties<object>().HasValue((object) null)}},
{"g_V_properties_hasValueXnull_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Properties<object>().HasValue(null, null)}},
{"g_V_properties_hasValueXnull_joshX_value", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Properties<object>().HasValue(null, "josh").Value<object>()}},
@@ -587,7 +587,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
{"g_V_valuesXageX_isXgtXVXvid1X_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Is(P.Gt(__.V(p["vid1"]).Values<object>("age")))}},
{"g_V_valuesXageX_isXltXVXvid3X_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Is(P.Lt(__.V(p["vid3"]).Values<object>("age")))}},
{"g_V_valuesXageX_isXneqXVXvid4X_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Is(P.Neq(__.V(p["vid4"]).Values<object>("age")))}},
- {"g_V_valuesXageX_isXwithinXVXvid1X_outXknowsX_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Is(P.Within(__.V(p["vid1"]).Out("knows").Values<object>("age")))}},
+ {"g_V_valuesXageX_isXwithinXVXvid1X_outXknowsX_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Is(P.Within(__.V(p["vid1"]).Out("knows").Values<object>("age").Fold()))}},
{"g_V_valuesXageX_isXVXvid1X_valuesXnonexistentXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Is(__.V(p["vid1"]).Values<object>("nonexistent"))}},
{"g_V_hasLabelXpersonX_valuesXageX_chooseXgtXVXvid1X_valuesXageXX_olderX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Values<object>("age").Choose<object>(P.Gt(__.V(p["vid1"]).Values<object>("age")), __.Constant<object>("older than marko"), __.Constant<object>("not older"))}},
{"g_V_hasLabelXpersonX_valuesXageX_chooseXgteXmeanAgeX_aboveX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Values<object>("age").Choose<object>(P.Gte(__.V().HasLabel("person").Values<object>("age").Mean<object>()), __.Constant<object>("above average"), __.Constant<object>("below average"))}},
@@ -777,7 +777,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
{"g_V_valuesXageX_whereXgtXVXvid1X_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Where(P.Gt(__.V(p["vid1"]).Values<object>("age")))}},
{"g_V_valuesXageX_whereXltXVXvid3X_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Where(P.Lt(__.V(p["vid3"]).Values<object>("age")))}},
{"g_V_valuesXageX_whereXeqXVXvid1X_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Where(P.Eq(__.V(p["vid1"]).Values<object>("age")))}},
- {"g_V_valuesXageX_whereXwithinXVXvid1X_outXknowsX_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Where(P.Within(__.V(p["vid1"]).Out("knows").Values<object>("age")))}},
+ {"g_V_valuesXageX_whereXwithinXVXvid1X_outXknowsX_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Where(P.Within(__.V(p["vid1"]).Out("knows").Values<object>("age").Fold()))}},
{"g_V_valuesXnameX_whereXneqXVXvid1X_valuesXnameXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name").Where(P.Neq(__.V(p["vid1"]).Values<object>("name")))}},
{"g_V_valuesXageX_whereXeqXV9999_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Where(P.Eq(__.V(9999).Values<object>("age")))}},
{"g_V_whereXgtXVXvid1X_valuesXageXXX_byXageX_valuesXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Where(P.Gt(__.V(p["vid1"]).Values<object>("age"))).By("age").Values<object>("name")}},
diff --git a/gremlin-go/driver/cucumber/gremlin.go b/gremlin-go/driver/cucumber/gremlin.go
index 93905479c5..1a7bf90d0c 100644
--- a/gremlin-go/driver/cucumber/gremlin.go
+++ b/gremlin-go/driver/cucumber/gremlin.go
@@ -533,14 +533,14 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[
"g_V_hasXage_eqXVXvid1X_valuesXnonexistentXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("age", gremlingo.P.Eq(gremlingo.T__.V(p["vid1"]).Values("nonexistent")))}},
"g_V_hasXlabel_VXvid1X_labelXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has(gremlingo.T.Label, gremlingo.T__.V(p["vid1"]).Label())}},
"g_V_hasXperson_name_VXvid1X_valuesXnameXX_age": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("person", "name", gremlingo.T__.V(p["vid1"]).Values("name")).Values("age")}},
- "g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_constantXpeterXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.P.Within(gremlingo.T__.V(p["vid1"]).Out("knows").Values("name"), gremlingo.T__.Constant("peter")))}},
+ "g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_constantXpeterXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.P.Within(gremlingo.T__.V(p["vid1"]).Out("knows").Values("name").Fold(), gremlingo.T__.Constant("peter")))}},
"g_V_hasXname_withinXVXvid1X_valuesXnonexistentX_constantXmarkoXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.P.Within(gremlingo.T__.V(p["vid1"]).Values("nonexistent"), gremlingo.T__.Constant("marko")))}},
"g_V_hasXname_withinXVXvid1X_valuesXnonexistentX_VXvid1X_valuesXnonexistentXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.P.Within(gremlingo.T__.V(p["vid1"]).Values("nonexistent"), gremlingo.T__.V(p["vid1"]).Values("nonexistent")))}},
"g_V_hasXname_withoutXVXvid1X_valuesXnameX_VXvid2X_valuesXnameX_VXvid3X_valuesXnameXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.P.Without(gremlingo.T__.V(p["vid1"]).Values("name"), gremlingo.T__.V(p["vid2"]).Values("name"), gremlingo.T__.V(p["vid3"]).Values("name")))}},
- "g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.P.Within(gremlingo.T__.V(p["vid1"]).Out("knows").Values("name"), gremlingo.T__.V(p["vid3"]).Out("created").Values("name")))}},
- "g_V_hasLabelXsoftwareX_hasXname_withoutXVXvid1X_outXcreatedX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("software").Has("name", gremlingo.P.Without(gremlingo.T__.V(p["vid1"]).Out("created").Values("name"), gremlingo.T__.V(p["vid3"]).Out("created").Values("name")))}},
- "g_V_hasLabelXpersonX_valuesXageX_isXwithinXVXvid1X_valuesXageX_V_hasXname_lopX_inXcreatedX_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("person").Values("age").Is(gremlingo.P.Within(gremlingo.T__.V(p["vid1"]).Values("age"), gremlingo.T__.V().Has("name", "lop").In("created").Values("age")))}},
- "g_VXvid1X_outEXknowsX_filterXinV_hasXname_withinXV_hasXname_lopX_inXcreatedX_valuesXnameX_V_hasXname_rippleX_inXcreatedX_valuesXnameXXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).OutE("knows").Filter(gremlingo.T__.InV().Has("name", gremlingo.P.Within(gremlingo.T__.V().Has("name", "lop").In("created").Values("name"), gremlingo.T__.V().Has("name", "ripple").In("created").Values("name"))))}},
+ "g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.P.Within(gremlingo.T__.V(p["vid1"]).Out("knows").Values("name").Fold(), gremlingo.T__.V(p["vid3"]).Out("created").Values("name").Fold()))}},
+ "g_V_hasLabelXsoftwareX_hasXname_withoutXVXvid1X_outXcreatedX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("software").Has("name", gremlingo.P.Without(gremlingo.T__.V(p["vid1"]).Out("created").Values("name").Fold(), gremlingo.T__.V(p["vid3"]).Out("created").Values("name").Fold()))}},
+ "g_V_hasLabelXpersonX_valuesXageX_isXwithinXVXvid1X_valuesXageX_V_hasXname_lopX_inXcreatedX_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("person").Values("age").Is(gremlingo.P.Within(gremlingo.T__.V(p["vid1"]).Values("age").Fold(), gremlingo.T__.V().Has("name", "lop").In("created").Values("age").Fold()))}},
+ "g_VXvid1X_outEXknowsX_filterXinV_hasXname_withinXV_hasXname_lopX_inXcreatedX_valuesXnameX_V_hasXname_rippleX_inXcreatedX_valuesXnameXXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).OutE("knows").Filter(gremlingo.T__.InV().Has("name", gremlingo.P.Within(gremlingo.T__.V().Has("name", "lop").In("created").Values("name").Fold(), gremlingo.T__.V().Has("name", "ripple").In("created").Values("name").Fold())))}},
"g_V_properties_hasValueXnullX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Properties().HasValue(nil)}},
"g_V_properties_hasValueXnull_nullX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Properties().HasValue(nil, nil)}},
"g_V_properties_hasValueXnull_joshX_value": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Properties().HasValue(nil, "josh").Value()}},
@@ -557,7 +557,7 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[
"g_V_valuesXageX_isXgtXVXvid1X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Is(gremlingo.P.Gt(gremlingo.T__.V(p["vid1"]).Values("age")))}},
"g_V_valuesXageX_isXltXVXvid3X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Is(gremlingo.P.Lt(gremlingo.T__.V(p["vid3"]).Values("age")))}},
"g_V_valuesXageX_isXneqXVXvid4X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Is(gremlingo.P.Neq(gremlingo.T__.V(p["vid4"]).Values("age")))}},
- "g_V_valuesXageX_isXwithinXVXvid1X_outXknowsX_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Is(gremlingo.P.Within(gremlingo.T__.V(p["vid1"]).Out("knows").Values("age")))}},
+ "g_V_valuesXageX_isXwithinXVXvid1X_outXknowsX_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Is(gremlingo.P.Within(gremlingo.T__.V(p["vid1"]).Out("knows").Values("age").Fold()))}},
"g_V_valuesXageX_isXVXvid1X_valuesXnonexistentXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Is(gremlingo.T__.V(p["vid1"]).Values("nonexistent"))}},
"g_V_hasLabelXpersonX_valuesXageX_chooseXgtXVXvid1X_valuesXageXX_olderX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("person").Values("age").Choose(gremlingo.P.Gt(gremlingo.T__.V(p["vid1"]).Values("age")), gremlingo.T__.Constant("older than marko"), gremlingo.T__.Constant("not older"))}},
"g_V_hasLabelXpersonX_valuesXageX_chooseXgteXmeanAgeX_aboveX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("person").Values("age").Choose(gremlingo.P.Gte(gremlingo.T__.V().HasLabel("person").Values("age").Mean()), gremlingo.T__.Constant("above average"), gremlingo.T__.Constant("below average"))}},
@@ -747,7 +747,7 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[
"g_V_valuesXageX_whereXgtXVXvid1X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Where(gremlingo.P.Gt(gremlingo.T__.V(p["vid1"]).Values("age")))}},
"g_V_valuesXageX_whereXltXVXvid3X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Where(gremlingo.P.Lt(gremlingo.T__.V(p["vid3"]).Values("age")))}},
"g_V_valuesXageX_whereXeqXVXvid1X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Where(gremlingo.P.Eq(gremlingo.T__.V(p["vid1"]).Values("age")))}},
- "g_V_valuesXageX_whereXwithinXVXvid1X_outXknowsX_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Where(gremlingo.P.Within(gremlingo.T__.V(p["vid1"]).Out("knows").Values("age")))}},
+ "g_V_valuesXageX_whereXwithinXVXvid1X_outXknowsX_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Where(gremlingo.P.Within(gremlingo.T__.V(p["vid1"]).Out("knows").Values("age").Fold()))}},
"g_V_valuesXnameX_whereXneqXVXvid1X_valuesXnameXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("name").Where(gremlingo.P.Neq(gremlingo.T__.V(p["vid1"]).Values("name")))}},
"g_V_valuesXageX_whereXeqXV9999_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Where(gremlingo.P.Eq(gremlingo.T__.V(9999).Values("age")))}},
"g_V_whereXgtXVXvid1X_valuesXageXXX_byXageX_valuesXnameX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Where(gremlingo.P.Gt(gremlingo.T__.V(p["vid1"]).Values("age"))).By("age").Values("name")}},
diff --git a/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js b/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js
index cec6e2d7fc..ea9b014ee2 100644
--- a/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js
+++ b/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js
@@ -564,14 +564,14 @@ const gremlins = {
g_V_hasXage_eqXVXvid1X_valuesXnonexistentXXX: [function({g, vid1}) { return g.V().has("age", P.eq(__.V(vid1).values("nonexistent"))) }],
g_V_hasXlabel_VXvid1X_labelXX: [function({g, vid1}) { return g.V().has(T.label, __.V(vid1).label()) }],
g_V_hasXperson_name_VXvid1X_valuesXnameXX_age: [function({g, vid1}) { return g.V().has("person", "name", __.V(vid1).values("name")).values("age") }],
- g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_constantXpeterXXX: [function({g, vid1}) { return g.V().has("name", P.within(__.V(vid1).out("knows").values("name"), __.constant("peter"))) }],
+ g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_constantXpeterXXX: [function({g, vid1}) { return g.V().has("name", P.within(__.V(vid1).out("knows").values("name").fold(), __.constant("peter"))) }],
g_V_hasXname_withinXVXvid1X_valuesXnonexistentX_constantXmarkoXXX: [function({g, vid1}) { return g.V().has("name", P.within(__.V(vid1).values("nonexistent"), __.constant("marko"))) }],
g_V_hasXname_withinXVXvid1X_valuesXnonexistentX_VXvid1X_valuesXnonexistentXXX: [function({g, vid1}) { return g.V().has("name", P.within(__.V(vid1).values("nonexistent"), __.V(vid1).values("nonexistent"))) }],
g_V_hasXname_withoutXVXvid1X_valuesXnameX_VXvid2X_valuesXnameX_VXvid3X_valuesXnameXXX: [function({g, vid3, vid2, vid1}) { return g.V().has("name", P.without(__.V(vid1).values("name"), __.V(vid2).values("name"), __.V(vid3).values("name"))) }],
- g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX: [function({g, vid3, vid1}) { return g.V().has("name", P.within(__.V(vid1).out("knows").values("name"), __.V(vid3).out("created").values("name"))) }],
- g_V_hasLabelXsoftwareX_hasXname_withoutXVXvid1X_outXcreatedX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX: [function({g, vid3, vid1}) { return g.V().hasLabel("software").has("name", P.without(__.V(vid1).out("created").values("name"), __.V(vid3).out("created").values("name"))) }],
- g_V_hasLabelXpersonX_valuesXageX_isXwithinXVXvid1X_valuesXageX_V_hasXname_lopX_inXcreatedX_valuesXageXXX: [function({g, vid1}) { return g.V().hasLabel("person").values("age").is(P.within(__.V(vid1).values("age"), __.V().has("name", "lop").in_("created").values("age"))) }],
- g_VXvid1X_outEXknowsX_filterXinV_hasXname_withinXV_hasXname_lopX_inXcreatedX_valuesXnameX_V_hasXname_rippleX_inXcreatedX_valuesXnameXXXX: [function({g, vid1}) { return g.V(vid1).outE("knows").filter(__.inV().has("name", P.within(__.V().has("name", "lop").in_("created").values("name"), __.V().has("name", "ripple").in_("created").values("name")))) }],
+ g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX: [function({g, vid3, vid1}) { return g.V().has("name", P.within(__.V(vid1).out("knows").values("name").fold(), __.V(vid3).out("created").values("name").fold())) }],
+ g_V_hasLabelXsoftwareX_hasXname_withoutXVXvid1X_outXcreatedX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX: [function({g, vid3, vid1}) { return g.V().hasLabel("software").has("name", P.without(__.V(vid1).out("created").values("name").fold(), __.V(vid3).out("created").values("name").fold())) }],
+ g_V_hasLabelXpersonX_valuesXageX_isXwithinXVXvid1X_valuesXageX_V_hasXname_lopX_inXcreatedX_valuesXageXXX: [function({g, vid1}) { return g.V().hasLabel("person").values("age").is(P.within(__.V(vid1).values("age").fold(), __.V().has("name", "lop").in_("created").values("age").fold())) }],
+ g_VXvid1X_outEXknowsX_filterXinV_hasXname_withinXV_hasXname_lopX_inXcreatedX_valuesXnameX_V_hasXname_rippleX_inXcreatedX_valuesXnameXXXX: [function({g, vid1}) { return g.V(vid1).outE("knows").filter(__.inV().has("name", P.within(__.V().has("name", "lop").in_("created").values("name").fold(), __.V().has("name", "ripple").in_("created").values("name").fold()))) }],
g_V_properties_hasValueXnullX: [function({g}) { return g.V().properties().hasValue(null) }],
g_V_properties_hasValueXnull_nullX: [function({g}) { return g.V().properties().hasValue(null, null) }],
g_V_properties_hasValueXnull_joshX_value: [function({g}) { return g.V().properties().hasValue(null, "josh").value() }],
@@ -588,7 +588,7 @@ const gremlins = {
g_V_valuesXageX_isXgtXVXvid1X_valuesXageXXX: [function({g, vid1}) { return g.V().values("age").is(P.gt(__.V(vid1).values("age"))) }],
g_V_valuesXageX_isXltXVXvid3X_valuesXageXXX: [function({g, vid3}) { return g.V().values("age").is(P.lt(__.V(vid3).values("age"))) }],
g_V_valuesXageX_isXneqXVXvid4X_valuesXageXXX: [function({g, vid4}) { return g.V().values("age").is(P.neq(__.V(vid4).values("age"))) }],
- g_V_valuesXageX_isXwithinXVXvid1X_outXknowsX_valuesXageXXX: [function({g, vid1}) { return g.V().values("age").is(P.within(__.V(vid1).out("knows").values("age"))) }],
+ g_V_valuesXageX_isXwithinXVXvid1X_outXknowsX_valuesXageXXX: [function({g, vid1}) { return g.V().values("age").is(P.within(__.V(vid1).out("knows").values("age").fold())) }],
g_V_valuesXageX_isXVXvid1X_valuesXnonexistentXX: [function({g, vid1}) { return g.V().values("age").is(__.V(vid1).values("nonexistent")) }],
g_V_hasLabelXpersonX_valuesXageX_chooseXgtXVXvid1X_valuesXageXX_olderX: [function({g, vid1}) { return g.V().hasLabel("person").values("age").choose(P.gt(__.V(vid1).values("age")), __.constant("older than marko"), __.constant("not older")) }],
g_V_hasLabelXpersonX_valuesXageX_chooseXgteXmeanAgeX_aboveX: [function({g}) { return g.V().hasLabel("person").values("age").choose(P.gte(__.V().hasLabel("person").values("age").mean()), __.constant("above average"), __.constant("below average")) }],
@@ -778,7 +778,7 @@ const gremlins = {
g_V_valuesXageX_whereXgtXVXvid1X_valuesXageXXX: [function({g, vid1}) { return g.V().values("age").where(P.gt(__.V(vid1).values("age"))) }],
g_V_valuesXageX_whereXltXVXvid3X_valuesXageXXX: [function({g, vid3}) { return g.V().values("age").where(P.lt(__.V(vid3).values("age"))) }],
g_V_valuesXageX_whereXeqXVXvid1X_valuesXageXXX: [function({g, vid1}) { return g.V().values("age").where(P.eq(__.V(vid1).values("age"))) }],
- g_V_valuesXageX_whereXwithinXVXvid1X_outXknowsX_valuesXageXXX: [function({g, vid1}) { return g.V().values("age").where(P.within(__.V(vid1).out("knows").values("age"))) }],
+ g_V_valuesXageX_whereXwithinXVXvid1X_outXknowsX_valuesXageXXX: [function({g, vid1}) { return g.V().values("age").where(P.within(__.V(vid1).out("knows").values("age").fold())) }],
g_V_valuesXnameX_whereXneqXVXvid1X_valuesXnameXXX: [function({g, vid1}) { return g.V().values("name").where(P.neq(__.V(vid1).values("name"))) }],
g_V_valuesXageX_whereXeqXV9999_valuesXageXXX: [function({g}) { return g.V().values("age").where(P.eq(__.V(9999).values("age"))) }],
g_V_whereXgtXVXvid1X_valuesXageXXX_byXageX_valuesXnameX: [function({g, vid1}) { return g.V().where(P.gt(__.V(vid1).values("age"))).by("age").values("name") }],
diff --git a/gremlin-python/src/main/python/tests/feature/gremlin.py b/gremlin-python/src/main/python/tests/feature/gremlin.py
index a3262c119c..eb3fcb11df 100644
--- a/gremlin-python/src/main/python/tests/feature/gremlin.py
+++ b/gremlin-python/src/main/python/tests/feature/gremlin.py
@@ -538,14 +538,14 @@ world.gremlins = {
'g_V_hasXage_eqXVXvid1X_valuesXnonexistentXXX': [(lambda g, vid1=None:g.V().has('age', P.eq(__.V(vid1).values('nonexistent'))))],
'g_V_hasXlabel_VXvid1X_labelXX': [(lambda g, vid1=None:g.V().has(T.label, __.V(vid1).label()))],
'g_V_hasXperson_name_VXvid1X_valuesXnameXX_age': [(lambda g, vid1=None:g.V().has('person', 'name', __.V(vid1).values('name')).values('age'))],
- 'g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_constantXpeterXXX': [(lambda g, vid1=None:g.V().has('name', P.within(__.V(vid1).out('knows').values('name'), __.constant('peter'))))],
+ 'g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_constantXpeterXXX': [(lambda g, vid1=None:g.V().has('name', P.within(__.V(vid1).out('knows').values('name').fold(), __.constant('peter'))))],
'g_V_hasXname_withinXVXvid1X_valuesXnonexistentX_constantXmarkoXXX': [(lambda g, vid1=None:g.V().has('name', P.within(__.V(vid1).values('nonexistent'), __.constant('marko'))))],
'g_V_hasXname_withinXVXvid1X_valuesXnonexistentX_VXvid1X_valuesXnonexistentXXX': [(lambda g, vid1=None:g.V().has('name', P.within(__.V(vid1).values('nonexistent'), __.V(vid1).values('nonexistent'))))],
'g_V_hasXname_withoutXVXvid1X_valuesXnameX_VXvid2X_valuesXnameX_VXvid3X_valuesXnameXXX': [(lambda g, vid3=None,vid2=None,vid1=None:g.V().has('name', P.without(__.V(vid1).values('name'), __.V(vid2).values('name'), __.V(vid3).values('name'))))],
- 'g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX': [(lambda g, vid3=None,vid1=None:g.V().has('name', P.within(__.V(vid1).out('knows').values('name'), __.V(vid3).out('created').values('name'))))],
- 'g_V_hasLabelXsoftwareX_hasXname_withoutXVXvid1X_outXcreatedX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX': [(lambda g, vid3=None,vid1=None:g.V().has_label('software').has('name', P.without(__.V(vid1).out('created').values('name'), __.V(vid3).out('created').values('name'))))],
- 'g_V_hasLabelXpersonX_valuesXageX_isXwithinXVXvid1X_valuesXageX_V_hasXname_lopX_inXcreatedX_valuesXageXXX': [(lambda g, vid1=None:g.V().has_label('person').values('age').is_(P.within(__.V(vid1).values('age'), __.V().has('name', 'lop').in_('created').values('age'))))],
- 'g_VXvid1X_outEXknowsX_filterXinV_hasXname_withinXV_hasXname_lopX_inXcreatedX_valuesXnameX_V_hasXname_rippleX_inXcreatedX_valuesXnameXXXX': [(lambda g, vid1=None:g.V(vid1).out_e('knows').filter_(__.in_v().has('name', P.within(__.V().has('name', 'lop').in_('created').values('name'), __.V().has('name', 'ripple').in_('created').values('name')))))],
+ 'g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX': [(lambda g, vid3=None,vid1=None:g.V().has('name', P.within(__.V(vid1).out('knows').values('name').fold(), __.V(vid3).out('created').values('name').fold())))],
+ 'g_V_hasLabelXsoftwareX_hasXname_withoutXVXvid1X_outXcreatedX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX': [(lambda g, vid3=None,vid1=None:g.V().has_label('software').has('name', P.without(__.V(vid1).out('created').values('name').fold(), __.V(vid3).out('created').values('name').fold())))],
+ 'g_V_hasLabelXpersonX_valuesXageX_isXwithinXVXvid1X_valuesXageX_V_hasXname_lopX_inXcreatedX_valuesXageXXX': [(lambda g, vid1=None:g.V().has_label('person').values('age').is_(P.within(__.V(vid1).values('age').fold(), __.V().has('name', 'lop').in_('created').values('age').fold())))],
+ 'g_VXvid1X_outEXknowsX_filterXinV_hasXname_withinXV_hasXname_lopX_inXcreatedX_valuesXnameX_V_hasXname_rippleX_inXcreatedX_valuesXnameXXXX': [(lambda g, vid1=None:g.V(vid1).out_e('knows').filter_(__.in_v().has('name', P.within(__.V().has('name', 'lop').in_('created').values('name').fold(), __.V().has('name', 'ripple').in_('created').values('name').fold()))))],
'g_V_properties_hasValueXnullX': [(lambda g:g.V().properties().has_value(None))],
'g_V_properties_hasValueXnull_nullX': [(lambda g:g.V().properties().has_value(None, None))],
'g_V_properties_hasValueXnull_joshX_value': [(lambda g:g.V().properties().has_value(None, 'josh').value())],
@@ -562,7 +562,7 @@ world.gremlins = {
'g_V_valuesXageX_isXgtXVXvid1X_valuesXageXXX': [(lambda g, vid1=None:g.V().values('age').is_(P.gt(__.V(vid1).values('age'))))],
'g_V_valuesXageX_isXltXVXvid3X_valuesXageXXX': [(lambda g, vid3=None:g.V().values('age').is_(P.lt(__.V(vid3).values('age'))))],
'g_V_valuesXageX_isXneqXVXvid4X_valuesXageXXX': [(lambda g, vid4=None:g.V().values('age').is_(P.neq(__.V(vid4).values('age'))))],
- 'g_V_valuesXageX_isXwithinXVXvid1X_outXknowsX_valuesXageXXX': [(lambda g, vid1=None:g.V().values('age').is_(P.within(__.V(vid1).out('knows').values('age'))))],
+ 'g_V_valuesXageX_isXwithinXVXvid1X_outXknowsX_valuesXageXXX': [(lambda g, vid1=None:g.V().values('age').is_(P.within(__.V(vid1).out('knows').values('age').fold())))],
'g_V_valuesXageX_isXVXvid1X_valuesXnonexistentXX': [(lambda g, vid1=None:g.V().values('age').is_(__.V(vid1).values('nonexistent')))],
'g_V_hasLabelXpersonX_valuesXageX_chooseXgtXVXvid1X_valuesXageXX_olderX': [(lambda g, vid1=None:g.V().has_label('person').values('age').choose(P.gt(__.V(vid1).values('age')), __.constant('older than marko'), __.constant('not older')))],
'g_V_hasLabelXpersonX_valuesXageX_chooseXgteXmeanAgeX_aboveX': [(lambda g:g.V().has_label('person').values('age').choose(P.gte(__.V().has_label('person').values('age').mean()), __.constant('above average'), __.constant('below average')))],
@@ -752,7 +752,7 @@ world.gremlins = {
'g_V_valuesXageX_whereXgtXVXvid1X_valuesXageXXX': [(lambda g, vid1=None:g.V().values('age').where(P.gt(__.V(vid1).values('age'))))],
'g_V_valuesXageX_whereXltXVXvid3X_valuesXageXXX': [(lambda g, vid3=None:g.V().values('age').where(P.lt(__.V(vid3).values('age'))))],
'g_V_valuesXageX_whereXeqXVXvid1X_valuesXageXXX': [(lambda g, vid1=None:g.V().values('age').where(P.eq(__.V(vid1).values('age'))))],
- 'g_V_valuesXageX_whereXwithinXVXvid1X_outXknowsX_valuesXageXXX': [(lambda g, vid1=None:g.V().values('age').where(P.within(__.V(vid1).out('knows').values('age'))))],
+ 'g_V_valuesXageX_whereXwithinXVXvid1X_outXknowsX_valuesXageXXX': [(lambda g, vid1=None:g.V().values('age').where(P.within(__.V(vid1).out('knows').values('age').fold())))],
'g_V_valuesXnameX_whereXneqXVXvid1X_valuesXnameXXX': [(lambda g, vid1=None:g.V().values('name').where(P.neq(__.V(vid1).values('name'))))],
'g_V_valuesXageX_whereXeqXV9999_valuesXageXXX': [(lambda g:g.V().values('age').where(P.eq(__.V(9999).values('age'))))],
'g_V_whereXgtXVXvid1X_valuesXageXXX_byXageX_valuesXnameX': [(lambda g, vid1=None:g.V().where(P.gt(__.V(vid1).values('age'))).by('age').values('name'))],
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json
index 1340ec569c..f59fb17768 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json
@@ -9793,16 +9793,16 @@
"scenario": "g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_constantXpeterXXX",
"traversals": [
{
- "original": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\"), __.constant(\"peter\")))",
- "language": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\"), __.constant(\"peter\")))",
- "canonical": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\"), __.constant(\"peter\")))",
- "anonymized": "g.V().has(string0, P.within(__.V(vid1).out(string1).values(string0), __.constant(string2)))",
- "dotnet": "g.V().Has(\"name\", P.Within(__.V(vid1).Out(\"knows\").Values<object>(\"name\"), __.Constant<object>(\"peter\")))",
- "go": "g.V().Has(\"name\", gremlingo.P.Within(gremlingo.T__.V(vid1).Out(\"knows\").Values(\"name\"), gremlingo.T__.Constant(\"peter\")))",
- "groovy": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\"), __.constant(\"peter\")))",
- "java": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\"), __.constant(\"peter\")))",
- "javascript": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\"), __.constant(\"peter\")))",
- "python": "g.V().has('name', P.within(__.V(vid1).out('knows').values('name'), __.constant('peter')))"
+ "original": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\").fold(), __.constant(\"peter\")))",
+ "language": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\").fold(), __.constant(\"peter\")))",
+ "canonical": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\").fold(), __.constant(\"peter\")))",
+ "anonymized": "g.V().has(string0, P.within(__.V(vid1).out(string1).values(string0).fold(), __.constant(string2)))",
+ "dotnet": "g.V().Has(\"name\", P.Within(__.V(vid1).Out(\"knows\").Values<object>(\"name\").Fold(), __.Constant<object>(\"peter\")))",
+ "go": "g.V().Has(\"name\", gremlingo.P.Within(gremlingo.T__.V(vid1).Out(\"knows\").Values(\"name\").Fold(), gremlingo.T__.Constant(\"peter\")))",
+ "groovy": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\").fold(), __.constant(\"peter\")))",
+ "java": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\").fold(), __.constant(\"peter\")))",
+ "javascript": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\").fold(), __.constant(\"peter\")))",
+ "python": "g.V().has('name', P.within(__.V(vid1).out('knows').values('name').fold(), __.constant('peter')))"
}
]
},
@@ -9861,16 +9861,16 @@
"scenario": "g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX",
"traversals": [
{
- "original": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\"), __.V(vid3).out(\"created\").values(\"name\")))",
- "language": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\"), __.V(vid3).out(\"created\").values(\"name\")))",
- "canonical": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\"), __.V(vid3).out(\"created\").values(\"name\")))",
- "anonymized": "g.V().has(string0, P.within(__.V(vid1).out(string1).values(string0), __.V(vid3).out(string2).values(string0)))",
- "dotnet": "g.V().Has(\"name\", P.Within(__.V(vid1).Out(\"knows\").Values<object>(\"name\"), __.V(vid3).Out(\"created\").Values<object>(\"name\")))",
- "go": "g.V().Has(\"name\", gremlingo.P.Within(gremlingo.T__.V(vid1).Out(\"knows\").Values(\"name\"), gremlingo.T__.V(vid3).Out(\"created\").Values(\"name\")))",
- "groovy": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\"), __.V(vid3).out(\"created\").values(\"name\")))",
- "java": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\"), __.V(vid3).out(\"created\").values(\"name\")))",
- "javascript": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\"), __.V(vid3).out(\"created\").values(\"name\")))",
- "python": "g.V().has('name', P.within(__.V(vid1).out('knows').values('name'), __.V(vid3).out('created').values('name')))"
+ "original": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\").fold(), __.V(vid3).out(\"created\").values(\"name\").fold()))",
+ "language": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\").fold(), __.V(vid3).out(\"created\").values(\"name\").fold()))",
+ "canonical": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\").fold(), __.V(vid3).out(\"created\").values(\"name\").fold()))",
+ "anonymized": "g.V().has(string0, P.within(__.V(vid1).out(string1).values(string0).fold(), __.V(vid3).out(string2).values(string0).fold()))",
+ "dotnet": "g.V().Has(\"name\", P.Within(__.V(vid1).Out(\"knows\").Values<object>(\"name\").Fold(), __.V(vid3).Out(\"created\").Values<object>(\"name\").Fold()))",
+ "go": "g.V().Has(\"name\", gremlingo.P.Within(gremlingo.T__.V(vid1).Out(\"knows\").Values(\"name\").Fold(), gremlingo.T__.V(vid3).Out(\"created\").Values(\"name\").Fold()))",
+ "groovy": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\").fold(), __.V(vid3).out(\"created\").values(\"name\").fold()))",
+ "java": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\").fold(), __.V(vid3).out(\"created\").values(\"name\").fold()))",
+ "javascript": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\").fold(), __.V(vid3).out(\"created\").values(\"name\").fold()))",
+ "python": "g.V().has('name', P.within(__.V(vid1).out('knows').values('name').fold(), __.V(vid3).out('created').values('name').fold()))"
}
]
},
@@ -9878,16 +9878,16 @@
"scenario": "g_V_hasLabelXsoftwareX_hasXname_withoutXVXvid1X_outXcreatedX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX",
"traversals": [
{
- "original": "g.V().hasLabel(\"software\").has(\"name\", P.without(__.V(vid1).out(\"created\").values(\"name\"), __.V(vid3).out(\"created\").values(\"name\")))",
- "language": "g.V().hasLabel(\"software\").has(\"name\", P.without(__.V(vid1).out(\"created\").values(\"name\"), __.V(vid3).out(\"created\").values(\"name\")))",
- "canonical": "g.V().hasLabel(\"software\").has(\"name\", P.without(__.V(vid1).out(\"created\").values(\"name\"), __.V(vid3).out(\"created\").values(\"name\")))",
- "anonymized": "g.V().hasLabel(string0).has(string1, P.without(__.V(vid1).out(string2).values(string1), __.V(vid3).out(string2).values(string1)))",
- "dotnet": "g.V().HasLabel(\"software\").Has(\"name\", P.Without(__.V(vid1).Out(\"created\").Values<object>(\"name\"), __.V(vid3).Out(\"created\").Values<object>(\"name\")))",
- "go": "g.V().HasLabel(\"software\").Has(\"name\", gremlingo.P.Without(gremlingo.T__.V(vid1).Out(\"created\").Values(\"name\"), gremlingo.T__.V(vid3).Out(\"created\").Values(\"name\")))",
- "groovy": "g.V().hasLabel(\"software\").has(\"name\", P.without(__.V(vid1).out(\"created\").values(\"name\"), __.V(vid3).out(\"created\").values(\"name\")))",
- "java": "g.V().hasLabel(\"software\").has(\"name\", P.without(__.V(vid1).out(\"created\").values(\"name\"), __.V(vid3).out(\"created\").values(\"name\")))",
- "javascript": "g.V().hasLabel(\"software\").has(\"name\", P.without(__.V(vid1).out(\"created\").values(\"name\"), __.V(vid3).out(\"created\").values(\"name\")))",
- "python": "g.V().has_label('software').has('name', P.without(__.V(vid1).out('created').values('name'), __.V(vid3).out('created').values('name')))"
+ "original": "g.V().hasLabel(\"software\").has(\"name\", P.without(__.V(vid1).out(\"created\").values(\"name\").fold(), __.V(vid3).out(\"created\").values(\"name\").fold()))",
+ "language": "g.V().hasLabel(\"software\").has(\"name\", P.without(__.V(vid1).out(\"created\").values(\"name\").fold(), __.V(vid3).out(\"created\").values(\"name\").fold()))",
+ "canonical": "g.V().hasLabel(\"software\").has(\"name\", P.without(__.V(vid1).out(\"created\").values(\"name\").fold(), __.V(vid3).out(\"created\").values(\"name\").fold()))",
+ "anonymized": "g.V().hasLabel(string0).has(string1, P.without(__.V(vid1).out(string2).values(string1).fold(), __.V(vid3).out(string2).values(string1).fold()))",
+ "dotnet": "g.V().HasLabel(\"software\").Has(\"name\", P.Without(__.V(vid1).Out(\"created\").Values<object>(\"name\").Fold(), __.V(vid3).Out(\"created\").Values<object>(\"name\").Fold()))",
+ "go": "g.V().HasLabel(\"software\").Has(\"name\", gremlingo.P.Without(gremlingo.T__.V(vid1).Out(\"created\").Values(\"name\").Fold(), gremlingo.T__.V(vid3).Out(\"created\").Values(\"name\").Fold()))",
+ "groovy": "g.V().hasLabel(\"software\").has(\"name\", P.without(__.V(vid1).out(\"created\").values(\"name\").fold(), __.V(vid3).out(\"created\").values(\"name\").fold()))",
+ "java": "g.V().hasLabel(\"software\").has(\"name\", P.without(__.V(vid1).out(\"created\").values(\"name\").fold(), __.V(vid3).out(\"created\").values(\"name\").fold()))",
+ "javascript": "g.V().hasLabel(\"software\").has(\"name\", P.without(__.V(vid1).out(\"created\").values(\"name\").fold(), __.V(vid3).out(\"created\").values(\"name\").fold()))",
+ "python": "g.V().has_label('software').has('name', P.without(__.V(vid1).out('created').values('name').fold(), __.V(vid3).out('created').values('name').fold()))"
}
]
},
@@ -9895,16 +9895,16 @@
"scenario": "g_V_hasLabelXpersonX_valuesXageX_isXwithinXVXvid1X_valuesXageX_V_hasXname_lopX_inXcreatedX_valuesXageXXX",
"traversals": [
{
- "original": "g.V().hasLabel(\"person\").values(\"age\").is(P.within(__.V(vid1).values(\"age\"), __.V().has(\"name\",\"lop\").in(\"created\").values(\"age\")))",
- "language": "g.V().hasLabel(\"person\").values(\"age\").is(P.within(__.V(vid1).values(\"age\"), __.V().has(\"name\", \"lop\").in(\"created\").values(\"age\")))",
- "canonical": "g.V().hasLabel(\"person\").values(\"age\").is(P.within(__.V(vid1).values(\"age\"), __.V().has(\"name\", \"lop\").in(\"created\").values(\"age\")))",
- "anonymized": "g.V().hasLabel(string0).values(string1).is(P.within(__.V(vid1).values(string1), __.V().has(string2, string3).in(string4).values(string1)))",
- "dotnet": "g.V().HasLabel(\"person\").Values<object>(\"age\").Is(P.Within(__.V(vid1).Values<object>(\"age\"), __.V().Has(\"name\", \"lop\").In(\"created\").Values<object>(\"age\")))",
- "go": "g.V().HasLabel(\"person\").Values(\"age\").Is(gremlingo.P.Within(gremlingo.T__.V(vid1).Values(\"age\"), gremlingo.T__.V().Has(\"name\", \"lop\").In(\"created\").Values(\"age\")))",
- "groovy": "g.V().hasLabel(\"person\").values(\"age\").is(P.within(__.V(vid1).values(\"age\"), __.V().has(\"name\", \"lop\").in(\"created\").values(\"age\")))",
- "java": "g.V().hasLabel(\"person\").values(\"age\").is(P.within(__.V(vid1).values(\"age\"), __.V().has(\"name\", \"lop\").in(\"created\").values(\"age\")))",
- "javascript": "g.V().hasLabel(\"person\").values(\"age\").is(P.within(__.V(vid1).values(\"age\"), __.V().has(\"name\", \"lop\").in_(\"created\").values(\"age\")))",
- "python": "g.V().has_label('person').values('age').is_(P.within(__.V(vid1).values('age'), __.V().has('name', 'lop').in_('created').values('age')))"
+ "original": "g.V().hasLabel(\"person\").values(\"age\").is(P.within(__.V(vid1).values(\"age\").fold(), __.V().has(\"name\",\"lop\").in(\"created\").values(\"age\").fold()))",
+ "language": "g.V().hasLabel(\"person\").values(\"age\").is(P.within(__.V(vid1).values(\"age\").fold(), __.V().has(\"name\", \"lop\").in(\"created\").values(\"age\").fold()))",
+ "canonical": "g.V().hasLabel(\"person\").values(\"age\").is(P.within(__.V(vid1).values(\"age\").fold(), __.V().has(\"name\", \"lop\").in(\"created\").values(\"age\").fold()))",
+ "anonymized": "g.V().hasLabel(string0).values(string1).is(P.within(__.V(vid1).values(string1).fold(), __.V().has(string2, string3).in(string4).values(string1).fold()))",
+ "dotnet": "g.V().HasLabel(\"person\").Values<object>(\"age\").Is(P.Within(__.V(vid1).Values<object>(\"age\").Fold(), __.V().Has(\"name\", \"lop\").In(\"created\").Values<object>(\"age\").Fold()))",
+ "go": "g.V().HasLabel(\"person\").Values(\"age\").Is(gremlingo.P.Within(gremlingo.T__.V(vid1).Values(\"age\").Fold(), gremlingo.T__.V().Has(\"name\", \"lop\").In(\"created\").Values(\"age\").Fold()))",
+ "groovy": "g.V().hasLabel(\"person\").values(\"age\").is(P.within(__.V(vid1).values(\"age\").fold(), __.V().has(\"name\", \"lop\").in(\"created\").values(\"age\").fold()))",
+ "java": "g.V().hasLabel(\"person\").values(\"age\").is(P.within(__.V(vid1).values(\"age\").fold(), __.V().has(\"name\", \"lop\").in(\"created\").values(\"age\").fold()))",
+ "javascript": "g.V().hasLabel(\"person\").values(\"age\").is(P.within(__.V(vid1).values(\"age\").fold(), __.V().has(\"name\", \"lop\").in_(\"created\").values(\"age\").fold()))",
+ "python": "g.V().has_label('person').values('age').is_(P.within(__.V(vid1).values('age').fold(), __.V().has('name', 'lop').in_('created').values('age').fold()))"
}
]
},
@@ -9912,16 +9912,16 @@
"scenario": "g_VXvid1X_outEXknowsX_filterXinV_hasXname_withinXV_hasXname_lopX_inXcreatedX_valuesXnameX_V_hasXname_rippleX_inXcreatedX_valuesXnameXXXX",
"traversals": [
{
- "original": "g.V(vid1).outE(\"knows\").filter(__.inV().has(\"name\", P.within(__.V().has(\"name\",\"lop\").in(\"created\").values(\"name\"), __.V().has(\"name\",\"ripple\").in(\"created\").values(\"name\"))))",
- "language": "g.V(vid1).outE(\"knows\").filter(__.inV().has(\"name\", P.within(__.V().has(\"name\", \"lop\").in(\"created\").values(\"name\"), __.V().has(\"name\", \"ripple\").in(\"created\").values(\"name\"))))",
- "canonical": "g.V(vid1).outE(\"knows\").filter(__.inV().has(\"name\", P.within(__.V().has(\"name\", \"lop\").in(\"created\").values(\"name\"), __.V().has(\"name\", \"ripple\").in(\"created\").values(\"name\"))))",
- "anonymized": "g.V(vid1).outE(string0).filter(__.inV().has(string1, P.within(__.V().has(string1, string2).in(string3).values(string1), __.V().has(string1, string4).in(string3).values(string1))))",
- "dotnet": "g.V(vid1).OutE(\"knows\").Filter(__.InV().Has(\"name\", P.Within(__.V().Has(\"name\", \"lop\").In(\"created\").Values<object>(\"name\"), __.V().Has(\"name\", \"ripple\").In(\"created\").Values<object>(\"name\"))))",
- "go": "g.V(vid1).OutE(\"knows\").Filter(gremlingo.T__.InV().Has(\"name\", gremlingo.P.Within(gremlingo.T__.V().Has(\"name\", \"lop\").In(\"created\").Values(\"name\"), gremlingo.T__.V().Has(\"name\", \"ripple\").In(\"created\").Values(\"name\"))))",
- "groovy": "g.V(vid1).outE(\"knows\").filter(__.inV().has(\"name\", P.within(__.V().has(\"name\", \"lop\").in(\"created\").values(\"name\"), __.V().has(\"name\", \"ripple\").in(\"created\").values(\"name\"))))",
- "java": "g.V(vid1).outE(\"knows\").filter(__.inV().has(\"name\", P.within(__.V().has(\"name\", \"lop\").in(\"created\").values(\"name\"), __.V().has(\"name\", \"ripple\").in(\"created\").values(\"name\"))))",
- "javascript": "g.V(vid1).outE(\"knows\").filter(__.inV().has(\"name\", P.within(__.V().has(\"name\", \"lop\").in_(\"created\").values(\"name\"), __.V().has(\"name\", \"ripple\").in_(\"created\").values(\"name\"))))",
- "python": "g.V(vid1).out_e('knows').filter_(__.in_v().has('name', P.within(__.V().has('name', 'lop').in_('created').values('name'), __.V().has('name', 'ripple').in_('created').values('name'))))"
+ "original": "g.V(vid1).outE(\"knows\").filter(__.inV().has(\"name\", P.within(__.V().has(\"name\",\"lop\").in(\"created\").values(\"name\").fold(), __.V().has(\"name\",\"ripple\").in(\"created\").values(\"name\").fold())))",
+ "language": "g.V(vid1).outE(\"knows\").filter(__.inV().has(\"name\", P.within(__.V().has(\"name\", \"lop\").in(\"created\").values(\"name\").fold(), __.V().has(\"name\", \"ripple\").in(\"created\").values(\"name\").fold())))",
+ "canonical": "g.V(vid1).outE(\"knows\").filter(__.inV().has(\"name\", P.within(__.V().has(\"name\", \"lop\").in(\"created\").values(\"name\").fold(), __.V().has(\"name\", \"ripple\").in(\"created\").values(\"name\").fold())))",
+ "anonymized": "g.V(vid1).outE(string0).filter(__.inV().has(string1, P.within(__.V().has(string1, string2).in(string3).values(string1).fold(), __.V().has(string1, string4).in(string3).values(string1).fold())))",
+ "dotnet": "g.V(vid1).OutE(\"knows\").Filter(__.InV().Has(\"name\", P.Within(__.V().Has(\"name\", \"lop\").In(\"created\").Values<object>(\"name\").Fold(), __.V().Has(\"name\", \"ripple\").In(\"created\").Values<object>(\"name\").Fold())))",
+ "go": "g.V(vid1).OutE(\"knows\").Filter(gremlingo.T__.InV().Has(\"name\", gremlingo.P.Within(gremlingo.T__.V().Has(\"name\", \"lop\").In(\"created\").Values(\"name\").Fold(), gremlingo.T__.V().Has(\"name\", \"ripple\").In(\"created\").Values(\"name\").Fold())))",
+ "groovy": "g.V(vid1).outE(\"knows\").filter(__.inV().has(\"name\", P.within(__.V().has(\"name\", \"lop\").in(\"created\").values(\"name\").fold(), __.V().has(\"name\", \"ripple\").in(\"created\").values(\"name\").fold())))",
+ "java": "g.V(vid1).outE(\"knows\").filter(__.inV().has(\"name\", P.within(__.V().has(\"name\", \"lop\").in(\"created\").values(\"name\").fold(), __.V().has(\"name\", \"ripple\").in(\"created\").values(\"name\").fold())))",
+ "javascript": "g.V(vid1).outE(\"knows\").filter(__.inV().has(\"name\", P.within(__.V().has(\"name\", \"lop\").in_(\"created\").values(\"name\").fold(), __.V().has(\"name\", \"ripple\").in_(\"created\").values(\"name\").fold())))",
+ "python": "g.V(vid1).out_e('knows').filter_(__.in_v().has('name', P.within(__.V().has('name', 'lop').in_('created').values('name').fold(), __.V().has('name', 'ripple').in_('created').values('name').fold())))"
}
]
},
@@ -10201,16 +10201,16 @@
"scenario": "g_V_valuesXageX_isXwithinXVXvid1X_outXknowsX_valuesXageXXX",
"traversals": [
{
- "original": "g.V().values(\"age\").is(P.within(__.V(vid1).out(\"knows\").values(\"age\")))",
- "language": "g.V().values(\"age\").is(P.within(__.V(vid1).out(\"knows\").values(\"age\")))",
- "canonical": "g.V().values(\"age\").is(P.within(__.V(vid1).out(\"knows\").values(\"age\")))",
- "anonymized": "g.V().values(string0).is(P.within(__.V(vid1).out(string1).values(string0)))",
- "dotnet": "g.V().Values<object>(\"age\").Is(P.Within(__.V(vid1).Out(\"knows\").Values<object>(\"age\")))",
- "go": "g.V().Values(\"age\").Is(gremlingo.P.Within(gremlingo.T__.V(vid1).Out(\"knows\").Values(\"age\")))",
- "groovy": "g.V().values(\"age\").is(P.within(__.V(vid1).out(\"knows\").values(\"age\")))",
- "java": "g.V().values(\"age\").is(P.within(__.V(vid1).out(\"knows\").values(\"age\")))",
- "javascript": "g.V().values(\"age\").is(P.within(__.V(vid1).out(\"knows\").values(\"age\")))",
- "python": "g.V().values('age').is_(P.within(__.V(vid1).out('knows').values('age')))"
+ "original": "g.V().values(\"age\").is(P.within(__.V(vid1).out(\"knows\").values(\"age\").fold()))",
+ "language": "g.V().values(\"age\").is(P.within(__.V(vid1).out(\"knows\").values(\"age\").fold()))",
+ "canonical": "g.V().values(\"age\").is(P.within(__.V(vid1).out(\"knows\").values(\"age\").fold()))",
+ "anonymized": "g.V().values(string0).is(P.within(__.V(vid1).out(string1).values(string0).fold()))",
+ "dotnet": "g.V().Values<object>(\"age\").Is(P.Within(__.V(vid1).Out(\"knows\").Values<object>(\"age\").Fold()))",
+ "go": "g.V().Values(\"age\").Is(gremlingo.P.Within(gremlingo.T__.V(vid1).Out(\"knows\").Values(\"age\").Fold()))",
+ "groovy": "g.V().values(\"age\").is(P.within(__.V(vid1).out(\"knows\").values(\"age\").fold()))",
+ "java": "g.V().values(\"age\").is(P.within(__.V(vid1).out(\"knows\").values(\"age\").fold()))",
+ "javascript": "g.V().values(\"age\").is(P.within(__.V(vid1).out(\"knows\").values(\"age\").fold()))",
+ "python": "g.V().values('age').is_(P.within(__.V(vid1).out('knows').values('age').fold()))"
}
]
},
@@ -13431,16 +13431,16 @@
"scenario": "g_V_valuesXageX_whereXwithinXVXvid1X_outXknowsX_valuesXageXXX",
"traversals": [
{
- "original": "g.V().values(\"age\").where(P.within(__.V(vid1).out(\"knows\").values(\"age\")))",
- "language": "g.V().values(\"age\").where(P.within(__.V(vid1).out(\"knows\").values(\"age\")))",
- "canonical": "g.V().values(\"age\").where(P.within(__.V(vid1).out(\"knows\").values(\"age\")))",
- "anonymized": "g.V().values(string0).where(P.within(__.V(vid1).out(string1).values(string0)))",
- "dotnet": "g.V().Values<object>(\"age\").Where(P.Within(__.V(vid1).Out(\"knows\").Values<object>(\"age\")))",
- "go": "g.V().Values(\"age\").Where(gremlingo.P.Within(gremlingo.T__.V(vid1).Out(\"knows\").Values(\"age\")))",
- "groovy": "g.V().values(\"age\").where(P.within(__.V(vid1).out(\"knows\").values(\"age\")))",
- "java": "g.V().values(\"age\").where(P.within(__.V(vid1).out(\"knows\").values(\"age\")))",
- "javascript": "g.V().values(\"age\").where(P.within(__.V(vid1).out(\"knows\").values(\"age\")))",
- "python": "g.V().values('age').where(P.within(__.V(vid1).out('knows').values('age')))"
+ "original": "g.V().values(\"age\").where(P.within(__.V(vid1).out(\"knows\").values(\"age\").fold()))",
+ "language": "g.V().values(\"age\").where(P.within(__.V(vid1).out(\"knows\").values(\"age\").fold()))",
+ "canonical": "g.V().values(\"age\").where(P.within(__.V(vid1).out(\"knows\").values(\"age\").fold()))",
+ "anonymized": "g.V().values(string0).where(P.within(__.V(vid1).out(string1).values(string0).fold()))",
+ "dotnet": "g.V().Values<object>(\"age\").Where(P.Within(__.V(vid1).Out(\"knows\").Values<object>(\"age\").Fold()))",
+ "go": "g.V().Values(\"age\").Where(gremlingo.P.Within(gremlingo.T__.V(vid1).Out(\"knows\").Values(\"age\").Fold()))",
+ "groovy": "g.V().values(\"age\").where(P.within(__.V(vid1).out(\"knows\").values(\"age\").fold()))",
+ "java": "g.V().values(\"age\").where(P.within(__.V(vid1).out(\"knows\").values(\"age\").fold()))",
+ "javascript": "g.V().values(\"age\").where(P.within(__.V(vid1).out(\"knows\").values(\"age\").fold()))",
+ "python": "g.V().values('age').where(P.within(__.V(vid1).out('knows').values('age').fold()))"
}
]
},
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/HasTraversal.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/HasTraversal.feature
index 8479eeac33..d9e521c21c 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/HasTraversal.feature
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/HasTraversal.feature
@@ -204,14 +204,14 @@ Feature: Step - has() with traversal arguments
| result |
| d[29].i |
- # Multi-traversal within() where one traversal produces multiple results
+ # Multi-traversal within() where one traversal produces multiple results — use fold() to collect
@GraphComputerVerificationMidVNotSupported
Scenario: g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_constantXpeterXXX
Given the modern graph
And using the parameter vid1 defined as "v[marko].id"
And the traversal of
"""
- g.V().has("name", P.within(__.V(vid1).out("knows").values("name"), __.constant("peter")))
+ g.V().has("name", P.within(__.V(vid1).out("knows").values("name").fold(), __.constant("peter")))
"""
When iterated to list
Then the result should be unordered
@@ -272,7 +272,7 @@ Feature: Step - has() with traversal arguments
And using the parameter vid3 defined as "v[josh].id"
And the traversal of
"""
- g.V().has("name", P.within(__.V(vid1).out("knows").values("name"), __.V(vid3).out("created").values("name")))
+ g.V().has("name", P.within(__.V(vid1).out("knows").values("name").fold(), __.V(vid3).out("created").values("name").fold()))
"""
When iterated to list
Then the result should be unordered
@@ -290,19 +290,19 @@ Feature: Step - has() with traversal arguments
And using the parameter vid3 defined as "v[josh].id"
And the traversal of
"""
- g.V().hasLabel("software").has("name", P.without(__.V(vid1).out("created").values("name"), __.V(vid3).out("created").values("name")))
+ g.V().hasLabel("software").has("name", P.without(__.V(vid1).out("created").values("name").fold(), __.V(vid3).out("created").values("name").fold()))
"""
When iterated to list
Then the result should be empty
- # Multi-traversal within() with is() — cross-label dynamic filtering
+ # Multi-traversal within() with is() — cross-label dynamic filtering, use fold() for multi-result
@GraphComputerVerificationMidVNotSupported
Scenario: g_V_hasLabelXpersonX_valuesXageX_isXwithinXVXvid1X_valuesXageX_V_hasXname_lopX_inXcreatedX_valuesXageXXX
Given the modern graph
And using the parameter vid1 defined as "v[marko].id"
And the traversal of
"""
- g.V().hasLabel("person").values("age").is(P.within(__.V(vid1).values("age"), __.V().has("name","lop").in("created").values("age")))
+ g.V().hasLabel("person").values("age").is(P.within(__.V(vid1).values("age").fold(), __.V().has("name","lop").in("created").values("age").fold()))
"""
When iterated to list
Then the result should be unordered
@@ -318,7 +318,7 @@ Feature: Step - has() with traversal arguments
And using the parameter vid1 defined as "v[marko].id"
And the traversal of
"""
- g.V(vid1).outE("knows").filter(__.inV().has("name", P.within(__.V().has("name","lop").in("created").values("name"), __.V().has("name","ripple").in("created").values("name"))))
+ g.V(vid1).outE("knows").filter(__.inV().has("name", P.within(__.V().has("name","lop").in("created").values("name").fold(), __.V().has("name","ripple").in("created").values("name").fold())))
"""
When iterated to list
Then the result should be unordered
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/IsTraversal.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/IsTraversal.feature
index 42b1eb898b..4a70f2ba24 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/IsTraversal.feature
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/IsTraversal.feature
@@ -93,7 +93,7 @@ Feature: Step - is() with traversal-bearing predicates
And using the parameter vid1 defined as "v[marko].id"
And the traversal of
"""
- g.V().values("age").is(P.within(__.V(vid1).out("knows").values("age")))
+ g.V().values("age").is(P.within(__.V(vid1).out("knows").values("age").fold()))
"""
When iterated to list
Then the result should be unordered
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/WhereTraversal.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/WhereTraversal.feature
index cf9628883a..abc91bbea6 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/WhereTraversal.feature
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/WhereTraversal.feature
@@ -69,7 +69,7 @@ Feature: Step - where(P) with traversal-bearing predicates
And using the parameter vid1 defined as "v[marko].id"
And the traversal of
"""
- g.V().values("age").where(P.within(__.V(vid1).out("knows").values("age")))
+ g.V().values("age").where(P.within(__.V(vid1).out("knows").values("age").fold()))
"""
When iterated to list
Then the result should be unordered
(tinkerpop) 13/14: clean up & refactors
Posted by xi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
xiazcy pushed a commit to branch steps-taking-traversal-poc
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit eee4d8192bc0a45f574f30a820011f23b94ff8cc
Author: Yang Xia <xi...@gmail.com>
AuthorDate: Thu Jun 4 17:12:35 2026 -0700
clean up & refactors
---
.../tinkerpop/gremlin/process/traversal/P.java | 48 ++++++++-------
.../tinkerpop/gremlin/process/traversal/TextP.java | 12 ++--
.../traversal/dsl/graph/GraphTraversal.java | 14 ++---
.../traversal/dsl/graph/GraphTraversalSource.java | 4 +-
.../traversal/step/filter/WherePredicateStep.java | 58 +++++++++---------
.../ChildTraversalVerificationStrategy.java | 44 +++++---------
.../traversal/util/ChildTraversalValidator.java | 69 +++++-----------------
7 files changed, 94 insertions(+), 155 deletions(-)
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java
index 72cd3bcc5d..f95001a55b 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java
@@ -346,27 +346,26 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
trav.reset();
trav.addStart(split);
- this.isCollection = false;
-
try {
- // All predicates take only the first result — consistent with by(traversal).
- // For within/without, the first result should be a Collection (e.g., from fold()).
+ // Take first result only — consistent with by(traversal) semantics.
if (!trav.hasNext()) {
this.resolvedEmpty = true;
this.literals = Collections.emptyList();
+ this.isCollection = false;
} else {
this.resolvedEmpty = false;
final Object firstResult = trav.next();
- if (this.biPredicate instanceof Contains && firstResult instanceof Collection) {
- // The traversal produced a Collection as its first result — use it directly
- this.literals = (Collection<V>) firstResult;
- this.isCollection = true;
- } else if (this.biPredicate instanceof Contains) {
- // Single non-Collection value for within/without — wrap in a singleton list
- this.literals = Collections.singletonList((V) firstResult);
+ if (this.biPredicate instanceof Contains) {
+ // Contains predicates need a Collection value. If first result is already
+ // a Collection (e.g., from fold()), use it directly. Otherwise wrap in singleton.
+ if (firstResult instanceof Collection) {
+ this.literals = (Collection<V>) firstResult;
+ } else {
+ this.literals = Collections.singletonList((V) firstResult);
+ }
this.isCollection = true;
} else {
- this.literals = Collections.singleton((V) firstResult);
+ setValue((V) firstResult);
}
}
} finally {
@@ -391,8 +390,8 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
trav.addStart(split);
try {
- // Take only the first result from each traversal — consistent with by(traversal).
- // If the first result is a Collection (from fold()), unpack it into the results.
+ // Take first result only from each traversal.
+ // If the result is a Collection (from fold()), unpack it.
if (trav.hasNext()) {
final Object firstResult = trav.next();
if (firstResult instanceof Collection) {
@@ -407,7 +406,6 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
}
this.resolvedEmpty = allResults.isEmpty();
-
if (allResults.isEmpty()) {
this.literals = Collections.emptyList();
this.isCollection = false;
@@ -730,7 +728,7 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
* @since 4.0.0
*/
public static <V> P<V> eq(final Traversal<?, ?> traversalValue) {
- ChildTraversalValidator.validateFilterContext(traversalValue.asAdmin());
+ ChildTraversalValidator.validate(traversalValue.asAdmin());
return new P(Compare.eq, traversalValue.asAdmin());
}
@@ -740,7 +738,7 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
* @since 4.0.0
*/
public static <V> P<V> neq(final Traversal<?, ?> traversalValue) {
- ChildTraversalValidator.validateFilterContext(traversalValue.asAdmin());
+ ChildTraversalValidator.validate(traversalValue.asAdmin());
return new P(Compare.neq, traversalValue.asAdmin());
}
@@ -750,7 +748,7 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
* @since 4.0.0
*/
public static <V> P<V> lt(final Traversal<?, ?> traversalValue) {
- ChildTraversalValidator.validateFilterContext(traversalValue.asAdmin());
+ ChildTraversalValidator.validate(traversalValue.asAdmin());
return new P(Compare.lt, traversalValue.asAdmin());
}
@@ -760,7 +758,7 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
* @since 4.0.0
*/
public static <V> P<V> lte(final Traversal<?, ?> traversalValue) {
- ChildTraversalValidator.validateFilterContext(traversalValue.asAdmin());
+ ChildTraversalValidator.validate(traversalValue.asAdmin());
return new P(Compare.lte, traversalValue.asAdmin());
}
@@ -770,7 +768,7 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
* @since 4.0.0
*/
public static <V> P<V> gt(final Traversal<?, ?> traversalValue) {
- ChildTraversalValidator.validateFilterContext(traversalValue.asAdmin());
+ ChildTraversalValidator.validate(traversalValue.asAdmin());
return new P(Compare.gt, traversalValue.asAdmin());
}
@@ -780,7 +778,7 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
* @since 4.0.0
*/
public static <V> P<V> gte(final Traversal<?, ?> traversalValue) {
- ChildTraversalValidator.validateFilterContext(traversalValue.asAdmin());
+ ChildTraversalValidator.validate(traversalValue.asAdmin());
return new P(Compare.gte, traversalValue.asAdmin());
}
@@ -790,7 +788,7 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
* @since 4.0.0
*/
public static <V> P<V> within(final Traversal<?, ?> traversalValue) {
- ChildTraversalValidator.validateFilterContext(traversalValue.asAdmin());
+ ChildTraversalValidator.validate(traversalValue.asAdmin());
return new P(Contains.within, traversalValue.asAdmin());
}
@@ -810,7 +808,7 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
}
}
for (final Traversal.Admin<?, ?> tv : traversals) {
- ChildTraversalValidator.validateFilterContext(tv);
+ ChildTraversalValidator.validate(tv);
}
return new P(Contains.within, traversals);
}
@@ -821,7 +819,7 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
* @since 4.0.0
*/
public static <V> P<V> without(final Traversal<?, ?> traversalValue) {
- ChildTraversalValidator.validateFilterContext(traversalValue.asAdmin());
+ ChildTraversalValidator.validate(traversalValue.asAdmin());
return new P(Contains.without, traversalValue.asAdmin());
}
@@ -841,7 +839,7 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
}
}
for (final Traversal.Admin<?, ?> tv : traversals) {
- ChildTraversalValidator.validateFilterContext(tv);
+ ChildTraversalValidator.validate(tv);
}
return new P(Contains.without, traversals);
}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TextP.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TextP.java
index dcbe70a0cd..c0bd155185 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TextP.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TextP.java
@@ -93,7 +93,7 @@ public class TextP extends P<String> {
* @since 4.0.0
*/
public static TextP startingWith(final Traversal<?, ?> traversalValue) {
- ChildTraversalValidator.validateFilterContext(traversalValue.asAdmin());
+ ChildTraversalValidator.validate(traversalValue.asAdmin());
return new TextP(Text.startingWith, traversalValue.asAdmin());
}
@@ -121,7 +121,7 @@ public class TextP extends P<String> {
* @since 4.0.0
*/
public static TextP notStartingWith(final Traversal<?, ?> traversalValue) {
- ChildTraversalValidator.validateFilterContext(traversalValue.asAdmin());
+ ChildTraversalValidator.validate(traversalValue.asAdmin());
return new TextP(Text.notStartingWith, traversalValue.asAdmin());
}
@@ -149,7 +149,7 @@ public class TextP extends P<String> {
* @since 4.0.0
*/
public static TextP endingWith(final Traversal<?, ?> traversalValue) {
- ChildTraversalValidator.validateFilterContext(traversalValue.asAdmin());
+ ChildTraversalValidator.validate(traversalValue.asAdmin());
return new TextP(Text.endingWith, traversalValue.asAdmin());
}
@@ -177,7 +177,7 @@ public class TextP extends P<String> {
* @since 4.0.0
*/
public static TextP notEndingWith(final Traversal<?, ?> traversalValue) {
- ChildTraversalValidator.validateFilterContext(traversalValue.asAdmin());
+ ChildTraversalValidator.validate(traversalValue.asAdmin());
return new TextP(Text.notEndingWith, traversalValue.asAdmin());
}
@@ -205,7 +205,7 @@ public class TextP extends P<String> {
* @since 4.0.0
*/
public static TextP containing(final Traversal<?, ?> traversalValue) {
- ChildTraversalValidator.validateFilterContext(traversalValue.asAdmin());
+ ChildTraversalValidator.validate(traversalValue.asAdmin());
return new TextP(Text.containing, traversalValue.asAdmin());
}
@@ -233,7 +233,7 @@ public class TextP extends P<String> {
* @since 4.0.0
*/
public static TextP notContaining(final Traversal<?, ?> traversalValue) {
- ChildTraversalValidator.validateFilterContext(traversalValue.asAdmin());
+ ChildTraversalValidator.validate(traversalValue.asAdmin());
return new TextP(Text.notContaining, traversalValue.asAdmin());
}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
index 552dec3be8..e015e708cb 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
@@ -427,7 +427,7 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
*/
public default GraphTraversal<S, Vertex> V(final Traversal<?, ?> traversal) {
if (null == traversal) return V(new Object[]{ null });
- ChildTraversalValidator.validateLookupContext(traversal.asAdmin());
+ ChildTraversalValidator.validate(traversal.asAdmin());
this.asAdmin().getGremlinLang().addStep(Symbols.V, traversal);
return this.asAdmin().addStep(new GraphStep<>(this.asAdmin(), Vertex.class, false, traversal.asAdmin()));
}
@@ -467,7 +467,7 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
*/
public default GraphTraversal<S, Edge> E(final Traversal<?, ?> traversal) {
if (null == traversal) return E(new Object[]{ null });
- ChildTraversalValidator.validateLookupContext(traversal.asAdmin());
+ ChildTraversalValidator.validate(traversal.asAdmin());
this.asAdmin().getGremlinLang().addStep(Symbols.E, traversal);
return this.asAdmin().addStep(new GraphStep<>(this.asAdmin(), Edge.class, false, traversal.asAdmin()));
}
@@ -2718,7 +2718,7 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
*/
public default GraphTraversal<S, E> has(final String propertyKey, final Traversal<?, ?> traversal) {
if (null == traversal) return has(propertyKey, (Object) null);
- ChildTraversalValidator.validateFilterContext(traversal.asAdmin());
+ ChildTraversalValidator.validate(traversal.asAdmin());
this.asAdmin().getGremlinLang().addStep(Symbols.has, propertyKey, traversal);
final HasContainer hasContainer = new HasContainer(propertyKey, traversal.asAdmin());
return this.asAdmin().addStep(new HasStep(this.asAdmin(), hasContainer));
@@ -2739,7 +2739,7 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
if (null == accessor)
throw new IllegalArgumentException("The T accessor value of has(T,Traversal) cannot be null");
if (null == traversal) return has(accessor, (Object) null);
- ChildTraversalValidator.validateFilterContext(traversal.asAdmin());
+ ChildTraversalValidator.validate(traversal.asAdmin());
this.asAdmin().getGremlinLang().addStep(Symbols.has, accessor, traversal);
final HasContainer hasContainer = new HasContainer(accessor.getAccessor(), traversal.asAdmin());
@@ -2792,7 +2792,7 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
*/
public default GraphTraversal<S, E> has(final String label, final String propertyKey, final Traversal<?, ?> traversal) {
if (null == traversal) return has(label, propertyKey, (Object) null);
- ChildTraversalValidator.validateFilterContext(traversal.asAdmin());
+ ChildTraversalValidator.validate(traversal.asAdmin());
this.asAdmin().getGremlinLang().addStep(Symbols.has, label, propertyKey, traversal);
TraversalHelper.addHasContainer(this.asAdmin(), new HasContainer(T.label.getAccessor(), P.eq(label)));
final HasContainer hasContainer = new HasContainer(propertyKey, traversal.asAdmin());
@@ -2905,7 +2905,7 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
*/
public default GraphTraversal<S, E> hasLabel(final Traversal<?, ?> traversal) {
if (null == traversal) return hasLabel((String) null);
- ChildTraversalValidator.validateFilterContext(traversal.asAdmin());
+ ChildTraversalValidator.validate(traversal.asAdmin());
this.asAdmin().getGremlinLang().addStep(Symbols.hasLabel, traversal);
final HasContainer hasContainer = new HasContainer(T.label.getAccessor(), traversal.asAdmin());
return this.asAdmin().addStep(new HasStep(this.asAdmin(), hasContainer));
@@ -3959,7 +3959,7 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
*/
public default GraphTraversal<S, E> property(final Traversal<?, ?> mapTraversal) {
if (null == mapTraversal) return this;
- ChildTraversalValidator.validateMutationContext(mapTraversal.asAdmin());
+ ChildTraversalValidator.validate(mapTraversal.asAdmin());
this.asAdmin().getGremlinLang().addStep(Symbols.property, mapTraversal);
this.asAdmin().addStep(new AddPropertyStepPlaceholder(this.asAdmin(), null, "~traversalMap", mapTraversal.asAdmin()));
return this;
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 96a9ae7980..bf33e619c5 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
@@ -549,7 +549,7 @@ public class GraphTraversalSource implements TraversalSource {
*/
public GraphTraversal<Vertex, Vertex> V(final Traversal<?, ?> traversal) {
if (null == traversal) return V(new Object[]{ null });
- ChildTraversalValidator.validateLookupContext(traversal.asAdmin());
+ ChildTraversalValidator.validate(traversal.asAdmin());
final GraphTraversalSource clone = this.clone();
clone.gremlinLang.addStep(GraphTraversal.Symbols.V, traversal);
final GraphTraversal.Admin<Vertex, Vertex> traversalAdmin = new DefaultGraphTraversal<>(clone);
@@ -588,7 +588,7 @@ public class GraphTraversalSource implements TraversalSource {
*/
public GraphTraversal<Edge, Edge> E(final Traversal<?, ?> traversal) {
if (null == traversal) return E(new Object[]{ null });
- ChildTraversalValidator.validateLookupContext(traversal.asAdmin());
+ ChildTraversalValidator.validate(traversal.asAdmin());
final GraphTraversalSource clone = this.clone();
clone.gremlinLang.addStep(GraphTraversal.Symbols.E, traversal);
final GraphTraversal.Admin<Edge, Edge> traversalAdmin = new DefaultGraphTraversal<>(clone);
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WherePredicateStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WherePredicateStep.java
index ce47519ea7..a3bd10ea48 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WherePredicateStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WherePredicateStep.java
@@ -54,6 +54,7 @@ public final class WherePredicateStep<S> extends FilterStep<S> implements Scopin
protected Set<String> keepLabels;
protected TraversalRing<S, ?> traversalRing = new TraversalRing<>();
+ private List<Traversal.Admin<?, ?>> predicateTraversals;
public WherePredicateStep(final Traversal.Admin traversal, final Optional<String> startKey, final P<String> predicate) {
super(traversal);
@@ -63,8 +64,12 @@ public final class WherePredicateStep<S> extends FilterStep<S> implements Scopin
this.predicate = (P) predicate;
this.selectKeys = new ArrayList<>();
this.configurePredicates(this.predicate);
- // Integrate child traversals from the predicate so they participate in cloning/strategy application
- P.integrateTraversals(this.predicate, this);
+ // Cache and integrate child traversals from the predicate
+ this.predicateTraversals = new ArrayList<>();
+ P.collectTraversals(this.predicate, this.predicateTraversals);
+ for (final Traversal.Admin<?, ?> t : this.predicateTraversals) {
+ this.integrateChild(t);
+ }
}
private void configurePredicates(final P<Object> predicate) {
@@ -115,35 +120,28 @@ public final class WherePredicateStep<S> extends FilterStep<S> implements Scopin
@Override
protected boolean filter(final Traverser.Admin<S> traverser) {
- // If the predicate has a child traversal, resolve it and test directly against the
- // current value (or startKey scope value). This bypasses the scope-label mechanism.
- if (this.predicate.hasTraversal()) {
- final Object leftValue;
- if (null == this.startKey) {
- final TraversalProduct product = TraversalUtil.produce(traverser, this.traversalRing.next());
- this.traversalRing.reset();
- if (!product.isProductive()) return false;
- leftValue = product.get();
- } else {
- final TraversalProduct product = TraversalUtil.produce((S) this.getSafeScopeValue(Pop.last, this.startKey, traverser), this.traversalRing.next());
- this.traversalRing.reset();
- if (!product.isProductive()) return false;
- leftValue = product.get();
- }
- this.predicate.resolve(traverser);
- if (this.predicate.isResolvedEmpty()) return false;
- return this.predicate.test(leftValue);
- }
-
- // Standard scope-label path for non-traversal predicates
+ // Resolve the left-hand value (current traverser or startKey scope value)
final TraversalProduct product = null == this.startKey ?
TraversalUtil.produce(traverser, this.traversalRing.next()) :
TraversalUtil.produce((S) this.getSafeScopeValue(Pop.last, this.startKey, traverser), this.traversalRing.next());
- final boolean predicateValuesProductive = this.setPredicateValues(this.predicate, traverser, this.selectKeys.iterator());
- this.traversalRing.reset();
+ if (!product.isProductive()) {
+ this.traversalRing.reset();
+ return false;
+ }
- return product.isProductive() && predicateValuesProductive && this.predicate.test(product.get());
+ if (this.predicate.hasTraversal()) {
+ // Traversal-bearing predicate: resolve the child traversal, then test
+ this.traversalRing.reset();
+ this.predicate.resolve(traverser);
+ if (this.predicate.isResolvedEmpty()) return false;
+ return this.predicate.test(product.get());
+ } else {
+ // Standard scope-label path: resolve predicate values from path labels
+ final boolean predicateValuesProductive = this.setPredicateValues(this.predicate, traverser, this.selectKeys.iterator());
+ this.traversalRing.reset();
+ return predicateValuesProductive && this.predicate.test(product.get());
+ }
}
@Override
@@ -190,11 +188,11 @@ public final class WherePredicateStep<S> extends FilterStep<S> implements Scopin
@Override
public List<Traversal.Admin<S, ?>> getLocalChildren() {
+ if (this.predicateTraversals.isEmpty()) {
+ return (List) this.traversalRing.getTraversals();
+ }
final List<Traversal.Admin<S, ?>> children = new ArrayList<>((List) this.traversalRing.getTraversals());
- // Also expose predicate child traversals for strategy application and cloning
- final List<Traversal.Admin<?, ?>> predicateTraversals = new ArrayList<>();
- P.collectTraversals(this.predicate, predicateTraversals);
- children.addAll((List) predicateTraversals);
+ children.addAll((List) this.predicateTraversals);
return children;
}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ChildTraversalVerificationStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ChildTraversalVerificationStrategy.java
index 95ba0cc642..730de40913 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ChildTraversalVerificationStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ChildTraversalVerificationStrategy.java
@@ -30,20 +30,12 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.filter.NoneStep;
import org.apache.tinkerpop.gremlin.process.traversal.step.map.GraphStep;
import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.AddPropertyStepContract;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy;
-import org.apache.tinkerpop.gremlin.process.traversal.util.ChildTraversalContext;
import org.apache.tinkerpop.gremlin.process.traversal.util.ChildTraversalValidator;
/**
- * A verification strategy that validates child traversals do not contain disallowed mutating steps
- * based on the context in which they are used. This serves as a safety net for cases where
- * construction-time validation is bypassed (e.g., programmatic traversal construction).
- * <p>
- * Context classification:
- * <ul>
- * <li>{@code HasStep}, {@code IsStep}, {@code AllStep}, {@code AnyStep}, {@code NoneStep} → FILTER</li>
- * <li>{@code GraphStep} with idTraversal → LOOKUP</li>
- * <li>{@code AddPropertyStepContract} → MUTATION</li>
- * </ul>
+ * Validates that child traversals in filter, lookup, and mutation steps do not contain mutating steps.
+ * Serves as a safety net for programmatic traversal construction that bypasses the DSL's
+ * construction-time validation.
*/
public final class ChildTraversalVerificationStrategy
extends AbstractTraversalStrategy<TraversalStrategy.VerificationStrategy>
@@ -57,31 +49,23 @@ public final class ChildTraversalVerificationStrategy
@Override
public void apply(final Traversal.Admin<?, ?> traversal) {
for (final Step<?, ?> step : traversal.getSteps()) {
- if (step instanceof TraversalParent) {
- final ChildTraversalContext context = classifyContext(step);
- if (context != ChildTraversalContext.NONE) {
- for (final Traversal.Admin<?, ?> child : ((TraversalParent) step).getLocalChildren()) {
- try {
- ChildTraversalValidator.validateRecursive(child, context);
- } catch (final IllegalArgumentException e) {
- throw new VerificationException(e.getMessage(), traversal);
- }
+ if (step instanceof TraversalParent && hasChildTraversalsToValidate(step)) {
+ for (final Traversal.Admin<?, ?> child : ((TraversalParent) step).getLocalChildren()) {
+ try {
+ ChildTraversalValidator.validate(child);
+ } catch (final IllegalArgumentException e) {
+ throw new VerificationException(e.getMessage(), traversal);
}
}
}
}
}
- private ChildTraversalContext classifyContext(final Step<?, ?> step) {
- if (step instanceof HasStep || step instanceof IsStep ||
- step instanceof AllStep || step instanceof AnyStep || step instanceof NoneStep) {
- return ChildTraversalContext.FILTER;
- } else if (step instanceof GraphStep && ((GraphStep<?, ?>) step).getIdTraversal() != null) {
- return ChildTraversalContext.LOOKUP;
- } else if (step instanceof AddPropertyStepContract) {
- return ChildTraversalContext.MUTATION;
- }
- return ChildTraversalContext.NONE;
+ private boolean hasChildTraversalsToValidate(final Step<?, ?> step) {
+ return step instanceof HasStep || step instanceof IsStep ||
+ step instanceof AllStep || step instanceof AnyStep || step instanceof NoneStep ||
+ (step instanceof GraphStep && ((GraphStep<?, ?>) step).getIdTraversal() != null) ||
+ step instanceof AddPropertyStepContract;
}
public static ChildTraversalVerificationStrategy instance() {
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ChildTraversalValidator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ChildTraversalValidator.java
index 18b35759a2..fb682e9a4b 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ChildTraversalValidator.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ChildTraversalValidator.java
@@ -24,14 +24,10 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.Mutating;
import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
/**
- * Validates child traversals to ensure they do not contain disallowed steps based on the context
- * in which they are used. This utility is shared between construction-time validation (in API methods)
- * and strategy-time validation ({@code ChildTraversalVerificationStrategy}).
- * <p>
- * Validation rules:
- * <ul>
- * <li><b>FILTER / LOOKUP / MUTATION context:</b> No steps implementing {@link Mutating} are allowed at any nesting depth.</li>
- * </ul>
+ * Validates that child traversals do not contain mutating steps. Child traversals used as
+ * arguments to filter predicates ({@code has()}, {@code is()}, etc.), lookup steps
+ * ({@code V(traversal)}, {@code E(traversal)}), and mutation steps ({@code property(traversal)})
+ * must be read-only — their purpose is to compute values, not produce side effects.
* <p>
* Recursion walks both {@link TraversalParent#getLocalChildren()} and
* {@link TraversalParent#getGlobalChildren()} to detect mutations nested inside
@@ -40,64 +36,27 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
public final class ChildTraversalValidator {
private ChildTraversalValidator() {
- // static utility
- }
-
- /**
- * Validates a child traversal used in filter context (has, is, all, any, none, choose predicate).
- * Throws {@link IllegalArgumentException} if any {@link Mutating} step is found.
- */
- public static void validateFilterContext(final Traversal.Admin<?, ?> child) {
- validateRecursive(child, ChildTraversalContext.FILTER);
- }
-
- /**
- * Validates a child traversal used in lookup context (V(traversal), E(traversal)).
- * Throws {@link IllegalArgumentException} if any {@link Mutating} step is found.
- */
- public static void validateLookupContext(final Traversal.Admin<?, ?> child) {
- validateRecursive(child, ChildTraversalContext.LOOKUP);
}
/**
- * Validates a child traversal used in mutation context (property(traversal)).
- * Throws {@link IllegalArgumentException} if any {@link Mutating} step is found.
+ * Validates that a child traversal contains no {@link Mutating} steps at any nesting depth.
+ * Throws {@link IllegalArgumentException} if one is found.
*/
- public static void validateMutationContext(final Traversal.Admin<?, ?> child) {
- validateRecursive(child, ChildTraversalContext.MUTATION);
- }
-
- /**
- * Recursively validates all steps in the child traversal and its nested children.
- */
- public static void validateRecursive(final Traversal.Admin<?, ?> child,
- final ChildTraversalContext context) {
+ public static void validate(final Traversal.Admin<?, ?> child) {
for (final Step<?, ?> step : child.getSteps()) {
- validateStep(step, context);
+ if (step instanceof Mutating) {
+ throw new IllegalArgumentException(
+ "Child traversal contains mutating step " +
+ step.getClass().getSimpleName() + ". Mutating steps are not allowed in child traversals.");
+ }
if (step instanceof TraversalParent) {
for (final Traversal.Admin<?, ?> nested : ((TraversalParent) step).getLocalChildren()) {
- validateRecursive(nested, context);
+ validate(nested);
}
for (final Traversal.Admin<?, ?> nested : ((TraversalParent) step).getGlobalChildren()) {
- validateRecursive(nested, context);
+ validate(nested);
}
}
}
}
-
- private static void validateStep(final Step<?, ?> step, final ChildTraversalContext context) {
- switch (context) {
- case FILTER:
- case LOOKUP:
- case MUTATION:
- if (step instanceof Mutating) {
- throw new IllegalArgumentException(
- "Child traversal in " + context.name().toLowerCase() + " context contains mutating step " +
- step.getClass().getSimpleName() + ". Mutating steps are not allowed in this context.");
- }
- break;
- default:
- break;
- }
- }
}
(tinkerpop) 05/14: allow V()/E() start steps to take traversals by generating a false traverser like mergeV/mergeE
Posted by xi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
xiazcy pushed a commit to branch steps-taking-traversal-poc
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit a9d1f642170da171bdc91b1a3ccb232f1e829d72
Author: Yang Xia <xi...@gmail.com>
AuthorDate: Wed May 20 16:54:19 2026 -0700
allow V()/E() start steps to take traversals by generating a false traverser like mergeV/mergeE
---
.../grammar/TraversalSourceSpawnMethodVisitor.java | 22 ++++++++++------------
.../traversal/dsl/graph/GraphTraversalSource.java | 10 ++++++----
.../process/traversal/step/map/GraphStep.java | 15 ++++++++++-----
gremlin-language/src/main/antlr4/Gremlin.g4 | 2 ++
.../gremlin/test/features/map/VETraversal.feature | 10 ++++++++--
5 files changed, 36 insertions(+), 23 deletions(-)
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalSourceSpawnMethodVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalSourceSpawnMethodVisitor.java
index f2ca8b7299..bed196c29e 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalSourceSpawnMethodVisitor.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalSourceSpawnMethodVisitor.java
@@ -99,13 +99,12 @@ public class TraversalSourceSpawnMethodVisitor extends DefaultGremlinBaseVisitor
*/
@Override
public GraphTraversal visitTraversalSourceSpawnMethod_E(final GremlinParser.TraversalSourceSpawnMethod_EContext ctx) {
+ if (ctx.nestedTraversal() != null) {
+ return this.traversalSource.E((Traversal<?, ?>) anonymousVisitor.visitNestedTraversal(ctx.nestedTraversal()));
+ }
final Object[] args = antlr.argumentVisitor.parseObjectVarargs(ctx.genericArgumentVarargs());
- for (final Object arg : args) {
- if (arg instanceof Traversal) {
- throw new IllegalArgumentException(
- "E(traversal) cannot be used as a start step because there is no Traverser context " +
- "available to evaluate the child traversal. Use E(traversal) as a mid-traversal step instead.");
- }
+ if (args.length == 1 && args[0] instanceof Traversal) {
+ return this.traversalSource.E((Traversal<?, ?>) args[0]);
}
return this.traversalSource.E(args);
}
@@ -115,13 +114,12 @@ public class TraversalSourceSpawnMethodVisitor extends DefaultGremlinBaseVisitor
*/
@Override
public GraphTraversal visitTraversalSourceSpawnMethod_V(final GremlinParser.TraversalSourceSpawnMethod_VContext ctx) {
+ if (ctx.nestedTraversal() != null) {
+ return this.traversalSource.V((Traversal<?, ?>) anonymousVisitor.visitNestedTraversal(ctx.nestedTraversal()));
+ }
final Object[] args = antlr.argumentVisitor.parseObjectVarargs(ctx.genericArgumentVarargs());
- for (final Object arg : args) {
- if (arg instanceof Traversal) {
- throw new IllegalArgumentException(
- "V(traversal) cannot be used as a start step because there is no Traverser context " +
- "available to evaluate the child traversal. Use V(traversal) as a mid-traversal step instead.");
- }
+ if (args.length == 1 && args[0] instanceof Traversal) {
+ return this.traversalSource.V((Traversal<?, ?>) args[0]);
}
return this.traversalSource.V(args);
}
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 78ab16e68e..b0991a67b9 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
@@ -539,8 +539,9 @@ public class GraphTraversalSource implements TraversalSource {
/**
* Spawns a {@link GraphTraversal} starting with vertices whose IDs are resolved from a child traversal.
- * This form will throw an {@link IllegalStateException} at runtime because there is no traverser context
- * available to evaluate the child traversal as a start step.
+ * As a start step, a synthetic traverser is generated to seed the child traversal evaluation,
+ * consistent with how {@code mergeV(traversal)} handles start steps. The child traversal should
+ * be self-contained (e.g., {@code __.V(1).id()}) rather than dependent on an incoming traverser.
*
* @param traversal the child traversal that produces vertex IDs
* @since 4.0.0
@@ -576,8 +577,9 @@ public class GraphTraversalSource implements TraversalSource {
/**
* Spawns a {@link GraphTraversal} starting with edges whose IDs are resolved from a child traversal.
- * This form will throw an {@link IllegalStateException} at runtime because there is no traverser context
- * available to evaluate the child traversal as a start step.
+ * As a start step, a synthetic traverser is generated to seed the child traversal evaluation,
+ * consistent with how {@code mergeE(traversal)} handles start steps. The child traversal should
+ * be self-contained (e.g., {@code __.V(1).outE().id()}) rather than dependent on an incoming traverser.
*
* @param traversal the child traversal that produces edge IDs
* @since 4.0.0
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GraphStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GraphStep.java
index 5abc13ecc9..043c99c99f 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GraphStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GraphStep.java
@@ -199,12 +199,17 @@ public class GraphStep<S, E extends Element> extends AbstractStep<S, E> implemen
if (this.done)
throw FastNoSuchElementException.instance();
if (this.idTraversal != null) {
- throw new IllegalStateException(
- "V(traversal)/E(traversal) cannot be used as a start step: " +
- "no Traverser context available to evaluate the child traversal");
+ // Start step with idTraversal: generate a synthetic traverser to seed
+ // the child traversal, consistent with how mergeV/addV handle start steps.
+ this.done = true;
+ final Traverser.Admin<S> syntheticTraverser = (Traverser.Admin<S>)
+ this.getTraversal().getTraverserGenerator().generate(false, (Step) this, 1L);
+ final Object[] resolvedIds = resolveTraversalIds(syntheticTraverser);
+ this.iterator = lookupElements(resolvedIds);
+ } else {
+ this.done = true;
+ this.iterator = null == this.iteratorSupplier ? EmptyIterator.instance() : this.iteratorSupplier.get();
}
- this.done = true;
- this.iterator = null == this.iteratorSupplier ? EmptyIterator.instance() : this.iteratorSupplier.get();
} else {
this.head = this.starts.next();
if (this.idTraversal != null) {
diff --git a/gremlin-language/src/main/antlr4/Gremlin.g4 b/gremlin-language/src/main/antlr4/Gremlin.g4
index b161a271d3..822cb59481 100644
--- a/gremlin-language/src/main/antlr4/Gremlin.g4
+++ b/gremlin-language/src/main/antlr4/Gremlin.g4
@@ -123,10 +123,12 @@ traversalSourceSpawnMethod_addV
traversalSourceSpawnMethod_E
: K_E LPAREN genericArgumentVarargs RPAREN
+ | K_E LPAREN nestedTraversal RPAREN
;
traversalSourceSpawnMethod_V
: K_V LPAREN genericArgumentVarargs RPAREN
+ | K_V LPAREN nestedTraversal RPAREN
;
traversalSourceSpawnMethod_inject
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/VETraversal.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/VETraversal.feature
index 7bddadb221..c8535d6a74 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/VETraversal.feature
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/VETraversal.feature
@@ -130,7 +130,9 @@ Feature: Step - V(traversal) and E(traversal)
g.V(__.V(vid1).id()).values("name")
"""
When iterated to list
- Then the traversal will raise an error
+ Then the result should be unordered
+ | result |
+ | marko |
Scenario: g_EXVXvid1X_outE_idX
Given the modern graph
@@ -140,4 +142,8 @@ Feature: Step - V(traversal) and E(traversal)
g.E(__.V(vid1).outE().id())
"""
When iterated to list
- Then the traversal will raise an error
+ Then the result should be unordered
+ | result |
+ | e[marko-created->lop] |
+ | e[marko-knows->josh] |
+ | e[marko-knows->vadas] |
(tinkerpop) 01/14: Add traversal-accepting arguments to has(), V(), E(), property(), is(), and predicates.
Posted by xi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
xiazcy pushed a commit to branch steps-taking-traversal-poc
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit 9a3a9ed92b1940cdad77f7e84db204e78539069c
Author: Yang Xia <xi...@gmail.com>
AuthorDate: Thu Apr 23 17:33:57 2026 -0700
Add traversal-accepting arguments to has(), V(), E(), property(), is(), and predicates.
Allows child traversals as arguments in Gremlin steps for dynamic,per-traverser value resolution at runtime.
Assisted-by: Kiro:Claude-Opus-4.6 [Kiro IDE]
---
.../grammar/DefaultGremlinBaseVisitor.java | 24 +
.../language/grammar/TraversalMethodVisitor.java | 124 ++-
.../grammar/TraversalPredicateVisitor.java | 60 +
.../grammar/TraversalSourceSpawnMethodVisitor.java | 23 +-
.../gremlin/process/traversal/GremlinLang.java | 10 +-
.../tinkerpop/gremlin/process/traversal/NotP.java | 16 +
.../tinkerpop/gremlin/process/traversal/P.java | 227 +++-
.../tinkerpop/gremlin/process/traversal/TextP.java | 72 +-
.../traversal/dsl/graph/GraphTraversal.java | 118 +-
.../traversal/dsl/graph/GraphTraversalSource.java | 32 +
.../gremlin/process/traversal/dsl/graph/__.java | 42 +
.../process/traversal/step/HasContainerHolder.java | 2 +-
.../process/traversal/step/filter/AllStep.java | 29 +-
.../process/traversal/step/filter/AnyStep.java | 29 +-
.../process/traversal/step/filter/HasStep.java | 197 +++-
.../process/traversal/step/filter/IsStep.java | 27 +-
.../process/traversal/step/filter/NoneStep.java | 31 +-
.../process/traversal/step/map/GraphStep.java | 122 ++-
.../traversal/step/sideEffect/AddPropertyStep.java | 98 +-
.../process/traversal/step/util/HasContainer.java | 42 +-
.../optimization/InlineFilterStrategy.java | 9 +
.../gremlin/process/traversal/util/AndP.java | 9 +
.../process/traversal/util/ConnectiveP.java | 18 +
.../gremlin/process/traversal/util/OrP.java | 13 +
.../language/grammar/GremlinQueryParserTest.java | 4 +-
.../grammar/GremlinQueryParserTraversalTest.java | 149 +++
.../GremlinLangTraversalRoundTripTest.java | 120 ++
.../tinkerpop/gremlin/process/traversal/PTest.java | 10 +-
.../gremlin/process/traversal/PTraversalTest.java | 218 ++++
.../step/CloneIndependenceTraversalTest.java | 119 ++
.../traversal/step/util/HasContainerTest.java | 96 ++
.../Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs | 36 +
gremlin-go/driver/cucumber/gremlin.go | 36 +
.../gremlin-javascript/test/cucumber/gremlin.js | 36 +
gremlin-language/src/main/antlr4/Gremlin.g4 | 27 +
.../src/main/python/tests/feature/gremlin.py | 36 +
.../gremlin/language/translator/translations.json | 1141 ++++++++++++++++++++
.../test/features/filter/HasTraversal.feature | 203 ++++
.../test/features/filter/IsTraversal.feature | 257 +++++
.../gremlin/test/features/map/VETraversal.feature | 143 +++
.../features/sideEffect/PropertyTraversal.feature | 253 +++++
.../traversal/step/sideEffect/TinkerGraphStep.java | 8 +
.../optimization/TinkerGraphStepStrategy.java | 11 +-
.../TinkerGraphStepStrategyTraversalTest.java | 154 +++
44 files changed, 4366 insertions(+), 65 deletions(-)
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/DefaultGremlinBaseVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/DefaultGremlinBaseVisitor.java
index 550774cd27..96cd5ef97a 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/DefaultGremlinBaseVisitor.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/DefaultGremlinBaseVisitor.java
@@ -455,6 +455,18 @@ public class DefaultGremlinBaseVisitor<T> extends AbstractParseTreeVisitor<T> im
* {@inheritDoc}
*/
@Override public T visitTraversalMethod_has_T_P(final GremlinParser.TraversalMethod_has_T_PContext ctx) { notImplemented(ctx); return null; }
+ /**
+ * {@inheritDoc}
+ */
+ @Override public T visitTraversalMethod_has_String_Traversal(final GremlinParser.TraversalMethod_has_String_TraversalContext ctx) { notImplemented(ctx); return null; }
+ /**
+ * {@inheritDoc}
+ */
+ @Override public T visitTraversalMethod_has_T_Traversal(final GremlinParser.TraversalMethod_has_T_TraversalContext ctx) { notImplemented(ctx); return null; }
+ /**
+ * {@inheritDoc}
+ */
+ @Override public T visitTraversalMethod_has_String_String_Traversal(final GremlinParser.TraversalMethod_has_String_String_TraversalContext ctx) { notImplemented(ctx); return null; }
/**
* {@inheritDoc}
*/
@@ -703,6 +715,18 @@ public class DefaultGremlinBaseVisitor<T> extends AbstractParseTreeVisitor<T> im
* {@inheritDoc}
*/
@Override public T visitTraversalMethod_property_Object(final GremlinParser.TraversalMethod_property_ObjectContext ctx) { notImplemented(ctx); return null; }
+ /**
+ * {@inheritDoc}
+ */
+ @Override public T visitTraversalMethod_property_Cardinality_Object_Traversal(final GremlinParser.TraversalMethod_property_Cardinality_Object_TraversalContext ctx) { notImplemented(ctx); return null; }
+ /**
+ * {@inheritDoc}
+ */
+ @Override public T visitTraversalMethod_property_Object_Traversal(final GremlinParser.TraversalMethod_property_Object_TraversalContext ctx) { notImplemented(ctx); return null; }
+ /**
+ * {@inheritDoc}
+ */
+ @Override public T visitTraversalMethod_property_Traversal(final GremlinParser.TraversalMethod_property_TraversalContext ctx) { notImplemented(ctx); return null; }
/**
* {@inheritDoc}
*/
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitor.java
index 537bdcbe52..1c99745f60 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitor.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitor.java
@@ -22,15 +22,23 @@ import org.apache.tinkerpop.gremlin.process.traversal.DT;
import org.apache.tinkerpop.gremlin.process.traversal.Merge;
import org.apache.tinkerpop.gremlin.process.traversal.Operator;
import org.apache.tinkerpop.gremlin.process.traversal.Order;
+import org.apache.tinkerpop.gremlin.process.traversal.P;
import org.apache.tinkerpop.gremlin.process.traversal.Pop;
import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions;
import org.apache.tinkerpop.gremlin.process.traversal.Scope;
import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
+import org.apache.tinkerpop.gremlin.process.traversal.step.filter.HasStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.GraphStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.AddPropertyStepPlaceholder;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer;
+import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
import org.apache.tinkerpop.gremlin.structure.Column;
import org.apache.tinkerpop.gremlin.structure.Direction;
+import org.apache.tinkerpop.gremlin.structure.Edge;
import org.apache.tinkerpop.gremlin.structure.T;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.apache.tinkerpop.gremlin.structure.VertexProperty.Cardinality;
import java.util.Arrays;
@@ -65,7 +73,14 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal>
*/
@Override
public GraphTraversal visitTraversalMethod_V(final GremlinParser.TraversalMethod_VContext ctx) {
- return this.graphTraversal.V(antlr.argumentVisitor.parseObjectVarargs(ctx.genericArgumentVarargs()));
+ if (ctx.nestedTraversal() != null) {
+ return this.graphTraversal.V((Traversal<?, ?>) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal()));
+ }
+ final Object[] args = antlr.argumentVisitor.parseObjectVarargs(ctx.genericArgumentVarargs());
+ if (args.length == 1 && args[0] instanceof Traversal) {
+ return this.graphTraversal.V((Traversal<?, ?>) args[0]);
+ }
+ return this.graphTraversal.V(args);
}
/**
@@ -73,7 +88,14 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal>
*/
@Override
public GraphTraversal visitTraversalMethod_E(final GremlinParser.TraversalMethod_EContext ctx) {
- return this.graphTraversal.E(antlr.argumentVisitor.parseObjectVarargs(ctx.genericArgumentVarargs()));
+ if (ctx.nestedTraversal() != null) {
+ return this.graphTraversal.E((Traversal<?, ?>) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal()));
+ }
+ final Object[] args = antlr.argumentVisitor.parseObjectVarargs(ctx.genericArgumentVarargs());
+ if (args.length == 1 && args[0] instanceof Traversal) {
+ return this.graphTraversal.E((Traversal<?, ?>) args[0]);
+ }
+ return this.graphTraversal.E(args);
}
/**
@@ -820,8 +842,12 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal>
*/
@Override
public GraphTraversal visitTraversalMethod_has_String_Object(final GremlinParser.TraversalMethod_has_String_ObjectContext ctx) {
- return graphTraversal.has(antlr.genericVisitor.parseString(ctx.stringNullableLiteral()),
- antlr.argumentVisitor.visitGenericArgument(ctx.genericArgument()));
+ final String key = antlr.genericVisitor.parseString(ctx.stringNullableLiteral());
+ final Object value = antlr.argumentVisitor.visitGenericArgument(ctx.genericArgument());
+ if (value instanceof Traversal) {
+ return graphTraversal.has(key, (Traversal<?, ?>) value);
+ }
+ return graphTraversal.has(key, value);
}
/**
@@ -839,14 +865,19 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal>
@Override
public GraphTraversal visitTraversalMethod_has_String_String_Object(final GremlinParser.TraversalMethod_has_String_String_ObjectContext ctx) {
final Object literalOrVar = antlr.argumentVisitor.visitStringNullableArgument(ctx.stringNullableArgument());
+ final String key = antlr.genericVisitor.parseString(ctx.stringNullableLiteral());
+ final Object value = antlr.argumentVisitor.visitGenericArgument(ctx.genericArgument());
+ if (value instanceof Traversal) {
+ if (GValue.valueInstanceOf(literalOrVar, String.class)) {
+ return graphTraversal.has(((GValue<String>) literalOrVar).get(), key, (Traversal<?, ?>) value);
+ } else {
+ return graphTraversal.has((String) literalOrVar, key, (Traversal<?, ?>) value);
+ }
+ }
if (GValue.valueInstanceOf(literalOrVar, String.class)) {
- return graphTraversal.has((GValue) literalOrVar,
- antlr.genericVisitor.parseString(ctx.stringNullableLiteral()),
- antlr.argumentVisitor.visitGenericArgument(ctx.genericArgument()));
+ return graphTraversal.has((GValue) literalOrVar, key, value);
} else {
- return graphTraversal.has((String) literalOrVar,
- antlr.genericVisitor.parseString(ctx.stringNullableLiteral()),
- antlr.argumentVisitor.visitGenericArgument(ctx.genericArgument()));
+ return graphTraversal.has((String) literalOrVar, key, value);
}
}
@@ -872,8 +903,12 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal>
*/
@Override
public GraphTraversal visitTraversalMethod_has_T_Object(final GremlinParser.TraversalMethod_has_T_ObjectContext ctx) {
- return graphTraversal.has(TraversalEnumParser.parseTraversalEnumFromContext(T.class, ctx.traversalT()),
- antlr.argumentVisitor.visitGenericArgument(ctx.genericArgument()));
+ final T accessor = TraversalEnumParser.parseTraversalEnumFromContext(T.class, ctx.traversalT());
+ final Object value = antlr.argumentVisitor.visitGenericArgument(ctx.genericArgument());
+ if (value instanceof Traversal) {
+ return graphTraversal.has(accessor, (Traversal<?, ?>) value);
+ }
+ return graphTraversal.has(accessor, value);
}
/**
@@ -885,6 +920,41 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal>
antlr.traversalPredicateVisitor.visitTraversalPredicate(ctx.traversalPredicate()));
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public GraphTraversal visitTraversalMethod_has_String_Traversal(final GremlinParser.TraversalMethod_has_String_TraversalContext ctx) {
+ final String key = antlr.genericVisitor.parseString(ctx.stringNullableLiteral());
+ final Traversal.Admin<?, ?> traversal = (Traversal.Admin<?, ?>) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal());
+ return this.graphTraversal.has(key, (Traversal<?, ?>) traversal);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public GraphTraversal visitTraversalMethod_has_String_String_Traversal(final GremlinParser.TraversalMethod_has_String_String_TraversalContext ctx) {
+ final Object literalOrVar = antlr.argumentVisitor.visitStringNullableArgument(ctx.stringNullableArgument());
+ final String key = antlr.genericVisitor.parseString(ctx.stringNullableLiteral());
+ final Traversal.Admin<?, ?> traversal = (Traversal.Admin<?, ?>) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal());
+ if (GValue.valueInstanceOf(literalOrVar, String.class)) {
+ return this.graphTraversal.has(((GValue<String>) literalOrVar).get(), key, (Traversal<?, ?>) traversal);
+ } else {
+ return this.graphTraversal.has((String) literalOrVar, key, (Traversal<?, ?>) traversal);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public GraphTraversal visitTraversalMethod_has_T_Traversal(final GremlinParser.TraversalMethod_has_T_TraversalContext ctx) {
+ final T accessor = TraversalEnumParser.parseTraversalEnumFromContext(T.class, ctx.traversalT());
+ final Traversal.Admin<?, ?> traversal = (Traversal.Admin<?, ?>) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal());
+ return this.graphTraversal.has(accessor, (Traversal<?, ?>) traversal);
+ }
+
/**
* {@inheritDoc}
*/
@@ -1432,6 +1502,36 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal>
return graphTraversal.property(antlr.argumentVisitor.parseMap(ctx.genericMapNullableArgument()));
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public GraphTraversal visitTraversalMethod_property_Cardinality_Object_Traversal(final GremlinParser.TraversalMethod_property_Cardinality_Object_TraversalContext ctx) {
+ return graphTraversal.property(
+ TraversalEnumParser.parseTraversalEnumFromContext(Cardinality.class, ctx.traversalCardinality()),
+ antlr.genericVisitor.visitGenericLiteral(ctx.genericLiteral()),
+ antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal()));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public GraphTraversal visitTraversalMethod_property_Object_Traversal(final GremlinParser.TraversalMethod_property_Object_TraversalContext ctx) {
+ return graphTraversal.property(
+ antlr.genericVisitor.visitGenericLiteral(ctx.genericLiteral()),
+ antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal()));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public GraphTraversal visitTraversalMethod_property_Traversal(final GremlinParser.TraversalMethod_property_TraversalContext ctx) {
+ final Traversal<?, ?> traversal = (Traversal<?, ?>) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal());
+ return this.graphTraversal.property(traversal);
+ }
+
/**
* {@inheritDoc}
*/
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalPredicateVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalPredicateVisitor.java
index 19a5ab4f29..c504c2e76d 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalPredicateVisitor.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalPredicateVisitor.java
@@ -22,6 +22,7 @@ import org.antlr.v4.runtime.tree.ParseTree;
import org.apache.tinkerpop.gremlin.process.traversal.GType;
import org.apache.tinkerpop.gremlin.process.traversal.P;
import org.apache.tinkerpop.gremlin.process.traversal.TextP;
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import java.util.Collection;
@@ -67,6 +68,9 @@ public class TraversalPredicateVisitor extends DefaultGremlinBaseVisitor<P> {
*/
@Override
public P visitTraversalPredicate_eq(final GremlinParser.TraversalPredicate_eqContext ctx) {
+ if (ctx.nestedTraversal() != null) {
+ return P.eq((Traversal.Admin<?, ?>) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal()));
+ }
return P.eq(getSingleGenericLiteralArgument(ctx));
}
@@ -75,6 +79,9 @@ public class TraversalPredicateVisitor extends DefaultGremlinBaseVisitor<P> {
*/
@Override
public P visitTraversalPredicate_neq(final GremlinParser.TraversalPredicate_neqContext ctx) {
+ if (ctx.nestedTraversal() != null) {
+ return P.neq((Traversal.Admin<?, ?>) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal()));
+ }
return P.neq(getSingleGenericLiteralArgument(ctx));
}
@@ -97,6 +104,9 @@ public class TraversalPredicateVisitor extends DefaultGremlinBaseVisitor<P> {
*/
@Override
public P visitTraversalPredicate_lt(final GremlinParser.TraversalPredicate_ltContext ctx) {
+ if (ctx.nestedTraversal() != null) {
+ return P.lt((Traversal.Admin<?, ?>) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal()));
+ }
return P.lt(getSingleGenericLiteralArgument(ctx));
}
@@ -105,6 +115,9 @@ public class TraversalPredicateVisitor extends DefaultGremlinBaseVisitor<P> {
*/
@Override
public P visitTraversalPredicate_lte(final GremlinParser.TraversalPredicate_lteContext ctx) {
+ if (ctx.nestedTraversal() != null) {
+ return P.lte((Traversal.Admin<?, ?>) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal()));
+ }
return P.lte(getSingleGenericLiteralArgument(ctx));
}
@@ -113,6 +126,9 @@ public class TraversalPredicateVisitor extends DefaultGremlinBaseVisitor<P> {
*/
@Override
public P visitTraversalPredicate_gt(final GremlinParser.TraversalPredicate_gtContext ctx) {
+ if (ctx.nestedTraversal() != null) {
+ return P.gt((Traversal.Admin<?, ?>) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal()));
+ }
return P.gt(getSingleGenericLiteralArgument(ctx));
}
@@ -121,6 +137,9 @@ public class TraversalPredicateVisitor extends DefaultGremlinBaseVisitor<P> {
*/
@Override
public P visitTraversalPredicate_gte(final GremlinParser.TraversalPredicate_gteContext ctx) {
+ if (ctx.nestedTraversal() != null) {
+ return P.gte((Traversal.Admin<?, ?>) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal()));
+ }
return P.gte(getSingleGenericLiteralArgument(ctx));
}
@@ -129,6 +148,11 @@ public class TraversalPredicateVisitor extends DefaultGremlinBaseVisitor<P> {
*/
@Override
public P visitTraversalPredicate_inside(final GremlinParser.TraversalPredicate_insideContext ctx) {
+ if (!ctx.nestedTraversal().isEmpty()) {
+ final Traversal.Admin<?, ?> first = (Traversal.Admin<?, ?>) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal(0));
+ final Traversal.Admin<?, ?> second = (Traversal.Admin<?, ?>) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal(1));
+ return P.gt(first).and(P.lt(second));
+ }
final Object[] arguments = getDoubleGenericLiteralArgument(ctx);
return P.inside(arguments[0], arguments[1]);
}
@@ -138,6 +162,11 @@ public class TraversalPredicateVisitor extends DefaultGremlinBaseVisitor<P> {
*/
@Override
public P visitTraversalPredicate_outside(final GremlinParser.TraversalPredicate_outsideContext ctx) {
+ if (!ctx.nestedTraversal().isEmpty()) {
+ final Traversal.Admin<?, ?> first = (Traversal.Admin<?, ?>) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal(0));
+ final Traversal.Admin<?, ?> second = (Traversal.Admin<?, ?>) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal(1));
+ return P.lt(first).or(P.gt(second));
+ }
final Object[] arguments = getDoubleGenericLiteralArgument(ctx);
return P.outside(arguments[0], arguments[1]);
}
@@ -147,6 +176,11 @@ public class TraversalPredicateVisitor extends DefaultGremlinBaseVisitor<P> {
*/
@Override
public P visitTraversalPredicate_between(final GremlinParser.TraversalPredicate_betweenContext ctx) {
+ if (!ctx.nestedTraversal().isEmpty()) {
+ final Traversal.Admin<?, ?> first = (Traversal.Admin<?, ?>) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal(0));
+ final Traversal.Admin<?, ?> second = (Traversal.Admin<?, ?>) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal(1));
+ return P.gte(first).and(P.lt(second));
+ }
final Object[] arguments = getDoubleGenericLiteralArgument(ctx);
return P.between(arguments[0], arguments[1]);
}
@@ -156,6 +190,10 @@ public class TraversalPredicateVisitor extends DefaultGremlinBaseVisitor<P> {
*/
@Override
public P visitTraversalPredicate_within(final GremlinParser.TraversalPredicate_withinContext ctx) {
+ if (ctx.nestedTraversal() != null) {
+ return P.within((Traversal.Admin<?, ?>) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal()));
+ }
+
// called with no args which is valid for java/groovy
if (null == ctx.genericArgumentVarargs()) return P.within();
@@ -175,6 +213,10 @@ public class TraversalPredicateVisitor extends DefaultGremlinBaseVisitor<P> {
*/
@Override
public P visitTraversalPredicate_without(final GremlinParser.TraversalPredicate_withoutContext ctx) {
+ if (ctx.nestedTraversal() != null) {
+ return P.without((Traversal.Admin<?, ?>) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal()));
+ }
+
// called with no args which is valid for java/groovy
if (null == ctx.genericArgumentVarargs()) return P.without();
@@ -199,31 +241,49 @@ public class TraversalPredicateVisitor extends DefaultGremlinBaseVisitor<P> {
@Override
public P visitTraversalPredicate_containing(final GremlinParser.TraversalPredicate_containingContext ctx) {
+ if (ctx.nestedTraversal() != null) {
+ return TextP.containing((Traversal.Admin<?, ?>) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal()));
+ }
return TextP.containing((String) antlr.argumentVisitor.visitStringArgument(ctx.stringArgument()));
}
@Override
public P visitTraversalPredicate_notContaining(final GremlinParser.TraversalPredicate_notContainingContext ctx) {
+ if (ctx.nestedTraversal() != null) {
+ return TextP.notContaining((Traversal.Admin<?, ?>) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal()));
+ }
return TextP.notContaining((String) antlr.argumentVisitor.visitStringArgument(ctx.stringArgument()));
}
@Override
public P visitTraversalPredicate_notEndingWith(final GremlinParser.TraversalPredicate_notEndingWithContext ctx) {
+ if (ctx.nestedTraversal() != null) {
+ return TextP.notEndingWith((Traversal.Admin<?, ?>) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal()));
+ }
return TextP.notEndingWith((String) antlr.argumentVisitor.visitStringArgument(ctx.stringArgument()));
}
@Override
public P visitTraversalPredicate_endingWith(final GremlinParser.TraversalPredicate_endingWithContext ctx) {
+ if (ctx.nestedTraversal() != null) {
+ return TextP.endingWith((Traversal.Admin<?, ?>) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal()));
+ }
return TextP.endingWith((String) antlr.argumentVisitor.visitStringArgument(ctx.stringArgument()));
}
@Override
public P visitTraversalPredicate_startingWith(final GremlinParser.TraversalPredicate_startingWithContext ctx) {
+ if (ctx.nestedTraversal() != null) {
+ return TextP.startingWith((Traversal.Admin<?, ?>) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal()));
+ }
return TextP.startingWith((String) antlr.argumentVisitor.visitStringArgument(ctx.stringArgument()));
}
@Override
public P visitTraversalPredicate_notStartingWith(final GremlinParser.TraversalPredicate_notStartingWithContext ctx) {
+ if (ctx.nestedTraversal() != null) {
+ return TextP.notStartingWith((Traversal.Admin<?, ?>) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal()));
+ }
return TextP.notStartingWith((String) antlr.argumentVisitor.visitStringArgument(ctx.stringArgument()));
}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalSourceSpawnMethodVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalSourceSpawnMethodVisitor.java
index a57f9cf40b..bed196c29e 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalSourceSpawnMethodVisitor.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalSourceSpawnMethodVisitor.java
@@ -19,9 +19,14 @@
package org.apache.tinkerpop.gremlin.language.grammar;
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.GraphTraversal;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.GraphStep;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+
import java.util.Map;
/**
@@ -94,7 +99,14 @@ public class TraversalSourceSpawnMethodVisitor extends DefaultGremlinBaseVisitor
*/
@Override
public GraphTraversal visitTraversalSourceSpawnMethod_E(final GremlinParser.TraversalSourceSpawnMethod_EContext ctx) {
- return this.traversalSource.E(antlr.argumentVisitor.parseObjectVarargs(ctx.genericArgumentVarargs()));
+ if (ctx.nestedTraversal() != null) {
+ return this.traversalSource.E((Traversal<?, ?>) anonymousVisitor.visitNestedTraversal(ctx.nestedTraversal()));
+ }
+ final Object[] args = antlr.argumentVisitor.parseObjectVarargs(ctx.genericArgumentVarargs());
+ if (args.length == 1 && args[0] instanceof Traversal) {
+ return this.traversalSource.E((Traversal<?, ?>) args[0]);
+ }
+ return this.traversalSource.E(args);
}
/**
@@ -102,7 +114,14 @@ public class TraversalSourceSpawnMethodVisitor extends DefaultGremlinBaseVisitor
*/
@Override
public GraphTraversal visitTraversalSourceSpawnMethod_V(final GremlinParser.TraversalSourceSpawnMethod_VContext ctx) {
- return this.traversalSource.V(antlr.argumentVisitor.parseObjectVarargs(ctx.genericArgumentVarargs()));
+ if (ctx.nestedTraversal() != null) {
+ return this.traversalSource.V((Traversal<?, ?>) anonymousVisitor.visitNestedTraversal(ctx.nestedTraversal()));
+ }
+ final Object[] args = antlr.argumentVisitor.parseObjectVarargs(ctx.genericArgumentVarargs());
+ if (args.length == 1 && args[0] instanceof Traversal) {
+ return this.traversalSource.V((Traversal<?, ?>) args[0]);
+ }
+ return this.traversalSource.V(args);
}
/**
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/GremlinLang.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/GremlinLang.java
index 08f124015c..5fd67b617e 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/GremlinLang.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/GremlinLang.java
@@ -287,7 +287,11 @@ public class GremlinLang implements Cloneable, Serializable {
final StringBuilder sb = new StringBuilder();
if (p instanceof TextP) {
sb.append("TextP.").append(p.getPredicateName()).append("(");
- sb.append(argAsString(p.getValue()));
+ if (p.hasTraversal()) {
+ sb.append(argAsString(p.getTraversalValue()));
+ } else {
+ sb.append(argAsString(p.getValue()));
+ }
} else if (p instanceof ConnectiveP) {
// ConnectiveP gets some special handling because it's reduced to and(P, P, P) and we want it
// generated the way it was written which was P.and(P).and(P)
@@ -307,6 +311,10 @@ public class GremlinLang implements Cloneable, Serializable {
} else if (p instanceof NotP) {
sb.append("P.not(");
sb.append(argAsString(p.negate())); // Wrap internal P in `P.not(%s)`
+ } else if (p.hasTraversal()) {
+ // Traversal-bearing predicate: serialize as P.op(traversalGremlinLang)
+ sb.append("P.").append(p.getPredicateName()).append("(");
+ sb.append(argAsString(p.getTraversalValue()));
} else {
sb.append("P.").append(p.getPredicateName()).append("(");
sb.append(argAsString(p.getValue()));
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/NotP.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/NotP.java
index f77f0f5974..50ea9c4be8 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/NotP.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/NotP.java
@@ -70,6 +70,22 @@ public class NotP<V> extends P<V> {
return new NotP<>(this.originalP.clone());
}
+ @Override
+ public boolean hasTraversal() {
+ return super.hasTraversal() || this.originalP.hasTraversal();
+ }
+
+ @Override
+ public boolean isResolvedEmpty() {
+ return this.originalP.isResolvedEmpty();
+ }
+
+ @Override
+ public void resolve(final Traverser.Admin<?> traverser) {
+ super.resolve(traverser);
+ this.originalP.resolve(traverser);
+ }
+
/**
* A NotPBiPredicate wraps a PBiPredicate and represents its negation.
*/
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java
index afc41b5681..4c05bc0135 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java
@@ -20,8 +20,10 @@ package org.apache.tinkerpop.gremlin.process.traversal;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
+import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.BulkSet;
import org.apache.tinkerpop.gremlin.process.traversal.util.AndP;
+import org.apache.tinkerpop.gremlin.process.traversal.util.ConnectiveP;
import org.apache.tinkerpop.gremlin.process.traversal.util.OrP;
import java.io.Serializable;
@@ -31,7 +33,10 @@ import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Predicate;
@@ -49,10 +54,22 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
protected Map<String, V> variables = new HashMap<>();
protected Collection<V> literals = Collections.EMPTY_LIST;
private boolean isCollection = false;
+ private boolean resolvedEmpty = false;
+ private Traversal.Admin<?, ?> traversalValue;
public P(final PBiPredicate<V, V> biPredicate, final V value) {
- setValue(value);
this.biPredicate = biPredicate;
+ // If the value is a DefaultGraphTraversal (the type created by __.xxx() anonymous traversals),
+ // treat it as a child traversal rather than a literal. This handles the case where Java's
+ // overload resolution picks P(BiPredicate, V) instead of P(BiPredicate, Traversal) when
+ // the caller passes a GraphTraversal. We specifically check for DefaultGraphTraversal
+ // rather than Traversal to avoid catching internal traversal types like ConstantTraversal,
+ // ValueTraversal, and IdentityTraversal which are used as literal values in P.
+ if (value instanceof org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.DefaultGraphTraversal) {
+ this.traversalValue = ((Traversal<?, ?>) value).asAdmin();
+ } else {
+ setValue(value);
+ }
}
public P(final PBiPredicate<V, V> biPredicate, final GValue<V> value) {
@@ -81,6 +98,16 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
this.isCollection = isCollection;
}
+ /**
+ * Constructs a {@code P} with a child traversal whose result is resolved at runtime against the current
+ * traverser. The literals and variables are left at their defaults and will be populated when
+ * {@link #resolve(Traverser.Admin)} is called.
+ */
+ public P(final PBiPredicate<V, V> biPredicate, final Traversal.Admin<?, ?> traversalValue) {
+ this.biPredicate = biPredicate;
+ this.traversalValue = traversalValue;
+ }
+
public PBiPredicate<V, V> getBiPredicate() {
return this.biPredicate;
}
@@ -162,6 +189,8 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
result ^= this.variables.hashCode();
if (null != this.literals)
result ^= this.literals.hashCode();
+ if (null != this.traversalValue)
+ result ^= this.traversalValue.hashCode();
return result;
}
@@ -171,7 +200,8 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
((P) other).getClass().equals(this.getClass()) &&
((P) other).getBiPredicate().equals(this.biPredicate) &&
((((P) other).variables == null && this.variables == null) || (((P) other).variables != null && ((P) other).variables.equals(this.variables))) &&
- ((((P) other).literals == null && this.literals == null) || (((P) other).literals != null && CollectionUtils.isEqualCollection(((P) other).literals, this.literals)));
+ ((((P) other).literals == null && this.literals == null) || (((P) other).literals != null && CollectionUtils.isEqualCollection(((P) other).literals, this.literals))) &&
+ Objects.equals(((P) other).traversalValue, this.traversalValue);
}
@Override
@@ -200,7 +230,11 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
public P<V> clone() {
try {
- return (P<V>) super.clone();
+ final P<V> clone = (P<V>) super.clone();
+ if (this.traversalValue != null) {
+ clone.traversalValue = this.traversalValue.clone();
+ }
+ return clone;
} catch (final CloneNotSupportedException e) {
throw new IllegalStateException(e.getMessage(), e);
}
@@ -224,6 +258,111 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
return results;
}
+ /**
+ * Determines if this predicate holds a child traversal whose result is resolved at runtime.
+ */
+ public boolean hasTraversal() {
+ return this.traversalValue != null;
+ }
+
+ /**
+ * Returns {@code true} if the most recent call to {@link #resolve(Traverser.Admin)} produced no results.
+ * Steps should check this after calling {@code resolve()} and short-circuit appropriately rather than
+ * calling {@link #test(Object)}, which would compare against {@code null}.
+ */
+ public boolean isResolvedEmpty() {
+ return this.resolvedEmpty;
+ }
+
+ /**
+ * Gets the child traversal value, if one was provided. Returns {@code null} when this predicate uses
+ * literal values or variables.
+ */
+ public Traversal.Admin<?, ?> getTraversalValue() {
+ return this.traversalValue;
+ }
+
+ /**
+ * Resolves the child traversal against the given traverser, replacing the traversal value with the
+ * resolved literal(s) for this test cycle. If no traversal is present, this method returns immediately.
+ *
+ * <p>For collection predicates ({@link Contains}), all results are collected into the literals
+ * collection. For all other predicates ({@link Compare}, {@link Text}, etc.), the traversal must
+ * produce exactly one result or an {@link IllegalArgumentException} is thrown.</p>
+ */
+ @SuppressWarnings("unchecked")
+ public void resolve(final Traverser.Admin<?> traverser) {
+ if (this.traversalValue == null) return;
+
+ // Use prepare + iteration directly to avoid ambiguous overload resolution of applyAll
+ // when S=Object (Traverser.Admin<Object> matches both the Traverser.Admin<S> and S overloads).
+ final Traversal.Admin<Object, Object> trav = (Traversal.Admin<Object, Object>) (Traversal.Admin) this.traversalValue;
+ final Traverser.Admin<Object> split = (Traverser.Admin<Object>) traverser.split();
+ split.setSideEffects(trav.getSideEffects());
+ split.setBulk(1L);
+ trav.reset();
+ trav.addStart(split);
+
+ final List<Object> results = new ArrayList<>();
+ while (trav.hasNext()) {
+ results.add(trav.next());
+ }
+
+ this.resolvedEmpty = results.isEmpty();
+
+ if (results.isEmpty()) {
+ this.literals = Collections.emptyList();
+ this.isCollection = false;
+ } else if (this.biPredicate instanceof Contains) {
+ // Collection predicates (within, without) accept multiple results
+ this.literals = (Collection<V>) (Collection<?>) results;
+ this.isCollection = true;
+ } else {
+ // Single-value predicates (Compare, Text, etc.) require exactly one result
+ if (results.size() > 1) {
+ throw new IllegalArgumentException(
+ "Predicate " + this.biPredicate.getPredicateName() +
+ " requires exactly one value but traversal produced " + results.size());
+ }
+ this.literals = Collections.singleton((V) results.get(0));
+ this.isCollection = false;
+ }
+ }
+
+ //////////////// predicate traversal utilities
+
+ /**
+ * Recursively integrates all child traversals found in the predicate tree into the given parent step.
+ * Handles {@link ConnectiveP} (recurses into children) and {@link NotP} (recurses into wrapped predicate).
+ */
+ public static void integrateTraversals(final P<?> p, final TraversalParent parent) {
+ if (p instanceof ConnectiveP) {
+ for (final P<?> child : ((ConnectiveP<?>) p).getPredicates()) {
+ integrateTraversals(child, parent);
+ }
+ } else if (p instanceof NotP) {
+ integrateTraversals(((NotP<?>) p).negate(), parent);
+ } else if (p.getTraversalValue() != null) {
+ parent.integrateChild(p.getTraversalValue());
+ }
+ }
+
+ /**
+ * Recursively collects all child traversals from a predicate tree.
+ * Handles {@link ConnectiveP} (recurses into children) and {@link NotP} (recurses into wrapped predicate).
+ */
+ public static void collectTraversals(final P<?> p, final List<Traversal.Admin<?, ?>> traversals) {
+ if (p instanceof ConnectiveP) {
+ for (final P<?> child : ((ConnectiveP<?>) p).getPredicates()) {
+ collectTraversals(child, traversals);
+ }
+ } else if (p instanceof NotP) {
+ collectTraversals(((NotP<?>) p).negate(), traversals);
+ } else if (p.getTraversalValue() != null) {
+ traversals.add(p.getTraversalValue());
+ }
+ }
+
//////////////// statics
/**
@@ -394,6 +533,12 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
* @since 3.0.0-incubating
*/
public static <V> P<V> within(final V... values) {
+ // If a single Traversal is passed, redirect to the Traversal-accepting overload.
+ // This handles cases where Java's overload resolution picks the varargs method
+ // instead of the Traversal-specific method.
+ if (values != null && values.length == 1 && values[0] instanceof Traversal) {
+ return P.within((Traversal<?, ?>) values[0]);
+ }
final V[] v = null == values ? (V[]) new Object[] { null } : (V[]) values;
return P.within(Arrays.asList(v));
}
@@ -427,6 +572,10 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
* @since 3.0.0-incubating
*/
public static <V> P<V> without(final V... values) {
+ // If a single Traversal is passed, redirect to the Traversal-accepting overload.
+ if (values != null && values.length == 1 && values[0] instanceof Traversal) {
+ return P.without((Traversal<?, ?>) values[0]);
+ }
final V[] v = null == values ? (V[]) new Object[] { null } : values;
return P.without(Arrays.asList(v));
}
@@ -453,6 +602,78 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
return new P(Contains.without, value);
}
+ /**
+ * Determines if values are equal using a child traversal resolved at runtime.
+ *
+ * @since 4.0.0
+ */
+ public static <V> P<V> eq(final Traversal<?, ?> traversalValue) {
+ return new P(Compare.eq, traversalValue.asAdmin());
+ }
+
+ /**
+ * Determines if values are not equal using a child traversal resolved at runtime.
+ *
+ * @since 4.0.0
+ */
+ public static <V> P<V> neq(final Traversal<?, ?> traversalValue) {
+ return new P(Compare.neq, traversalValue.asAdmin());
+ }
+
+ /**
+ * Determines if a value is less than another using a child traversal resolved at runtime.
+ *
+ * @since 4.0.0
+ */
+ public static <V> P<V> lt(final Traversal<?, ?> traversalValue) {
+ return new P(Compare.lt, traversalValue.asAdmin());
+ }
+
+ /**
+ * Determines if a value is less than or equal to another using a child traversal resolved at runtime.
+ *
+ * @since 4.0.0
+ */
+ public static <V> P<V> lte(final Traversal<?, ?> traversalValue) {
+ return new P(Compare.lte, traversalValue.asAdmin());
+ }
+
+ /**
+ * Determines if a value is greater than another using a child traversal resolved at runtime.
+ *
+ * @since 4.0.0
+ */
+ public static <V> P<V> gt(final Traversal<?, ?> traversalValue) {
+ return new P(Compare.gt, traversalValue.asAdmin());
+ }
+
+ /**
+ * Determines if a value is greater than or equal to another using a child traversal resolved at runtime.
+ *
+ * @since 4.0.0
+ */
+ public static <V> P<V> gte(final Traversal<?, ?> traversalValue) {
+ return new P(Compare.gte, traversalValue.asAdmin());
+ }
+
+ /**
+ * Determines if a value is within the results of a child traversal resolved at runtime.
+ *
+ * @since 4.0.0
+ */
+ public static <V> P<V> within(final Traversal<?, ?> traversalValue) {
+ return new P(Contains.within, traversalValue.asAdmin());
+ }
+
+ /**
+ * Determines if a value is not within the results of a child traversal resolved at runtime.
+ *
+ * @since 4.0.0
+ */
+ public static <V> P<V> without(final Traversal<?, ?> traversalValue) {
+ return new P(Contains.without, traversalValue.asAdmin());
+ }
+
/**
* Determines if a value is of a type denoted by {@code GType}.
*
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TextP.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TextP.java
index d1d8c21019..8ec80a7c62 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TextP.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TextP.java
@@ -38,6 +38,16 @@ public class TextP extends P<String> {
super(biPredicate, value);
}
+ /**
+ * Constructs a {@code TextP} with a child traversal whose result is resolved at runtime against the
+ * current traverser. The traversal must produce a {@code String} result.
+ *
+ * @since 4.0.0
+ */
+ public TextP(final PBiPredicate<String, String> biPredicate, final Traversal.Admin<?, ?> traversalValue) {
+ super(biPredicate, traversalValue);
+ }
+
protected TextP(final PBiPredicate<String, String> biPredicate, final Collection<String> literals, final Map<String, String> variables) {
super(biPredicate, literals, variables, false);
}
@@ -76,6 +86,15 @@ public class TextP extends P<String> {
return new TextP(Text.startingWith, value);
}
+ /**
+ * Determines if String does start with the value resolved from a child traversal at runtime.
+ *
+ * @since 4.0.0
+ */
+ public static TextP startingWith(final Traversal<?, ?> traversalValue) {
+ return new TextP(Text.startingWith, traversalValue.asAdmin());
+ }
+
/**
* Determines if String does not start with the given value.
*
@@ -95,7 +114,16 @@ public class TextP extends P<String> {
}
/**
- * Determines if String does start with the given value.
+ * Determines if String does not start with the value resolved from a child traversal at runtime.
+ *
+ * @since 4.0.0
+ */
+ public static TextP notStartingWith(final Traversal<?, ?> traversalValue) {
+ return new TextP(Text.notStartingWith, traversalValue.asAdmin());
+ }
+
+ /**
+ * Determines if String does end with the given value.
*
* @since 3.4.0
*/
@@ -104,7 +132,7 @@ public class TextP extends P<String> {
}
/**
- * Determines if String does start with the given value.
+ * Determines if String does end with the given value.
*
* @since 3.8.0
*/
@@ -113,7 +141,16 @@ public class TextP extends P<String> {
}
/**
- * Determines if String does not start with the given value.
+ * Determines if String does end with the value resolved from a child traversal at runtime.
+ *
+ * @since 4.0.0
+ */
+ public static TextP endingWith(final Traversal<?, ?> traversalValue) {
+ return new TextP(Text.endingWith, traversalValue.asAdmin());
+ }
+
+ /**
+ * Determines if String does not end with the given value.
*
* @since 3.4.0
*/
@@ -122,7 +159,7 @@ public class TextP extends P<String> {
}
/**
- * Determines if String does not start with the given value.
+ * Determines if String does not end with the given value.
*
* @since 3.8.0
*/
@@ -130,6 +167,15 @@ public class TextP extends P<String> {
return new TextP(Text.notEndingWith, value);
}
+ /**
+ * Determines if String does not end with the value resolved from a child traversal at runtime.
+ *
+ * @since 4.0.0
+ */
+ public static TextP notEndingWith(final Traversal<?, ?> traversalValue) {
+ return new TextP(Text.notEndingWith, traversalValue.asAdmin());
+ }
+
/**
* Determines if String does contain the given value.
*
@@ -148,6 +194,15 @@ public class TextP extends P<String> {
return new TextP(Text.containing, value);
}
+ /**
+ * Determines if String does contain the value resolved from a child traversal at runtime.
+ *
+ * @since 4.0.0
+ */
+ public static TextP containing(final Traversal<?, ?> traversalValue) {
+ return new TextP(Text.containing, traversalValue.asAdmin());
+ }
+
/**
* Determines if String does not contain the given value.
*
@@ -165,6 +220,15 @@ public class TextP extends P<String> {
public static TextP notContaining(final GValue<String> value) {
return new TextP(Text.notContaining, value);
}
+
+ /**
+ * Determines if String does not contain the value resolved from a child traversal at runtime.
+ *
+ * @since 4.0.0
+ */
+ public static TextP notContaining(final Traversal<?, ?> traversalValue) {
+ return new TextP(Text.notContaining, traversalValue.asAdmin());
+ }
/**
* Determines if String has a match with the given regex pattern. The TinkerPop reference implementation uses
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
index c42859f7a5..97129c4ba0 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
@@ -414,6 +414,22 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
return this.asAdmin().addStep(step);
}
+ /**
+ * A {@code V} step that accepts a child traversal whose results are used as vertex IDs for lookup.
+ * This form is only valid as a mid-traversal step; using it as a start step will throw an
+ * {@link IllegalStateException} at runtime because there is no traverser context to evaluate the child traversal.
+ *
+ * @param traversal the child traversal that produces vertex IDs
+ * @return the traversal with an appended {@link GraphStep}
+ * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#graph-step" target="_blank">Reference Documentation - Graph Step</a>
+ * @since 4.0.0
+ */
+ public default GraphTraversal<S, Vertex> V(final Traversal<?, ?> traversal) {
+ if (null == traversal) return V(new Object[]{ null });
+ this.asAdmin().getGremlinLang().addStep(Symbols.V, traversal);
+ return this.asAdmin().addStep(new GraphStep<>(this.asAdmin(), Vertex.class, false, traversal.asAdmin()));
+ }
+
/**
* A {@code E} step is usually used to start a traversal but it may also be used mid-traversal.
*
@@ -437,6 +453,22 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
return this.asAdmin().addStep(step);
}
+ /**
+ * A {@code E} step that accepts a child traversal whose results are used as edge IDs for lookup.
+ * This form is only valid as a mid-traversal step; using it as a start step will throw an
+ * {@link IllegalStateException} at runtime because there is no traverser context to evaluate the child traversal.
+ *
+ * @param traversal the child traversal that produces edge IDs
+ * @return the traversal with an appended {@link GraphStep}
+ * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#e-step" target="_blank">Reference Documentation - E Step</a>
+ * @since 4.0.0
+ */
+ public default GraphTraversal<S, Edge> E(final Traversal<?, ?> traversal) {
+ if (null == traversal) return E(new Object[]{ null });
+ this.asAdmin().getGremlinLang().addStep(Symbols.E, traversal);
+ return this.asAdmin().addStep(new GraphStep<>(this.asAdmin(), Edge.class, false, traversal.asAdmin()));
+ }
+
/**
* Map the {@link Vertex} to its adjacent vertices given a direction.
*
@@ -2670,6 +2702,45 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
}
}
+ /**
+ * Filters vertices, edges and vertex properties based on their properties using a child traversal
+ * whose results are resolved at runtime against the current traverser. The resolved results are used
+ * with {@code P.within()} semantics for comparison against the named property.
+ *
+ * @param propertyKey the key of the property to filter on
+ * @param traversal the child traversal whose results are used as the filter value
+ * @return the traversal with an appended {@link HasStep}
+ * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#has-step" target="_blank">Reference Documentation - Has Step</a>
+ * @since 4.0.0
+ */
+ public default GraphTraversal<S, E> has(final String propertyKey, final Traversal<?, ?> traversal) {
+ if (null == traversal) return has(propertyKey, (Object) null);
+ this.asAdmin().getGremlinLang().addStep(Symbols.has, propertyKey, traversal);
+ final HasContainer hasContainer = new HasContainer(propertyKey, traversal.asAdmin());
+ return this.asAdmin().addStep(new HasStep(this.asAdmin(), hasContainer));
+ }
+
+ /**
+ * Filters vertices, edges and vertex properties based on their properties using a child traversal
+ * whose results are resolved at runtime against the current traverser. The resolved results are used
+ * with {@code P.within()} semantics for comparison against the T-accessor value (id or label).
+ *
+ * @param accessor the {@link T} accessor of the property to filter on
+ * @param traversal the child traversal whose results are used as the filter value
+ * @return the traversal with an appended {@link HasStep}
+ * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#has-step" target="_blank">Reference Documentation - Has Step</a>
+ * @since 4.0.0
+ */
+ public default GraphTraversal<S, E> has(final T accessor, final Traversal<?, ?> traversal) {
+ if (null == accessor)
+ throw new IllegalArgumentException("The T accessor value of has(T,Traversal) cannot be null");
+ if (null == traversal) return has(accessor, (Object) null);
+
+ this.asAdmin().getGremlinLang().addStep(Symbols.has, accessor, traversal);
+ final HasContainer hasContainer = new HasContainer(accessor.getAccessor(), traversal.asAdmin());
+ return this.asAdmin().addStep(new HasStep(this.asAdmin(), hasContainer));
+ }
+
/**
* Filters vertices, edges and vertex properties based on their properties.
*
@@ -2702,6 +2773,26 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
return TraversalHelper.addHasContainer(this.asAdmin(), new HasContainer(propertyKey, value instanceof P ? (P) value : P.eq(value)));
}
+ /**
+ * Filters vertices, edges and vertex properties based on their label and a property value resolved
+ * from a child traversal at runtime. The label is matched first, then the child traversal results
+ * are used with {@code P.within()} semantics for comparison against the named property.
+ *
+ * @param label the label of the {@link Element}
+ * @param propertyKey the key of the property to filter on
+ * @param traversal the child traversal whose results are used as the filter value
+ * @return the traversal with an appended {@link HasStep}
+ * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#has-step" target="_blank">Reference Documentation - Has Step</a>
+ * @since 4.0.0
+ */
+ public default GraphTraversal<S, E> has(final String label, final String propertyKey, final Traversal<?, ?> traversal) {
+ if (null == traversal) return has(label, propertyKey, (Object) null);
+ this.asAdmin().getGremlinLang().addStep(Symbols.has, label, propertyKey, traversal);
+ TraversalHelper.addHasContainer(this.asAdmin(), new HasContainer(T.label.getAccessor(), P.eq(label)));
+ final HasContainer hasContainer = new HasContainer(propertyKey, traversal.asAdmin());
+ return this.asAdmin().addStep(new HasStep(this.asAdmin(), hasContainer));
+ }
+
/**
* Filters vertices, edges and vertex properties based on the existence of properties.
*
@@ -3022,7 +3113,14 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
*/
public default GraphTraversal<S, E> is(final Object value) {
this.asAdmin().getGremlinLang().addStep(Symbols.is, value);
- P<E> predicate = value instanceof P ? (P<E>) value : P.eq((E) value);
+ P<E> predicate;
+ if (value instanceof P) {
+ predicate = (P<E>) value;
+ } else if (value instanceof Traversal) {
+ predicate = (P<E>) P.eq(((Traversal<?, ?>) value).asAdmin());
+ } else {
+ predicate = P.eq((E) value);
+ }
return this.asAdmin().addStep(predicate.isParameterized() ? new IsStepPlaceholder<>(this.asAdmin(), predicate) : new IsStep<>(this.asAdmin(), predicate));
}
@@ -3825,6 +3923,24 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
}
return this;
}
+
+ /**
+ * Sets properties on the current element using a child traversal that produces a {@code Map}.
+ * Each entry in the resulting Map becomes a property (key → value) on the element. The traversal
+ * is evaluated at execution time against the current traverser.
+ *
+ * @param mapTraversal a traversal that produces a {@code Map<String, Object>} of property key/value pairs
+ * @return the traversal with the {@link AddPropertyStepPlaceholder} added
+ * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#addproperty-step" target="_blank">AddProperty Step</a>
+ * @since 4.0.0
+ */
+ public default GraphTraversal<S, E> property(final Traversal<?, ?> mapTraversal) {
+ if (null == mapTraversal) return this;
+ this.asAdmin().getGremlinLang().addStep(Symbols.property, mapTraversal);
+ this.asAdmin().addStep(new AddPropertyStepPlaceholder(this.asAdmin(), null, "~traversalMap", mapTraversal.asAdmin()));
+ return this;
+ }
+
///////////////////// BRANCH STEPS /////////////////////
/**
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 684d9e8609..78ab16e68e 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
@@ -537,6 +537,22 @@ public class GraphTraversalSource implements TraversalSource {
return traversal.addStep(step);
}
+ /**
+ * Spawns a {@link GraphTraversal} starting with vertices whose IDs are resolved from a child traversal.
+ * This form will throw an {@link IllegalStateException} at runtime because there is no traverser context
+ * available to evaluate the child traversal as a start step.
+ *
+ * @param traversal the child traversal that produces vertex IDs
+ * @since 4.0.0
+ */
+ public GraphTraversal<Vertex, Vertex> V(final Traversal<?, ?> traversal) {
+ if (null == traversal) return V(new Object[]{ null });
+ final GraphTraversalSource clone = this.clone();
+ clone.gremlinLang.addStep(GraphTraversal.Symbols.V, traversal);
+ final GraphTraversal.Admin<Vertex, Vertex> traversalAdmin = new DefaultGraphTraversal<>(clone);
+ return traversalAdmin.addStep(new GraphStep<>(traversalAdmin, Vertex.class, true, traversal.asAdmin()));
+ }
+
/**
* Spawns a {@link GraphTraversal} starting with all edges or some subset of edges as specified by their unique
* identifier.
@@ -558,6 +574,22 @@ public class GraphTraversalSource implements TraversalSource {
return traversal.addStep(step);
}
+ /**
+ * Spawns a {@link GraphTraversal} starting with edges whose IDs are resolved from a child traversal.
+ * This form will throw an {@link IllegalStateException} at runtime because there is no traverser context
+ * available to evaluate the child traversal as a start step.
+ *
+ * @param traversal the child traversal that produces edge IDs
+ * @since 4.0.0
+ */
+ public GraphTraversal<Edge, Edge> E(final Traversal<?, ?> traversal) {
+ if (null == traversal) return E(new Object[]{ null });
+ final GraphTraversalSource clone = this.clone();
+ clone.gremlinLang.addStep(GraphTraversal.Symbols.E, traversal);
+ final GraphTraversal.Admin<Edge, Edge> traversalAdmin = new DefaultGraphTraversal<>(clone);
+ return traversalAdmin.addStep(new GraphStep<>(traversalAdmin, Edge.class, true, traversal.asAdmin()));
+ }
+
/**
* Spawns a {@link GraphTraversal} starting with a list of available services.
*
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java
index 01986b4534..3dc2ed0651 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java
@@ -140,6 +140,13 @@ public class __ {
return __.<A>start().V(vertexIdsOrElements);
}
+ /**
+ * @see GraphTraversal#V(Traversal)
+ */
+ public static <A> GraphTraversal<A, Vertex> V(final Traversal<?, ?> traversal) {
+ return __.<A>start().V(traversal);
+ }
+
/**
* @see GraphTraversal#E(Object...)
*/
@@ -147,6 +154,13 @@ public class __ {
return __.<A>start().E(edgeIdsOrElements);
}
+ /**
+ * @see GraphTraversal#E(Traversal)
+ */
+ public static <A> GraphTraversal<A, Edge> E(final Traversal<?, ?> traversal) {
+ return __.<A>start().E(traversal);
+ }
+
/**
* @see GraphTraversal#to(Direction)
*/
@@ -1092,6 +1106,13 @@ public class __ {
return __.<A>start().has(propertyKey, predicate);
}
+ /**
+ * @see GraphTraversal#has(String, Traversal)
+ */
+ public static <A> GraphTraversal<A, A> has(final String propertyKey, final Traversal<?, ?> traversal) {
+ return __.<A>start().has(propertyKey, traversal);
+ }
+
/**
* @see GraphTraversal#has(T, P)
*/
@@ -1113,6 +1134,13 @@ public class __ {
return __.<A>start().has(accessor, value);
}
+ /**
+ * @see GraphTraversal#has(T, Traversal)
+ */
+ public static <A> GraphTraversal<A, A> has(final T accessor, final Traversal<?, ?> traversal) {
+ return __.<A>start().has(accessor, traversal);
+ }
+
/**
* @see GraphTraversal#has(String, String, Object)
*/
@@ -1142,6 +1170,13 @@ public class __ {
return __.<A>start().has(label, propertyKey, predicate);
}
+ /**
+ * @see GraphTraversal#has(String, String, Traversal)
+ */
+ public static <A> GraphTraversal<A, A> has(final String label, final String propertyKey, final Traversal<?, ?> traversal) {
+ return __.<A>start().has(label, propertyKey, traversal);
+ }
+
/**
* @see GraphTraversal#has(String)
*/
@@ -1558,6 +1593,13 @@ public class __ {
return __.<A>start().property(value);
}
+ /**
+ * @see GraphTraversal#property(Traversal)
+ */
+ public static <A> GraphTraversal<A, A> property(final Traversal<?, ?> mapTraversal) {
+ return __.<A>start().property(mapTraversal);
+ }
+
///////////////////// BRANCH STEPS /////////////////////
/**
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/HasContainerHolder.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/HasContainerHolder.java
index f016aa03f4..47343d3ea6 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/HasContainerHolder.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/HasContainerHolder.java
@@ -53,7 +53,7 @@ public interface HasContainerHolder<S, E> extends GValueHolder<S, E> {
}
public default Collection<P<?>> getPredicatesGValueSafe() {
- return getHasContainers().stream().map(p -> p.getPredicate()).collect(Collectors.toList());
+ return getHasContainers().stream().map(p -> p.getPredicate()).filter(p -> p != null).collect(Collectors.toList());
}
public default HasContainerHolder<S, E> asConcreteStep() {
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/AllStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/AllStep.java
index 64853f6614..ddabdfb798 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/AllStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/AllStep.java
@@ -21,15 +21,18 @@ package org.apache.tinkerpop.gremlin.process.traversal.step.filter;
import org.apache.tinkerpop.gremlin.process.traversal.P;
import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
+import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
-import java.util.EnumSet;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.Iterator;
+import java.util.List;
import java.util.Set;
-public final class AllStep<S, S2> extends FilterStep<S> {
+public final class AllStep<S, S2> extends FilterStep<S> implements TraversalParent {
private P<S2> predicate;
@@ -41,10 +44,16 @@ public final class AllStep<S, S2> extends FilterStep<S> {
}
this.predicate = predicate;
+ P.integrateTraversals(this.predicate, this);
}
@Override
protected boolean filter(final Traverser.Admin<S> traverser) {
+ if (this.predicate.hasTraversal()) {
+ this.predicate.resolve(traverser);
+ if (this.predicate.isResolvedEmpty()) return false;
+ }
+
final S item = traverser.get();
if (item instanceof Iterable || item instanceof Iterator || ((item != null) && item.getClass().isArray())) {
@@ -65,6 +74,14 @@ public final class AllStep<S, S2> extends FilterStep<S> {
return StringFactory.stepString(this, this.predicate);
}
+ @SuppressWarnings("unchecked")
+ @Override
+ public <S, E> List<Traversal.Admin<S, E>> getLocalChildren() {
+ final List<Traversal.Admin<?, ?>> traversals = new ArrayList<>();
+ P.collectTraversals(this.predicate, traversals);
+ return (List) Collections.unmodifiableList(traversals);
+ }
+
@Override
public AllStep<S, S2> clone() {
final AllStep<S, S2> clone = (AllStep<S, S2>) super.clone();
@@ -74,6 +91,12 @@ public final class AllStep<S, S2> extends FilterStep<S> {
@Override
public Set<TraverserRequirement> getRequirements() {
- return EnumSet.of(TraverserRequirement.OBJECT);
+ return this.getSelfAndChildRequirements(TraverserRequirement.OBJECT);
+ }
+
+ @Override
+ public void setTraversal(final Traversal.Admin<?, ?> parentTraversal) {
+ super.setTraversal(parentTraversal);
+ P.integrateTraversals(this.predicate, this);
}
}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/AnyStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/AnyStep.java
index 9881186d7c..a518829ea9 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/AnyStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/AnyStep.java
@@ -21,15 +21,18 @@ package org.apache.tinkerpop.gremlin.process.traversal.step.filter;
import org.apache.tinkerpop.gremlin.process.traversal.P;
import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
+import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
-import java.util.EnumSet;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.Iterator;
+import java.util.List;
import java.util.Set;
-public final class AnyStep<S, S2> extends FilterStep<S> {
+public final class AnyStep<S, S2> extends FilterStep<S> implements TraversalParent {
private P<S2> predicate;
@@ -41,10 +44,16 @@ public final class AnyStep<S, S2> extends FilterStep<S> {
}
this.predicate = predicate;
+ P.integrateTraversals(this.predicate, this);
}
@Override
protected boolean filter(final Traverser.Admin<S> traverser) {
+ if (this.predicate.hasTraversal()) {
+ this.predicate.resolve(traverser);
+ if (this.predicate.isResolvedEmpty()) return false;
+ }
+
final S item = traverser.get();
if (item instanceof Iterable || item instanceof Iterator || ((item != null) && item.getClass().isArray())) {
@@ -65,6 +74,14 @@ public final class AnyStep<S, S2> extends FilterStep<S> {
return StringFactory.stepString(this, this.predicate);
}
+ @SuppressWarnings("unchecked")
+ @Override
+ public <S, E> List<Traversal.Admin<S, E>> getLocalChildren() {
+ final List<Traversal.Admin<?, ?>> traversals = new ArrayList<>();
+ P.collectTraversals(this.predicate, traversals);
+ return (List) Collections.unmodifiableList(traversals);
+ }
+
@Override
public AnyStep<S, S2> clone() {
final AnyStep<S, S2> clone = (AnyStep<S, S2>) super.clone();
@@ -74,6 +91,12 @@ public final class AnyStep<S, S2> extends FilterStep<S> {
@Override
public Set<TraverserRequirement> getRequirements() {
- return EnumSet.of(TraverserRequirement.OBJECT);
+ return this.getSelfAndChildRequirements(TraverserRequirement.OBJECT);
+ }
+
+ @Override
+ public void setTraversal(final Traversal.Admin<?, ?> parentTraversal) {
+ super.setTraversal(parentTraversal);
+ P.integrateTraversals(this.predicate, this);
}
}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/HasStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/HasStep.java
index e7ef009565..07e15f5fd7 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/HasStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/HasStep.java
@@ -18,35 +18,44 @@
*/
package org.apache.tinkerpop.gremlin.process.traversal.step.filter;
+import org.apache.tinkerpop.gremlin.process.traversal.P;
import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
import org.apache.tinkerpop.gremlin.process.traversal.step.Configuring;
import org.apache.tinkerpop.gremlin.process.traversal.step.HasContainerHolder;
+import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.Parameters;
import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
+import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil;
import org.apache.tinkerpop.gremlin.structure.Element;
import org.apache.tinkerpop.gremlin.structure.Property;
+import org.apache.tinkerpop.gremlin.structure.T;
+import org.apache.tinkerpop.gremlin.structure.util.CloseableIterator;
import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.EnumSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Set;
/**
* @author Marko A. Rodriguez (http://markorodriguez.com)
*/
-public class HasStep<S extends Element> extends FilterStep<S> implements HasContainerHolder<S, S>, Configuring {
+public class HasStep<S extends Element> extends FilterStep<S> implements HasContainerHolder<S, S>, Configuring, TraversalParent {
private final Parameters parameters = new Parameters();
private List<HasContainer> hasContainers;
+ private List<Traversal.Admin<?, ?>> childTraversals = new ArrayList<>();
public HasStep(final Traversal.Admin traversal, final HasContainer... hasContainers) {
super(traversal);
this.hasContainers = new ArrayList<>();
- Collections.addAll(this.hasContainers, hasContainers);
+ for (final HasContainer hc : hasContainers) {
+ this.hasContainers.add(hc);
+ extractAndIntegrateTraversals(hc);
+ }
}
@Override
@@ -63,14 +72,159 @@ public class HasStep<S extends Element> extends FilterStep<S> implements HasCont
protected boolean filter(final Traverser.Admin<S> traverser) {
// the generic S is defined as Element but Property can also be used with HasStep so this seems to cause
// problems with some jdk versions.
- if (traverser.get() instanceof Element)
- return HasContainer.testAll(traverser.get(), this.hasContainers);
- else if (traverser.get() instanceof Property)
- return HasContainer.testAll((Property) traverser.get(), this.hasContainers);
- else
+ // Check Property BEFORE Element because VertexProperty implements both interfaces.
+ // HasContainer.test(Property) correctly handles T.key and T.value accessors, whereas
+ // HasContainer.test(Element) would fall through to element.properties("~key") which fails.
+ if (traverser.get() instanceof Property) {
+ return testAllWithTraversals(traverser, (Property) traverser.get());
+ } else if (traverser.get() instanceof Element) {
+ return testAllWithTraversals(traverser, (Element) traverser.get());
+ } else {
throw new IllegalStateException(String.format(
"Traverser to has() must be of type Property or Element, not %s",
traverser.get().getClass().getName()));
+ }
+ }
+
+ /**
+ * Tests all HasContainers against an Element, handling traversal-bearing containers by evaluating
+ * child traversals against the current traverser.
+ */
+ private boolean testAllWithTraversals(final Traverser.Admin<S> traverser, final Element element) {
+ for (final HasContainer hc : this.hasContainers) {
+ if (!testHasContainer(traverser, hc, element)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Tests all HasContainers against a Property, handling traversal-bearing containers by evaluating
+ * child traversals against the current traverser.
+ */
+ private boolean testAllWithTraversals(final Traverser.Admin<S> traverser, final Property property) {
+ for (final HasContainer hc : this.hasContainers) {
+ if (hc.hasTraversal()) {
+ // For properties with traversals, we need to handle the traversal resolution
+ if (hc.getTraversalValue() != null) {
+ final List<Object> results = collectTraversalResults(traverser, hc.getTraversalValue());
+ if (results.isEmpty()) return false;
+ // Get the property value to test against
+ final Object propertyValue = getPropertyValueFromProperty(property, hc.getKey());
+ if (!P.within(results).test(propertyValue)) return false;
+ } else if (hc.getPredicate() != null && hc.getPredicate().hasTraversal()) {
+ hc.getPredicate().resolve(traverser);
+ if (hc.getPredicate().isResolvedEmpty()) return false;
+ if (!hc.test(property)) return false;
+ } else {
+ if (!hc.test(property)) return false;
+ }
+ } else {
+ if (!hc.test(property)) return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Tests a single HasContainer against an Element, resolving traversals if present.
+ */
+ private boolean testHasContainer(final Traverser.Admin<S> traverser, final HasContainer hc, final Element element) {
+ if (hc.hasTraversal()) {
+ if (hc.getTraversalValue() != null) {
+ // Direct traversal value: evaluate and use P.within(results)
+ final List<Object> results = collectTraversalResults(traverser, hc.getTraversalValue());
+ if (results.isEmpty()) return false;
+ final Object propertyValue = getPropertyValue(element, hc.getKey());
+ if (propertyValue == null) return false;
+ return P.within(results).test(propertyValue);
+ } else if (hc.getPredicate() != null && hc.getPredicate().hasTraversal()) {
+ // Predicate with embedded traversal: resolve then test normally
+ hc.getPredicate().resolve(traverser);
+ if (hc.getPredicate().isResolvedEmpty()) return false;
+ return hc.test(element);
+ }
+ }
+ // No traversal: use existing test path
+ return hc.test(element);
+ }
+
+ /**
+ * Gets the property value from an Element for the given key, handling T.id and T.label accessors.
+ */
+ private Object getPropertyValue(final Element element, final String key) {
+ if (key != null) {
+ if (key.equals(T.id.getAccessor())) {
+ return element.id();
+ }
+ if (key.equals(T.label.getAccessor())) {
+ return element.label();
+ }
+ }
+ final Iterator<? extends Property> itty = element.properties(key);
+ try {
+ if (itty.hasNext()) {
+ return itty.next().value();
+ }
+ } finally {
+ CloseableIterator.closeIterator(itty);
+ }
+ return null;
+ }
+
+ /**
+ * Gets the property value from a Property for the given key, handling T.value and T.key accessors.
+ */
+ private Object getPropertyValueFromProperty(final Property property, final String key) {
+ if (key != null) {
+ if (key.equals(T.value.getAccessor())) {
+ return property.value();
+ }
+ if (key.equals(T.key.getAccessor())) {
+ return property.key();
+ }
+ }
+ if (property instanceof Element) {
+ return getPropertyValue((Element) property, key);
+ }
+ return null;
+ }
+
+ /**
+ * Collects all results from a child traversal evaluated against the current traverser.
+ * Uses the same prepare + iterate pattern as {@link TraversalUtil#applyAll(Traverser.Admin, Traversal.Admin)}
+ * to avoid ambiguous overload resolution when S extends Element.
+ */
+ @SuppressWarnings("unchecked")
+ private List<Object> collectTraversalResults(final Traverser.Admin<S> traverser,
+ final Traversal.Admin<?, ?> childTraversal) {
+ final List<Object> results = new ArrayList<>();
+ TraversalUtil.prepare(traverser, (Traversal.Admin) childTraversal);
+ while (childTraversal.hasNext()) {
+ results.add(childTraversal.next());
+ }
+ return results;
+ }
+
+ /**
+ * Extracts child traversals from a HasContainer and integrates them as children of this step.
+ * Handles direct traversal values on the container as well as traversals embedded within
+ * predicates (including ConnectiveP which may have traversals on child predicates).
+ */
+ private void extractAndIntegrateTraversals(final HasContainer hc) {
+ if (hc.getTraversalValue() != null) {
+ this.childTraversals.add(hc.getTraversalValue());
+ this.integrateChild(hc.getTraversalValue());
+ }
+ if (hc.getPredicate() != null && hc.getPredicate().hasTraversal()) {
+ final List<Traversal.Admin<?, ?>> predicateTraversals = new ArrayList<>();
+ P.collectTraversals(hc.getPredicate(), predicateTraversals);
+ for (final Traversal.Admin<?, ?> t : predicateTraversals) {
+ this.childTraversals.add(t);
+ this.integrateChild(t);
+ }
+ }
}
@Override
@@ -91,23 +245,46 @@ public class HasStep<S extends Element> extends FilterStep<S> implements HasCont
@Override
public void addHasContainer(final HasContainer hasContainer) {
this.hasContainers.add(hasContainer);
+ extractAndIntegrateTraversals(hasContainer);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <S, E> List<Traversal.Admin<S, E>> getLocalChildren() {
+ return (List) Collections.unmodifiableList(this.childTraversals);
}
@Override
public Set<TraverserRequirement> getRequirements() {
- return EnumSet.of(TraverserRequirement.OBJECT);
+ return this.getSelfAndChildRequirements(TraverserRequirement.OBJECT);
}
@Override
public HasStep<S> clone() {
final HasStep<S> clone = (HasStep<S>) super.clone();
clone.hasContainers = new ArrayList<>();
+ clone.childTraversals = new ArrayList<>();
for (final HasContainer hasContainer : this.hasContainers) {
- clone.addHasContainer(hasContainer.clone());
+ final HasContainer clonedHc = hasContainer.clone();
+ clone.hasContainers.add(clonedHc);
+ if (clonedHc.getTraversalValue() != null) {
+ clone.childTraversals.add(clonedHc.getTraversalValue());
+ }
+ if (clonedHc.getPredicate() != null && clonedHc.getPredicate().hasTraversal()) {
+ P.collectTraversals(clonedHc.getPredicate(), clone.childTraversals);
+ }
}
return clone;
}
+ @Override
+ public void setTraversal(final Traversal.Admin<?, ?> parentTraversal) {
+ super.setTraversal(parentTraversal);
+ for (final Traversal.Admin<?, ?> childTraversal : this.childTraversals) {
+ this.integrateChild(childTraversal);
+ }
+ }
+
@Override
public int hashCode() {
int result = super.hashCode();
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/IsStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/IsStep.java
index 70ad55ff31..04d492733e 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/IsStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/IsStep.java
@@ -21,27 +21,35 @@ package org.apache.tinkerpop.gremlin.process.traversal.step.filter;
import org.apache.tinkerpop.gremlin.process.traversal.P;
import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
+import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
-import java.util.EnumSet;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
import java.util.Set;
/**
* @author Daniel Kuppitz (http://gremlin.guru)
* @author Marko A. Rodriguez (http://markorodriguez.com)
*/
-public final class IsStep<S> extends FilterStep<S> implements IsStepContract<S> {
+public final class IsStep<S> extends FilterStep<S> implements IsStepContract<S>, TraversalParent {
private P<S> predicate;
public IsStep(final Traversal.Admin traversal, final P<S> predicate) {
super(traversal);
this.predicate = predicate;
+ P.integrateTraversals(this.predicate, this);
}
@Override
protected boolean filter(final Traverser.Admin<S> traverser) {
+ if (this.predicate.hasTraversal()) {
+ this.predicate.resolve(traverser);
+ if (this.predicate.isResolvedEmpty()) return false;
+ }
return this.predicate.test(traverser.get());
}
@@ -55,6 +63,14 @@ public final class IsStep<S> extends FilterStep<S> implements IsStepContract<S>
return this.predicate;
}
+ @SuppressWarnings("unchecked")
+ @Override
+ public <S, E> List<Traversal.Admin<S, E>> getLocalChildren() {
+ final List<Traversal.Admin<?, ?>> traversals = new ArrayList<>();
+ P.collectTraversals(this.predicate, traversals);
+ return (List) Collections.unmodifiableList(traversals);
+ }
+
@Override
public IsStep<S> clone() {
final IsStep<S> clone = (IsStep<S>) super.clone();
@@ -69,7 +85,12 @@ public final class IsStep<S> extends FilterStep<S> implements IsStepContract<S>
@Override
public Set<TraverserRequirement> getRequirements() {
- return EnumSet.of(TraverserRequirement.OBJECT);
+ return this.getSelfAndChildRequirements(TraverserRequirement.OBJECT);
}
+ @Override
+ public void setTraversal(final Traversal.Admin<?, ?> parentTraversal) {
+ super.setTraversal(parentTraversal);
+ P.integrateTraversals(this.predicate, this);
+ }
}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/NoneStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/NoneStep.java
index 542d16ca5c..b303d30c6e 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/NoneStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/NoneStep.java
@@ -21,15 +21,18 @@ package org.apache.tinkerpop.gremlin.process.traversal.step.filter;
import org.apache.tinkerpop.gremlin.process.traversal.P;
import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
+import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
-import java.util.EnumSet;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.Iterator;
+import java.util.List;
import java.util.Set;
-public final class NoneStep<S, S2> extends FilterStep<S> {
+public final class NoneStep<S, S2> extends FilterStep<S> implements TraversalParent {
private P<S2> predicate;
@@ -41,10 +44,18 @@ public final class NoneStep<S, S2> extends FilterStep<S> {
}
this.predicate = predicate;
+ P.integrateTraversals(this.predicate, this);
}
@Override
protected boolean filter(final Traverser.Admin<S> traverser) {
+ if (this.predicate.hasTraversal()) {
+ this.predicate.resolve(traverser);
+ // Vacuously true: if the predicate can't be evaluated (no comparison value),
+ // then no item can match, so none() is satisfied.
+ if (this.predicate.isResolvedEmpty()) return true;
+ }
+
final S item = traverser.get();
if (item instanceof Iterable || item instanceof Iterator || ((item != null) && item.getClass().isArray())) {
@@ -65,6 +76,14 @@ public final class NoneStep<S, S2> extends FilterStep<S> {
return StringFactory.stepString(this, this.predicate);
}
+ @SuppressWarnings("unchecked")
+ @Override
+ public <S, E> List<Traversal.Admin<S, E>> getLocalChildren() {
+ final List<Traversal.Admin<?, ?>> traversals = new ArrayList<>();
+ P.collectTraversals(this.predicate, traversals);
+ return (List) Collections.unmodifiableList(traversals);
+ }
+
@Override
public NoneStep<S, S2> clone() {
final NoneStep<S, S2> clone = (NoneStep<S, S2>) super.clone();
@@ -74,6 +93,12 @@ public final class NoneStep<S, S2> extends FilterStep<S> {
@Override
public Set<TraverserRequirement> getRequirements() {
- return EnumSet.of(TraverserRequirement.OBJECT);
+ return this.getSelfAndChildRequirements(TraverserRequirement.OBJECT);
+ }
+
+ @Override
+ public void setTraversal(final Traversal.Admin<?, ?> parentTraversal) {
+ super.setTraversal(parentTraversal);
+ P.integrateTraversals(this.predicate, this);
}
}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GraphStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GraphStep.java
index 7e64cd391a..5abc13ecc9 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GraphStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GraphStep.java
@@ -25,10 +25,12 @@ import org.apache.tinkerpop.gremlin.process.traversal.Step;
import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
+import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.AbstractStep;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.Parameters;
import org.apache.tinkerpop.gremlin.process.traversal.util.FastNoSuchElementException;
+import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil;
import org.apache.tinkerpop.gremlin.structure.Edge;
import org.apache.tinkerpop.gremlin.structure.Element;
import org.apache.tinkerpop.gremlin.structure.T;
@@ -37,10 +39,12 @@ import org.apache.tinkerpop.gremlin.structure.util.CloseableIterator;
import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
import org.apache.tinkerpop.gremlin.util.iterator.EmptyIterator;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
+import java.util.List;
import java.util.Objects;
import java.util.function.Supplier;
@@ -48,7 +52,7 @@ import java.util.function.Supplier;
* @author Marko A. Rodriguez (http://markorodriguez.com)
* @author Pieter Martin
*/
-public class GraphStep<S, E extends Element> extends AbstractStep<S, E> implements GraphStepContract<S, E> {
+public class GraphStep<S, E extends Element> extends AbstractStep<S, E> implements GraphStepContract<S, E>, TraversalParent {
protected Parameters parameters = new Parameters();
protected final Class<E> returnClass;
@@ -58,6 +62,7 @@ public class GraphStep<S, E extends Element> extends AbstractStep<S, E> implemen
protected boolean done = false;
private Traverser.Admin<S> head = null;
private Iterator<E> iterator = EmptyIterator.instance();
+ private Traversal.Admin<?, ?> idTraversal;
public GraphStep(final Traversal.Admin traversal, final Class<E> returnClass, final boolean isStart, final Object... ids) {
@@ -76,7 +81,36 @@ public class GraphStep<S, E extends Element> extends AbstractStep<S, E> implemen
this.getTraversal().getGraph().get().edges(this.ids));
}
+ public GraphStep(final Traversal.Admin traversal, final Class<E> returnClass, final boolean isStart, final Traversal.Admin<?, ?> idTraversal) {
+ this(traversal, returnClass, isStart);
+ this.idTraversal = idTraversal;
+ if (this.idTraversal != null) {
+ this.integrateChild(this.idTraversal);
+ }
+ }
+
+ /**
+ * Returns the child traversal used to resolve element IDs, or {@code null} if literal IDs are used.
+ */
+ public Traversal.Admin<?, ?> getIdTraversal() {
+ return this.idTraversal;
+ }
+
+ /**
+ * Sets the child traversal used to resolve element IDs. Calls {@link #integrateChild(Traversal.Admin)}
+ * on the provided traversal.
+ */
+ public void setIdTraversal(final Traversal.Admin<?, ?> idTraversal) {
+ this.idTraversal = idTraversal;
+ if (this.idTraversal != null) {
+ this.integrateChild(this.idTraversal);
+ }
+ }
+
public String toString() {
+ if (this.idTraversal != null) {
+ return StringFactory.stepString(this, this.returnClass.getSimpleName().toLowerCase(), this.idTraversal);
+ }
return StringFactory.stepString(this, this.returnClass.getSimpleName().toLowerCase(), Arrays.toString(this.ids));
}
@@ -164,16 +198,60 @@ public class GraphStep<S, E extends Element> extends AbstractStep<S, E> implemen
if (this.isStart) {
if (this.done)
throw FastNoSuchElementException.instance();
- else {
- this.done = true;
- this.iterator = null == this.iteratorSupplier ? EmptyIterator.instance() : this.iteratorSupplier.get();
+ if (this.idTraversal != null) {
+ throw new IllegalStateException(
+ "V(traversal)/E(traversal) cannot be used as a start step: " +
+ "no Traverser context available to evaluate the child traversal");
}
+ this.done = true;
+ this.iterator = null == this.iteratorSupplier ? EmptyIterator.instance() : this.iteratorSupplier.get();
} else {
this.head = this.starts.next();
- this.iterator = null == this.iteratorSupplier ? EmptyIterator.instance() : this.iteratorSupplier.get();
+ if (this.idTraversal != null) {
+ final Object[] resolvedIds = resolveTraversalIds(this.head);
+ this.iterator = lookupElements(resolvedIds);
+ } else {
+ this.iterator = null == this.iteratorSupplier ? EmptyIterator.instance() : this.iteratorSupplier.get();
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Resolves element IDs by evaluating the child traversal against the current traverser.
+ * Handles Element (extract ID), Collection (unpack), and raw values.
+ */
+ @SuppressWarnings("unchecked")
+ private Object[] resolveTraversalIds(final Traverser.Admin<S> traverser) {
+ final List<Object> ids = new ArrayList<>();
+ TraversalUtil.prepare(traverser, (Traversal.Admin) this.idTraversal);
+ while (this.idTraversal.hasNext()) {
+ final Object result = this.idTraversal.next();
+ if (result instanceof Element) {
+ ids.add(((Element) result).id());
+ } else if (result instanceof Collection) {
+ for (final Object item : (Collection<?>) result) {
+ ids.add(item instanceof Element ? ((Element) item).id() : item);
}
+ } else {
+ ids.add(result);
}
}
+ return ids.toArray();
+ }
+
+ /**
+ * Looks up elements (vertices or edges) by the given IDs using the graph.
+ */
+ @SuppressWarnings("unchecked")
+ private Iterator<E> lookupElements(final Object[] elementIds) {
+ if (elementIds.length == 0) {
+ return EmptyIterator.instance();
+ }
+ return (Iterator<E>) (Vertex.class.isAssignableFrom(this.returnClass) ?
+ this.getTraversal().getGraph().get().vertices(elementIds) :
+ this.getTraversal().getGraph().get().edges(elementIds));
}
@Override
@@ -182,6 +260,9 @@ public class GraphStep<S, E extends Element> extends AbstractStep<S, E> implemen
this.head = null;
this.done = false;
this.iterator = EmptyIterator.instance();
+ if (this.idTraversal != null) {
+ this.idTraversal.reset();
+ }
}
@Override
@@ -195,6 +276,31 @@ public class GraphStep<S, E extends Element> extends AbstractStep<S, E> implemen
return result;
}
+ @SuppressWarnings("unchecked")
+ @Override
+ public <S, E> List<Traversal.Admin<S, E>> getLocalChildren() {
+ return this.idTraversal != null
+ ? Collections.singletonList((Traversal.Admin<S, E>) this.idTraversal)
+ : Collections.emptyList();
+ }
+
+ @Override
+ public GraphStep<S, E> clone() {
+ final GraphStep<S, E> clone = (GraphStep<S, E>) super.clone();
+ if (this.idTraversal != null) {
+ clone.idTraversal = this.idTraversal.clone();
+ }
+ return clone;
+ }
+
+ @Override
+ public void setTraversal(final Traversal.Admin<?, ?> parentTraversal) {
+ super.setTraversal(parentTraversal);
+ if (this.idTraversal != null) {
+ this.integrateChild(this.idTraversal);
+ }
+ }
+
/**
* Attempts to close an underlying iterator if it is of type {@link CloseableIterator}. Graph providers may choose
* to return this interface containing their vertices and edges if there are expensive resources that might need to
@@ -203,6 +309,11 @@ public class GraphStep<S, E extends Element> extends AbstractStep<S, E> implemen
@Override
public void close() {
CloseableIterator.closeIterator(iterator);
+ try {
+ TraversalParent.super.close();
+ } catch (final Exception e) {
+ throw new RuntimeException(e);
+ }
}
/**
@@ -213,6 +324,7 @@ public class GraphStep<S, E extends Element> extends AbstractStep<S, E> implemen
* @return true if the {@link HasContainer} updated ids and thus, was processed.
*/
public static boolean processHasContainerIds(final GraphStep<?, ?> graphStep, final HasContainer hasContainer) {
+ if (hasContainer.hasTraversal()) return false;
final String key = hasContainer.getKey();
if (key != null && key.equals(T.id.getAccessor()) && graphStep.ids.length == 0 &&
(hasContainer.getBiPredicate() == Compare.eq || hasContainer.getBiPredicate() == Contains.within)) {
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AddPropertyStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AddPropertyStep.java
index 4223f98bd5..bc83ca4b0c 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AddPropertyStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AddPropertyStep.java
@@ -25,6 +25,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.util.Parameters;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.event.*;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.EventStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
+import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil;
import org.apache.tinkerpop.gremlin.structure.Edge;
import org.apache.tinkerpop.gremlin.structure.Element;
import org.apache.tinkerpop.gremlin.structure.Property;
@@ -35,6 +36,7 @@ import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
import org.apache.tinkerpop.gremlin.structure.util.keyed.KeyedProperty;
import org.apache.tinkerpop.gremlin.structure.util.keyed.KeyedVertexProperty;
+import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -89,11 +91,99 @@ public class AddPropertyStep<S extends Element> extends SideEffectStep<S> implem
throw new IllegalStateException(String.format("T.%s is immutable on existing elements", ((T) k).name()));
final String key = (String) k;
- final Object value = this.internalParameters.get(traverser, T.value, () -> {
- throw new IllegalStateException("The AddPropertyStep does not have a provided value: " + this);
- }).get(0);
+
+ // Check if the raw value is a traversal to enable multi-result handling.
+ // Exclude ConstantTraversal which is used internally by TinkerPop to wrap literal values.
+ final List<Object> rawValues = this.internalParameters.get(T.value, null);
+ final boolean valueIsTraversal = !rawValues.isEmpty()
+ && rawValues.get(0) instanceof Traversal.Admin
+ && !(rawValues.get(0) instanceof ConstantTraversal);
+
+ if (valueIsTraversal) {
+ handleTraversalValue(traverser, key);
+ } else {
+ final Object value = this.internalParameters.get(traverser, T.value, () -> {
+ throw new IllegalStateException("The AddPropertyStep does not have a provided value: " + this);
+ }).get(0);
+ final Object[] vertexPropertyKeyValues = this.internalParameters.getKeyValues(traverser, T.key, T.value);
+ applyPropertyMutation(traverser, key, value, vertexPropertyKeyValues);
+ }
+ }
+
+ /**
+ * Handles the case where the value argument is a child traversal, supporting multi-result
+ * resolution, Map-producing traversals, and cardinality-aware property setting.
+ */
+ private void handleTraversalValue(final Traverser.Admin<S> traverser, final String key) {
+ final List<Object> rawValues = this.internalParameters.get(T.value, null);
+ final Traversal.Admin<?, ?> valueTraversal = (Traversal.Admin<?, ?>) rawValues.get(0);
+
+ // Collect all results from the child traversal
+ final List<Object> results = new ArrayList<>();
+ final Traverser.Admin<S> trav = traverser;
+ final Iterator<?> itty = TraversalUtil.<S, Object>applyAll(trav, (Traversal.Admin<S, Object>) (Traversal.Admin) valueTraversal);
+ while (itty.hasNext()) {
+ results.add(itty.next());
+ }
+
+ // No-result case: skip mutation, pass element through unchanged
+ if (results.isEmpty()) {
+ return;
+ }
+
+ final Element element = traverser.get();
final Object[] vertexPropertyKeyValues = this.internalParameters.getKeyValues(traverser, T.key, T.value);
+ // Map-producing form: property(traversal) where traversal produces a Map
+ if (results.size() == 1 && results.get(0) instanceof Map) {
+ final Map<?, ?> map = (Map<?, ?>) results.get(0);
+ for (final Map.Entry<?, ?> entry : map.entrySet()) {
+ if (!(entry.getKey() instanceof String)) {
+ throw new IllegalArgumentException(
+ "Property key must be a String but found " + entry.getKey().getClass().getSimpleName());
+ }
+ final String mapKey = (String) entry.getKey();
+ applyPropertyMutation(traverser, mapKey, entry.getValue(), vertexPropertyKeyValues);
+ }
+ return;
+ }
+
+ // Multi-result handling with cardinality awareness
+ if (results.size() > 1) {
+ // Determine effective cardinality
+ final VertexProperty.Cardinality effectiveCard = this.cardinality != null
+ ? this.cardinality
+ : (element instanceof Vertex ? element.graph().features().vertex().getCardinality(key) : null);
+
+ if (effectiveCard == VertexProperty.Cardinality.single) {
+ throw new IllegalArgumentException(
+ "Single-cardinality property requires exactly one value, but traversal produced " +
+ results.size() + " results");
+ }
+
+ // For list/set cardinality with multiple results, add each as a separate property value
+ if (effectiveCard == VertexProperty.Cardinality.list || effectiveCard == VertexProperty.Cardinality.set) {
+ if (!(element instanceof Vertex)) {
+ throw new IllegalStateException(String.format(
+ "Property cardinality can only be set for a Vertex but the traversal encountered %s for key: %s",
+ element.getClass().getSimpleName(), key));
+ }
+ for (final Object v : results) {
+ applyPropertyMutation(traverser, key, v, vertexPropertyKeyValues);
+ }
+ return;
+ }
+ }
+
+ // Single result or default cardinality: use the first result
+ applyPropertyMutation(traverser, key, results.get(0), vertexPropertyKeyValues);
+ }
+
+ /**
+ * Applies a single property mutation to the element, handling eventing and cardinality.
+ */
+ private void applyPropertyMutation(final Traverser.Admin<S> traverser, final String key,
+ final Object value, final Object[] vertexPropertyKeyValues) {
final Element element = traverser.get();
// can't set cardinality if the element is something other than a vertex as only vertices can have
@@ -116,7 +206,7 @@ public class AddPropertyStep<S extends Element> extends SideEffectStep<S> implem
final VertexProperty.Cardinality card = this.cardinality != null
? this.cardinality
- : element.graph().features().vertex().getCardinality(key);
+ : (element instanceof Vertex ? element.graph().features().vertex().getCardinality(key) : null);
// update property
if (element instanceof Vertex) {
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/HasContainer.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/HasContainer.java
index 99a9c4e959..df3b2f1b13 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/HasContainer.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/HasContainer.java
@@ -19,6 +19,7 @@
package org.apache.tinkerpop.gremlin.process.traversal.step.util;
import org.apache.tinkerpop.gremlin.process.traversal.P;
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.structure.Element;
import org.apache.tinkerpop.gremlin.structure.Property;
import org.apache.tinkerpop.gremlin.structure.T;
@@ -39,6 +40,7 @@ public class HasContainer implements Serializable, Cloneable, Predicate<Element>
private String key;
private P predicate;
+ private Traversal.Admin<?, ?> traversalValue;
private final boolean testingIdString;
@@ -48,6 +50,18 @@ public class HasContainer implements Serializable, Cloneable, Predicate<Element>
this.testingIdString = isStringTestable();
}
+ /**
+ * Constructs a {@code HasContainer} with a child traversal whose result is resolved at runtime
+ * against the current traverser. The predicate is set to {@code null} and will be constructed
+ * dynamically during evaluation (e.g., as {@code P.within(results)}).
+ */
+ public HasContainer(final String key, final Traversal.Admin<?, ?> traversalValue) {
+ this.key = key;
+ this.predicate = null;
+ this.traversalValue = traversalValue;
+ this.testingIdString = false;
+ }
+
public final boolean test(final Element element) {
// it is OK to evaluate equality of ids via toString(), given that the test suite enforces the value of
// id().toString() to be a first class representation of the identifier. a string test is only executed
@@ -104,13 +118,19 @@ public class HasContainer implements Serializable, Cloneable, Predicate<Element>
}
public final String toString() {
+ if (this.traversalValue != null) {
+ return Objects.toString(this.key) + ".traversal(" + this.traversalValue + ")";
+ }
return Objects.toString(this.key) + '.' + this.predicate;
}
public HasContainer clone() {
try {
final HasContainer clone = (HasContainer) super.clone();
- clone.predicate = this.predicate.clone();
+ clone.predicate = this.predicate != null ? this.predicate.clone() : null;
+ if (this.traversalValue != null) {
+ clone.traversalValue = this.traversalValue.clone();
+ }
return clone;
} catch (final CloneNotSupportedException e) {
throw new IllegalStateException(e.getMessage(), e);
@@ -135,13 +155,33 @@ public class HasContainer implements Serializable, Cloneable, Predicate<Element>
}
public final BiPredicate<?, ?> getBiPredicate() {
+ if (this.predicate == null)
+ throw new IllegalStateException("Cannot access BiPredicate on a traversal-bearing HasContainer; check hasTraversal() first");
return this.predicate.getBiPredicate();
}
public final Object getValue() {
+ if (this.predicate == null)
+ throw new IllegalStateException("Cannot access value on a traversal-bearing HasContainer; check hasTraversal() first");
return this.predicate.getValue();
}
+ /**
+ * Determines if this {@code HasContainer} holds a child traversal, either directly
+ * via the {@code traversalValue} field or embedded within the predicate.
+ */
+ public boolean hasTraversal() {
+ return this.traversalValue != null || (this.predicate != null && this.predicate.hasTraversal());
+ }
+
+ /**
+ * Gets the child traversal value, if one was provided. Returns {@code null} when this
+ * {@code HasContainer} uses a literal predicate.
+ */
+ public Traversal.Admin<?, ?> getTraversalValue() {
+ return this.traversalValue;
+ }
+
////////////
/**
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java
index 8a6edcde28..d8c260d87f 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java
@@ -114,6 +114,10 @@ public final class InlineFilterStrategy extends AbstractTraversalStrategy<Traver
///////////////////////////
private static boolean processHasStep(final HasStep<?> step, final Traversal.Admin<?, ?> traversal) {
+ if (step.getHasContainers().stream().anyMatch(HasContainer::hasTraversal)) return false;
+ if (step.getPreviousStep() instanceof HasStep) {
+ if (((HasStep<?>) step.getPreviousStep()).getHasContainers().stream().anyMatch(HasContainer::hasTraversal)) return false;
+ }
if (step.getPreviousStep() instanceof HasStep) {
final HasStep<?> previousStep = (HasStep<?>) step.getPreviousStep();
final List<HasContainer> hasContainers = new ArrayList<>(step.getHasContainers());
@@ -221,6 +225,11 @@ public final class InlineFilterStrategy extends AbstractTraversalStrategy<Traver
InlineFilterStrategy.instance().apply(childTraversal);
for (final Step<?, ?> childStep : childTraversal.getSteps()) {
if (childStep instanceof HasStep) {
+ // Skip optimization if any HasContainer has a traversal-bearing predicate
+ if (((HasStep<?>) childStep).getHasContainers().stream().anyMatch(HasContainer::hasTraversal)) {
+ process = false;
+ break;
+ }
P p = null;
for (final HasContainer hasContainer : ((HasStep<?>) childStep).getHasContainers()) {
if (null == key)
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/AndP.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/AndP.java
index db5cced9ec..c6b860fd11 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/AndP.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/AndP.java
@@ -56,6 +56,15 @@ public final class AndP<V> extends ConnectiveP<V> {
return new OrP<>(this.predicates);
}
+ @Override
+ public boolean isResolvedEmpty() {
+ // AND short-circuits: if any child resolved empty, the conjunction cannot be satisfied
+ for (final P<V> p : this.predicates) {
+ if (p.hasTraversal() && p.isResolvedEmpty()) return true;
+ }
+ return false;
+ }
+
@Override
public String toString() {
return "and(" + StringFactory.removeEndBrackets(this.predicates) + ")";
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ConnectiveP.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ConnectiveP.java
index ef5a1142c3..fa277d2806 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ConnectiveP.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ConnectiveP.java
@@ -19,6 +19,7 @@
package org.apache.tinkerpop.gremlin.process.traversal.util;
import org.apache.tinkerpop.gremlin.process.traversal.P;
+import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
import java.util.ArrayList;
@@ -134,4 +135,21 @@ public abstract class ConnectiveP<V> extends P<V> {
}
return allGValues;
}
+
+ @Override
+ public boolean hasTraversal() {
+ if (super.hasTraversal()) return true;
+ for (final P<?> p : this.predicates) {
+ if (p.hasTraversal()) return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void resolve(final Traverser.Admin<?> traverser) {
+ super.resolve(traverser);
+ for (final P<?> p : this.predicates) {
+ p.resolve(traverser);
+ }
+ }
}
\ No newline at end of file
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/OrP.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/OrP.java
index 2a0c27c7af..0a054033e9 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/OrP.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/OrP.java
@@ -57,6 +57,19 @@ public final class OrP<V> extends ConnectiveP<V> {
return new AndP<>(this.predicates);
}
+ @Override
+ public boolean isResolvedEmpty() {
+ // OR short-circuits: only empty if ALL traversal-bearing children resolved empty
+ boolean anyTraversal = false;
+ for (final P<V> p : this.predicates) {
+ if (p.hasTraversal()) {
+ anyTraversal = true;
+ if (!p.isResolvedEmpty()) return false;
+ }
+ }
+ return anyTraversal;
+ }
+
@Override
public String toString() {
return "or(" + StringFactory.removeEndBrackets(this.predicates) + ")";
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/GremlinQueryParserTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/GremlinQueryParserTest.java
index e26a621ba0..cd16ef308c 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/GremlinQueryParserTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/GremlinQueryParserTest.java
@@ -96,7 +96,7 @@ public class GremlinQueryParserTest {
VariableResolver.NullVariableResolver.instance());
final GraphTraversal<?, ?> t = (GraphTraversal<?, ?>) GremlinQueryParser.parse("g.V().has('name',gt(z))", gremlinAntlrToJava);
- assertEquals(g.V().has("name", P.gt(null)).asAdmin().getGremlinLang(),
+ assertEquals(g.V().has("name", P.gt((Object) null)).asAdmin().getGremlinLang(),
t.asAdmin().getGremlinLang());
}
@@ -107,7 +107,7 @@ public class GremlinQueryParserTest {
VariableResolver.NullVariableResolver.instance());
final GraphTraversal<?, ?> t = (GraphTraversal<?, ?>) GremlinQueryParser.parse("g.V(a,b,c).has('name',gt(z))", gremlinAntlrToJava);
- assertEquals(g.V(null, null, null).has("name", P.gt(null)).asAdmin().getGremlinLang(),
+ assertEquals(g.V(null, null, null).has("name", P.gt((Object) null)).asAdmin().getGremlinLang(),
t.asAdmin().getGremlinLang());
}
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/GremlinQueryParserTraversalTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/GremlinQueryParserTraversalTest.java
new file mode 100644
index 0000000000..4eccaf97c0
--- /dev/null
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/GremlinQueryParserTraversalTest.java
@@ -0,0 +1,149 @@
+/*
+ * 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.language.grammar;
+
+import org.antlr.v4.runtime.CharStreams;
+import org.antlr.v4.runtime.CommonTokenStream;
+import org.apache.tinkerpop.gremlin.process.traversal.P;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.DefaultGraphTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.structure.T;
+import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource.traversal;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests that the Gremlin grammar correctly parses the new traversal-accepting syntax forms
+ * for has(), V(), E(), property(), and predicates.
+ */
+public class GremlinQueryParserTraversalTest {
+
+ private GraphTraversalSource g;
+ private GremlinAntlrToJava antlrToLanguage;
+
+ @Before
+ public void setup() {
+ g = traversal().withEmbedded(EmptyGraph.instance());
+ antlrToLanguage = new GremlinAntlrToJava();
+ }
+
+ private Object eval(final String query) {
+ final GremlinLexer lexer = new GremlinLexer(CharStreams.fromString(query));
+ final GremlinParser parser = new GremlinParser(new CommonTokenStream(lexer));
+ return antlrToLanguage.visit(parser.queryList());
+ }
+
+ private void compare(final Object expected, final Object actual) {
+ assertEquals(((DefaultGraphTraversal) expected).asAdmin().getGremlinLang(),
+ ((DefaultGraphTraversal) actual).asAdmin().getGremlinLang());
+ }
+
+ // ---- has(key, traversal) ----
+
+ @Test
+ public void shouldParseHasStringTraversal() {
+ compare(g.V().has("name", __.values("x")),
+ eval("g.V().has('name', __.values('x'))"));
+ }
+
+ // ---- has(label, key, traversal) ----
+
+ @Test
+ public void shouldParseHasStringStringTraversal() {
+ compare(g.V().has("person", "name", __.values("x")),
+ eval("g.V().has('person', 'name', __.values('x'))"));
+ }
+
+ // ---- has(T, traversal) ----
+
+ @Test
+ public void shouldParseHasTTraversal() {
+ compare(g.V().has(T.id, __.values("x")),
+ eval("g.V().has(T.id, __.values('x'))"));
+ }
+
+ // ---- V(traversal) mid-traversal ----
+
+ @Test
+ public void shouldParseVTraversalMidTraversal() {
+ compare(g.V().out().V(__.select("ids")),
+ eval("g.V().out().V(__.select('ids'))"));
+ }
+
+ // ---- E(traversal) mid-traversal ----
+
+ @Test
+ public void shouldParseETraversalMidTraversal() {
+ compare(g.V().out().E(__.select("ids")),
+ eval("g.V().out().E(__.select('ids'))"));
+ }
+
+ // ---- property(key, traversal) ----
+
+ @Test
+ public void shouldParsePropertyKeyTraversal() {
+ compare(g.V().property("key", __.select("val")),
+ eval("g.V().property('key', __.select('val'))"));
+ }
+
+ // ---- property(Cardinality, key, traversal) ----
+
+ @Test
+ public void shouldParsePropertyCardinalityKeyTraversal() {
+ compare(g.V().property(VertexProperty.Cardinality.single, "key", __.select("val")),
+ eval("g.V().property(Cardinality.single, 'key', __.select('val'))"));
+ }
+
+ // ---- P.eq(traversal) via has ----
+
+ @Test
+ public void shouldParseHasWithPEqTraversal() {
+ compare(g.V().has("name", P.eq(__.values("x"))),
+ eval("g.V().has('name', P.eq(__.values('x')))"));
+ }
+
+ // ---- P.gt(traversal) via has ----
+
+ @Test
+ public void shouldParseHasWithPGtTraversal() {
+ compare(g.V().has("age", P.gt(__.values("x"))),
+ eval("g.V().has('age', P.gt(__.values('x')))"));
+ }
+
+ // ---- P.within(traversal) via has ----
+
+ @Test
+ public void shouldParseHasWithPWithinTraversal() {
+ compare(g.V().has("name", P.within(__.values("x"))),
+ eval("g.V().has('name', P.within(__.values('x')))"));
+ }
+
+ // ---- property(traversal) — Map-producing form ----
+
+ @Test
+ public void shouldParsePropertyTraversal() {
+ compare(g.V().property(__.V().project("a").by("name")),
+ eval("g.V().property(__.V().project('a').by('name'))"));
+ }
+}
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/GremlinLangTraversalRoundTripTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/GremlinLangTraversalRoundTripTest.java
new file mode 100644
index 0000000000..60afe89fdc
--- /dev/null
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/GremlinLangTraversalRoundTripTest.java
@@ -0,0 +1,120 @@
+/*
+ * 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;
+
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.language.grammar.GremlinAntlrToJava;
+import org.apache.tinkerpop.gremlin.language.grammar.GremlinQueryParser;
+import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph;
+import org.junit.Test;
+
+import static org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource.traversal;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Property 7: GremlinLang serialization round-trip preserves traversal arguments.
+ * <p>
+ * For any step containing a child traversal argument, serializing to GremlinLang and parsing back
+ * SHALL produce a structurally equivalent traversal.
+ * <p>
+ * <b>Validates: Requirements 1.3, 3.6, 4.5, 6.5, 7.3</b>
+ */
+public class GremlinLangTraversalRoundTripTest {
+
+ private static final GraphTraversalSource g = traversal().with(EmptyGraph.instance());
+
+ /**
+ * Serializes a traversal to GremlinLang, parses it back, and verifies structural equivalence
+ * by comparing the GremlinLang output of both the original and the round-tripped traversal.
+ */
+ private void assertRoundTrip(final Traversal<?, ?> traversal) {
+ final String originalGremlin = traversal.asAdmin().getGremlinLang().getGremlin();
+
+ // Parse the GremlinLang string back into a traversal
+ final GremlinAntlrToJava antlr = new GremlinAntlrToJava();
+ final Object parsed = GremlinQueryParser.parse(originalGremlin, antlr);
+
+ // Get the GremlinLang of the parsed traversal
+ final String roundTrippedGremlin = ((Traversal<?, ?>) parsed).asAdmin().getGremlinLang().getGremlin();
+
+ assertEquals("GremlinLang round-trip should preserve traversal structure for: " + originalGremlin,
+ originalGremlin, roundTrippedGremlin);
+ }
+
+ @Test
+ public void shouldRoundTripHasWithTraversalValue() {
+ // g.V().has("name", __.values("x"))
+ assertRoundTrip(g.V().has("name", __.values("x")));
+ }
+
+ @Test
+ public void shouldRoundTripHasWithPredicateTraversal() {
+ // g.V().has("name", P.eq(__.values("x")))
+ assertRoundTrip(g.V().has("name", P.eq(__.values("x").asAdmin())));
+ }
+
+ @Test
+ public void shouldRoundTripVWithTraversal() {
+ // g.V().V(__.select("ids"))
+ assertRoundTrip(g.V().V(__.select("ids")));
+ }
+
+ @Test
+ public void shouldRoundTripPropertyWithTraversal() {
+ // g.V().property("key", __.select("val"))
+ assertRoundTrip(g.V().property("key", __.select("val")));
+ }
+
+ @Test
+ public void shouldRoundTripHasWithConstantTraversal() {
+ // g.V().has("name", __.constant("marko"))
+ assertRoundTrip(g.V().has("name", __.constant("marko")));
+ }
+
+ @Test
+ public void shouldRoundTripLiteralHasUnchanged() {
+ // Backward compatibility: literal has() should still round-trip correctly
+ assertRoundTrip(g.V().has("name", "marko"));
+ }
+
+ @Test
+ public void shouldRoundTripLiteralPredicateUnchanged() {
+ // Backward compatibility: literal P.eq() should still round-trip correctly
+ assertRoundTrip(g.V().has("name", P.eq("marko")));
+ }
+
+ @Test
+ public void shouldRoundTripHasWithPGtTraversal() {
+ // g.V().has("age", P.gt(__.constant(30)))
+ assertRoundTrip(g.V().has("age", P.gt(__.constant(30).asAdmin())));
+ }
+
+ @Test
+ public void shouldRoundTripEWithTraversal() {
+ // g.V().E(__.select("edgeIds"))
+ assertRoundTrip(g.V().E(__.select("edgeIds")));
+ }
+
+ @Test
+ public void shouldRoundTripPropertyWithMapTraversal() {
+ // g.V().property(__.V().project("a").by("name")) — the Map-producing form
+ assertRoundTrip(g.V().property(__.V().project("a").by("name")));
+ }
+}
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTest.java
index 4a8959a1ee..80f65c59db 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTest.java
@@ -65,8 +65,8 @@ public class PTest {
{P.eq(-0), +0, true},
{P.eq(0), 1, false},
{P.eq(0), null, false},
- {P.eq(null), null, true},
- {P.eq(null), 0, false},
+ {P.eq((Object) null), null, true},
+ {P.eq((Object) null), 0, false},
{P.eq(Double.POSITIVE_INFINITY), Double.NEGATIVE_INFINITY, false},
{P.eq(Float.POSITIVE_INFINITY), Float.NEGATIVE_INFINITY, false},
{P.eq(Float.POSITIVE_INFINITY), Double.NEGATIVE_INFINITY, false},
@@ -82,8 +82,8 @@ public class PTest {
{P.neq(-0), +0, false},
{P.neq(0), 1, true},
{P.neq(0), null, true},
- {P.neq(null), null, false},
- {P.neq(null), 0, true},
+ {P.neq((Object) null), null, false},
+ {P.neq((Object) null), 0, true},
{P.neq(Double.POSITIVE_INFINITY), Double.NEGATIVE_INFINITY, true},
{P.neq(Float.POSITIVE_INFINITY), Float.NEGATIVE_INFINITY, true},
{P.neq(Float.POSITIVE_INFINITY), Double.NEGATIVE_INFINITY, true},
@@ -468,7 +468,7 @@ public class PTest {
assertTrue(predicate.test(null));
assertFalse(predicate.test(INITIAL_VALUE));
assertEquals("eq", predicate.toString());
- assertEquals(predicate, P.eq(null));
+ assertEquals(predicate, P.eq((Object) null));
assertNotEquals(predicate, P.eq(INITIAL_VALUE));
}
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTraversalTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTraversalTest.java
new file mode 100644
index 0000000000..0485f9e509
--- /dev/null
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTraversalTest.java
@@ -0,0 +1,218 @@
+/*
+ * 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;
+
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
+import org.apache.tinkerpop.gremlin.process.traversal.traverser.B_O_Traverser;
+import org.junit.Test;
+import org.junit.experimental.runners.Enclosed;
+import org.junit.runner.RunWith;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+/**
+ * Tests for traversal-aware behavior in {@link P}, covering traversal detection accuracy
+ * and single-value predicate rejection of multiple traversal results.
+ */
+@RunWith(Enclosed.class)
+public class PTraversalTest {
+
+ /**
+ * Property 10: Traversal detection in predicates is accurate.
+ * <p>
+ * For any P instance containing a child traversal, {@code P.hasTraversal()} SHALL return true.
+ * For any P instance containing only literal values or GValue variables,
+ * {@code P.hasTraversal()} SHALL return false.
+ * <p>
+ * <b>Validates: Requirements 9.4</b>
+ */
+ public static class TraversalDetectionTest {
+
+ @Test
+ public void shouldDetectTraversalInComparisonPredicate() {
+ final P<Object> p = P.eq(__.identity().asAdmin());
+ assertThat(p.hasTraversal(), is(true));
+ }
+
+ @Test
+ public void shouldDetectTraversalInCollectionPredicate() {
+ final P<Object> p = P.within(__.inject(1, 2, 3).asAdmin());
+ assertThat(p.hasTraversal(), is(true));
+ }
+
+ @Test
+ public void shouldNotDetectTraversalInLiteralPredicate() {
+ final P<String> p = P.eq("value");
+ assertThat(p.hasTraversal(), is(false));
+ }
+
+ @Test
+ public void shouldNotDetectTraversalInGValuePredicate() {
+ final P<String> p = P.eq(GValue.of("x", "value"));
+ assertThat(p.hasTraversal(), is(false));
+ }
+
+ @Test
+ public void shouldReturnTraversalValueWhenPresent() {
+ final Traversal.Admin<?, ?> traversal = __.inject(42).asAdmin();
+ final P<Object> p = P.eq(traversal);
+ assertThat(p.getTraversalValue() == traversal, is(true));
+ }
+
+ @Test
+ public void shouldReturnNullTraversalValueForLiteral() {
+ final P<String> p = P.eq("value");
+ assertThat(p.getTraversalValue() == null, is(true));
+ }
+ }
+
+ /**
+ * Property 3: Single-value predicate rejects multiple traversal results.
+ * <p>
+ * For any single-value predicate (eq, neq, gt, lt, gte, lte) and any child traversal that produces
+ * more than one result, the predicate SHALL throw an IllegalArgumentException.
+ * For any collection predicate (within, without) and any child traversal producing multiple results,
+ * the predicate SHALL accept all results as the collection value.
+ * <p>
+ * <b>Validates: Requirements 2.5</b>
+ */
+ public static class SingleValuePredicateRejectionTest {
+
+ private Traverser.Admin<?> createTraverser(final Object value) {
+ return new B_O_Traverser<>(value, 1L);
+ }
+
+ // --- Single-value predicates should throw on multiple results ---
+
+ @Test(expected = IllegalArgumentException.class)
+ public void shouldRejectMultipleResultsForEq() {
+ final P<Object> p = P.eq(__.inject(1, 2).asAdmin());
+ p.resolve(createTraverser("start"));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void shouldRejectMultipleResultsForNeq() {
+ final P<Object> p = P.neq(__.inject(1, 2).asAdmin());
+ p.resolve(createTraverser("start"));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void shouldRejectMultipleResultsForGt() {
+ final P<Object> p = P.gt(__.inject(10, 20).asAdmin());
+ p.resolve(createTraverser("start"));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void shouldRejectMultipleResultsForLt() {
+ final P<Object> p = P.lt(__.inject(10, 20).asAdmin());
+ p.resolve(createTraverser("start"));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void shouldRejectMultipleResultsForGte() {
+ final P<Object> p = P.gte(__.inject(10, 20).asAdmin());
+ p.resolve(createTraverser("start"));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void shouldRejectMultipleResultsForLte() {
+ final P<Object> p = P.lte(__.inject(10, 20).asAdmin());
+ p.resolve(createTraverser("start"));
+ }
+
+ // --- Collection predicates should accept multiple results ---
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void shouldAcceptMultipleResultsForWithin() {
+ final P<Object> p = P.within(__.inject(1, 2, 3).asAdmin());
+ p.resolve(createTraverser("start"));
+ // After resolve, the predicate should have the collection value and be testable
+ assertThat(p.test(1), is(true));
+ assertThat(p.test(2), is(true));
+ assertThat(p.test(3), is(true));
+ assertThat(p.test(4), is(false));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void shouldAcceptMultipleResultsForWithout() {
+ final P<Object> p = P.without(__.inject(1, 2, 3).asAdmin());
+ p.resolve(createTraverser("start"));
+ // After resolve, without should exclude the resolved values
+ assertThat(p.test(1), is(false));
+ assertThat(p.test(2), is(false));
+ assertThat(p.test(3), is(false));
+ assertThat(p.test(4), is(true));
+ }
+
+ // --- Single-value predicates should succeed with exactly one result ---
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void shouldAcceptSingleResultForEq() {
+ final P<Object> p = P.eq(__.constant(42).asAdmin());
+ p.resolve(createTraverser("start"));
+ assertThat(p.test(42), is(true));
+ assertThat(p.test(99), is(false));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void shouldAcceptSingleResultForNeq() {
+ final P<Object> p = P.neq(__.constant(42).asAdmin());
+ p.resolve(createTraverser("start"));
+ assertThat(p.test(42), is(false));
+ assertThat(p.test(99), is(true));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void shouldAcceptSingleResultForGt() {
+ final P<Object> p = P.gt(__.constant(10).asAdmin());
+ p.resolve(createTraverser("start"));
+ assertThat(p.test(11), is(true));
+ assertThat(p.test(10), is(false));
+ assertThat(p.test(9), is(false));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void shouldAcceptSingleResultForLt() {
+ final P<Object> p = P.lt(__.constant(10).asAdmin());
+ p.resolve(createTraverser("start"));
+ assertThat(p.test(9), is(true));
+ assertThat(p.test(10), is(false));
+ assertThat(p.test(11), is(false));
+ }
+
+ // --- Collection predicates should also work with single result ---
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void shouldAcceptSingleResultForWithin() {
+ final P<Object> p = P.within(__.constant(42).asAdmin());
+ p.resolve(createTraverser("start"));
+ assertThat(p.test(42), is(true));
+ assertThat(p.test(99), is(false));
+ }
+ }
+}
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/CloneIndependenceTraversalTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/CloneIndependenceTraversalTest.java
new file mode 100644
index 0000000000..237a5d7884
--- /dev/null
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/CloneIndependenceTraversalTest.java
@@ -0,0 +1,119 @@
+/*
+ * 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.step;
+
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.process.traversal.step.filter.HasStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.GraphStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer;
+import org.apache.tinkerpop.gremlin.process.traversal.util.EmptyTraversal;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.junit.Test;
+
+import java.util.List;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.IsSame.sameInstance;
+
+/**
+ * Property 8: Clone independence for traversal-bearing steps.
+ * <p>
+ * For any step containing child traversal arguments, cloning the step SHALL produce a deep copy
+ * where modifying the clone's child traversal state does NOT affect the original step's child
+ * traversal state.
+ * <p>
+ * <b>Validates: Requirements 6.2</b>
+ */
+public class CloneIndependenceTraversalTest {
+
+ @Test
+ public void shouldProduceIndependentCloneForHasStepWithTraversalValue() {
+ // Create a HasStep with a traversal-bearing HasContainer
+ final Traversal.Admin<?, ?> childTraversal = __.constant("marko").asAdmin();
+ final HasContainer hc = new HasContainer("name", childTraversal);
+ final HasStep<Vertex> original = new HasStep<>(EmptyTraversal.instance(), hc);
+
+ // Clone the step
+ final HasStep<Vertex> clone = original.clone();
+
+ // Verify the clone has child traversals
+ final List<Traversal.Admin<?, ?>> originalChildren = (List) original.getLocalChildren();
+ final List<Traversal.Admin<?, ?>> cloneChildren = (List) clone.getLocalChildren();
+
+ assertThat(originalChildren.size(), is(1));
+ assertThat(cloneChildren.size(), is(1));
+
+ // The child traversals should be different instances (deep copy)
+ assertThat(cloneChildren.get(0), is(not(sameInstance(originalChildren.get(0)))));
+
+ // Verify HasContainers are also independent
+ final List<HasContainer> originalContainers = original.getHasContainers();
+ final List<HasContainer> cloneContainers = clone.getHasContainers();
+ assertThat(cloneContainers.get(0), is(not(sameInstance(originalContainers.get(0)))));
+ assertThat(cloneContainers.get(0).getTraversalValue(),
+ is(not(sameInstance(originalContainers.get(0).getTraversalValue()))));
+ }
+
+ @Test
+ public void shouldProduceIndependentCloneForGraphStepWithIdTraversal() {
+ // Create a GraphStep with an idTraversal
+ final Traversal.Admin<?, ?> idTraversal = __.select("ids").asAdmin();
+ final GraphStep<Vertex, Vertex> original =
+ new GraphStep<>(EmptyTraversal.instance(), Vertex.class, false, idTraversal);
+
+ // Clone the step
+ final GraphStep<Vertex, Vertex> clone = original.clone();
+
+ // Verify the clone has a child traversal
+ assertThat(original.getIdTraversal(), is(notNullValue()));
+ assertThat(clone.getIdTraversal(), is(notNullValue()));
+
+ // The idTraversal should be a different instance (deep copy)
+ assertThat(clone.getIdTraversal(), is(not(sameInstance(original.getIdTraversal()))));
+ }
+
+ @Test
+ public void shouldProduceIndependentCloneForHasStepWithMultipleContainers() {
+ // Create a HasStep with multiple HasContainers, some with traversals
+ final HasContainer hc1 = new HasContainer("name", __.constant("marko").asAdmin());
+ final HasContainer hc2 = new HasContainer("age", __.constant(29).asAdmin());
+ final HasStep<Vertex> original = new HasStep<>(EmptyTraversal.instance(), hc1, hc2);
+
+ // Clone the step
+ final HasStep<Vertex> clone = original.clone();
+
+ // Verify all containers are independent
+ final List<HasContainer> originalContainers = original.getHasContainers();
+ final List<HasContainer> cloneContainers = clone.getHasContainers();
+
+ assertThat(originalContainers.size(), is(2));
+ assertThat(cloneContainers.size(), is(2));
+
+ for (int i = 0; i < originalContainers.size(); i++) {
+ assertThat(cloneContainers.get(i), is(not(sameInstance(originalContainers.get(i)))));
+ assertThat(cloneContainers.get(i).getTraversalValue(),
+ is(not(sameInstance(originalContainers.get(i).getTraversalValue()))));
+ }
+ }
+
+}
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/HasContainerTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/HasContainerTest.java
new file mode 100644
index 0000000000..2164b7feba
--- /dev/null
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/HasContainerTest.java
@@ -0,0 +1,96 @@
+/*
+ * 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.step.util;
+
+import org.apache.tinkerpop.gremlin.process.traversal.P;
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.IsNot.not;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests for {@link HasContainer}, including traversal-bearing constructor and lifecycle methods.
+ */
+public class HasContainerTest {
+
+ @Test
+ public void shouldReturnFalseForHasTraversalWithLiteralPredicate() {
+ final HasContainer hc = new HasContainer("name", P.eq("marko"));
+ assertThat(hc.hasTraversal(), is(false));
+ }
+
+ @Test
+ public void shouldReturnTrueForHasTraversalWithTraversalValue() {
+ final Traversal.Admin<?, ?> traversal = __.identity().asAdmin();
+ final HasContainer hc = new HasContainer("name", traversal);
+ assertThat(hc.hasTraversal(), is(true));
+ }
+
+ @Test
+ public void shouldSetFieldsCorrectlyWithTraversalConstructor() {
+ final Traversal.Admin<?, ?> traversal = __.identity().asAdmin();
+ final HasContainer hc = new HasContainer("age", traversal);
+
+ assertEquals("age", hc.getKey());
+ assertThat(hc.getPredicate(), is(nullValue()));
+ assertThat(hc.getTraversalValue(), is(notNullValue()));
+ assertThat(hc.getTraversalValue(), is(sameInstance(traversal)));
+ }
+
+ @Test
+ public void shouldCloneProduceIndependentDeepCopyOfTraversalValue() {
+ final Traversal.Admin<?, ?> traversal = __.identity().asAdmin();
+ final HasContainer original = new HasContainer("name", traversal);
+ final HasContainer clone = original.clone();
+
+ // clone should have a traversalValue that is not the same instance
+ assertThat(clone.getTraversalValue(), is(notNullValue()));
+ assertThat(clone.getTraversalValue(), is(not(sameInstance(original.getTraversalValue()))));
+
+ // key should be equal
+ assertEquals(original.getKey(), clone.getKey());
+
+ // both should still report hasTraversal
+ assertThat(clone.hasTraversal(), is(true));
+ }
+
+ @Test
+ public void shouldCloneLiteralHasContainerWithoutTraversal() {
+ final HasContainer original = new HasContainer("name", P.eq("marko"));
+ final HasContainer clone = original.clone();
+
+ assertThat(clone.hasTraversal(), is(false));
+ assertThat(clone.getTraversalValue(), is(nullValue()));
+ assertEquals("name", clone.getKey());
+ assertEquals(P.eq("marko"), clone.getPredicate());
+ }
+
+ @Test
+ public void shouldReturnNullTraversalValueForLiteralConstructor() {
+ final HasContainer hc = new HasContainer("name", P.eq("marko"));
+ assertThat(hc.getTraversalValue(), is(nullValue()));
+ }
+}
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
index 8ac4ef7b25..7588da5935 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
@@ -532,6 +532,21 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
{"g_E_hasXlabel_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E().Has(T.Label, (object) null)}},
{"g_V_properties_hasLabelXnullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Properties<object>().HasLabel((string) null)}},
{"g_V_hasNotXageX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasNot("age").Values<object>("name")}},
+ {"g_V_hasXname_VXvid1X_valuesXnameXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name", __.V(p["vid1"]).Values<object>("name"))}},
+ {"g_V_hasXname_VXvid1X_outXknowsX_valuesXnameXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name", __.V(p["vid1"]).Out("knows").Values<object>("name"))}},
+ {"g_V_hasXage_VXvid1X_outXknowsX_valuesXageXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("age", __.V(p["vid1"]).Out("knows").Values<object>("age"))}},
+ {"g_V_hasXname_VXvid1X_outXcreatedX_valuesXnameXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name", __.V(p["vid1"]).Out("created").Values<object>("name"))}},
+ {"g_V_hasXname_VXvid1X_valuesXnonexistentXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name", __.V(p["vid1"]).Values<object>("nonexistent"))}},
+ {"g_V_hasXname_notXidentityXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name", __.Not(__.Identity()))}},
+ {"g_V_hasXage_gtXVXvid1X_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("age", P.Gt(__.V(p["vid1"]).Values<object>("age")))}},
+ {"g_V_hasXage_lteXVXvid2X_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("age", P.Lte(__.V(p["vid2"]).Values<object>("age")))}},
+ {"g_V_hasXage_neqXVXvid3X_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("age", P.Neq(__.V(p["vid3"]).Values<object>("age")))}},
+ {"g_V_hasXname_eqXVXvid1X_valuesXnameXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name", P.Eq(__.V(p["vid1"]).Values<object>("name")))}},
+ {"g_V_hasXage_ltXVXvid1X_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("age", P.Lt(__.V(p["vid1"]).Values<object>("age")))}},
+ {"g_V_hasXage_gteXVXvid3X_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("age", P.Gte(__.V(p["vid3"]).Values<object>("age")))}},
+ {"g_V_hasXage_eqXVXvid1X_valuesXnonexistentXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("age", P.Eq(__.V(p["vid1"]).Values<object>("nonexistent")))}},
+ {"g_V_hasXlabel_VXvid1X_labelXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has(T.Label, __.V(p["vid1"]).Label())}},
+ {"g_V_hasXperson_name_VXvid1X_valuesXnameXX_age", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("person", "name", __.V(p["vid1"]).Values<object>("name")).Values<object>("age")}},
{"g_V_properties_hasValueXnullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Properties<object>().HasValue((object) null)}},
{"g_V_properties_hasValueXnull_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Properties<object>().HasValue(null, null)}},
{"g_V_properties_hasValueXnull_joshX_value", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Properties<object>().HasValue(null, "josh").Value<object>()}},
@@ -1779,6 +1794,16 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
{"g_V_localXoutE_foldX_unfold", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Local<object>(__.OutE().Fold()).Unfold<object>()}},
{"g_V_valueMap_unfold_mapXselectXkeysXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ValueMap<object, object>().Unfold<object>().Map<object>(__.Select<object>(Column.Keys))}},
{"g_VX1X_repeatXboth_simplePathX_untilXhasIdX6XX_path_byXnameX_unfold", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Repeat(__.Both().SimplePath()).Until(__.HasId(p["vid6"])).Path().By("name").Unfold<object>()}},
+ {"g_VXvid1X_outXcreatedX_asXsoftwareX_V_hasXname_selectXsoftwareX_valuesXnameXX_inXcreatedX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out("created").As("sw").V().Has("name", __.Select<object>("sw").Values<object>("name")).In("created").Values<object>("name")}},
+ {"g_VXvid1X_VXoutXknowsX_idX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).V(__.Out("knows").Id()).Values<object>("name")}},
+ {"g_VXvid1X_VXoutXknowsX_hasXname_joshX_idX_valuesXageX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).V(__.Out("knows").Has("name", "josh").Id()).Values<object>("age")}},
+ {"g_VXvid1X_VXoutXknowsX_outXknowsX_idX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).V(__.Out("knows").Out("knows").Id()).Values<object>("name")}},
+ {"g_VXvid1X_VXoutXcreatedX_idX_valuesXlangX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).V(__.Out("created").Id()).Values<object>("lang")}},
+ {"g_VXvid1X_EXoutE_idX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).E(__.OutE().Id())}},
+ {"g_VXvid1X_EXoutEXknowsX_hasXweight_05X_idX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).E(__.OutE("knows").Has("weight", 0.5d).Id())}},
+ {"g_VXvid1X_EXoutXknowsX_outXknowsX_outE_idX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).E(__.Out("knows").Out("knows").OutE().Id())}},
+ {"g_VXVXvid1X_idX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(__.V(p["vid1"]).Id()).Values<object>("name")}},
+ {"g_EXVXvid1X_outE_idX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E(__.V(p["vid1"]).OutE().Id())}},
{"g_V_valueMap", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ValueMap<object, object>()}},
{"g_V_valueMapXtrueX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ValueMap<object, object>(true)}},
{"g_V_valueMap_withXtokensX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ValueMap<object, object>().With(WithOptions.Tokens)}},
@@ -2100,6 +2125,17 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
{"g_injectX1_3_100_300X_list", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(new List<object> { 1, 3, 100, 300 })}},
{"g_injectX1_3_100_300X_set", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(new HashSet<object> { 1, 3, 100, 300 })}},
{"g_injectX1_1X_set", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(new HashSet<object> { 1, 1 })}},
+ {"g_VXvid2X_propertyXalias_VXvid1X_valuesXnameXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid2"]).Property("alias", __.V(p["vid1"]).Values<object>("name")), (g,p) =>g.V().Has("alias", "marko")}},
+ {"g_VXvid1X_propertyXcreatorCount_VXvid1X_inXcreatedX_countX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Property("creatorCount", __.V(p["vid1"]).In("created").Count()), (g,p) =>g.V().Has("creatorCount", 3l)}},
+ {"g_VXvid1X_propertyXknownCount_outXknowsX_countX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Property("knownCount", __.Out("knows").Count()), (g,p) =>g.V().Has("knownCount", 2l)}},
+ {"g_VXvid1X_propertyXcreator_inXcreatedX_valuesXnameXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Property("creator", __.In("created").Values<object>("name")), (g,p) =>g.V().Has("creator")}},
+ {"g_VXvid2X_propertyXVXvid1X_projectXfriendCount_softwareCreatedXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid2"]).Property(__.V(p["vid1"]).Project<object>("friendCount", "softwareCreated").By(__.Out("knows").Count()).By(__.Out("created").Values<object>("name"))), (g,p) =>g.V().Has("friendCount", 2l), (g,p) =>g.V().Has("softwareCreated", "lop")}},
+ {"g_VXvid2X_propertyXVXvid1X_projectXoriginalName_originalLabelX_byXnameX_byXlabelXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid2"]).Property(__.V(p["vid1"]).Project<object>("originalName", "originalLabel").By(__.Values<object>("name")).By(__.Label())), (g,p) =>g.V(p["vid2"]).Has("originalName", "marko"), (g,p) =>g.V(p["vid2"]).Has("originalLabel", "person")}},
+ {"g_VXvid1X_propertyXlist_friends_outXknowsX_valuesXnameXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Property(Cardinality.List, "friends", __.Out("knows").Values<object>("name")), (g,p) =>g.V(p["vid1"]).Properties<object>("friends")}},
+ {"g_VXvid1X_propertyXlist_creators_inXcreatedX_valuesXnameXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Property(Cardinality.List, "creators", __.In("created").Values<object>("name")), (g,p) =>g.V(p["vid1"]).Properties<object>("creators")}},
+ {"g_VXvid1X_propertyXset_langs_outXcreatedX_valuesXlangXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Property(Cardinality.Set, "langs", __.Out("created").Values<object>("lang")), (g,p) =>g.V(p["vid1"]).Properties<object>("langs")}},
+ {"g_VXvid1X_propertyXsingle_friend_outXknowsX_valuesXnameXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Property(Cardinality.Single, "friend", __.Out("knows").Values<object>("name"))}},
+ {"g_VXvid1X_propertyXVXvid1X_groupX_byXidX_byXvaluesXnameXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Property(__.V(p["vid1"]).Group<object, object>().By(__.Id()).By(__.Values<object>("name")))}},
{"g_io_readXkryoX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Io<object>("data/tinkerpop-modern.kryo").Read(), (g,p) =>g.V(), (g,p) =>g.E()}},
{"g_io_read_withXreader_gryoX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Io<object>("data/tinkerpop-modern.kryo").With(IO.Reader, IO.Gryo).Read(), (g,p) =>g.V(), (g,p) =>g.E()}},
{"g_io_readXgraphsonX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Io<object>("data/tinkerpop-modern.json").Read(), (g,p) =>g.V(), (g,p) =>g.E()}},
diff --git a/gremlin-go/driver/cucumber/gremlin.go b/gremlin-go/driver/cucumber/gremlin.go
index 574fdb45fc..72df59267e 100644
--- a/gremlin-go/driver/cucumber/gremlin.go
+++ b/gremlin-go/driver/cucumber/gremlin.go
@@ -502,6 +502,21 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[
"g_E_hasXlabel_nullX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E().Has(gremlingo.T.Label, nil)}},
"g_V_properties_hasLabelXnullX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Properties().HasLabel(nil)}},
"g_V_hasNotXageX_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasNot("age").Values("name")}},
+ "g_V_hasXname_VXvid1X_valuesXnameXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.T__.V(p["vid1"]).Values("name"))}},
+ "g_V_hasXname_VXvid1X_outXknowsX_valuesXnameXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.T__.V(p["vid1"]).Out("knows").Values("name"))}},
+ "g_V_hasXage_VXvid1X_outXknowsX_valuesXageXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("age", gremlingo.T__.V(p["vid1"]).Out("knows").Values("age"))}},
+ "g_V_hasXname_VXvid1X_outXcreatedX_valuesXnameXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.T__.V(p["vid1"]).Out("created").Values("name"))}},
+ "g_V_hasXname_VXvid1X_valuesXnonexistentXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.T__.V(p["vid1"]).Values("nonexistent"))}},
+ "g_V_hasXname_notXidentityXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.T__.Not(gremlingo.T__.Identity()))}},
+ "g_V_hasXage_gtXVXvid1X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("age", gremlingo.P.Gt(gremlingo.T__.V(p["vid1"]).Values("age")))}},
+ "g_V_hasXage_lteXVXvid2X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("age", gremlingo.P.Lte(gremlingo.T__.V(p["vid2"]).Values("age")))}},
+ "g_V_hasXage_neqXVXvid3X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("age", gremlingo.P.Neq(gremlingo.T__.V(p["vid3"]).Values("age")))}},
+ "g_V_hasXname_eqXVXvid1X_valuesXnameXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.P.Eq(gremlingo.T__.V(p["vid1"]).Values("name")))}},
+ "g_V_hasXage_ltXVXvid1X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("age", gremlingo.P.Lt(gremlingo.T__.V(p["vid1"]).Values("age")))}},
+ "g_V_hasXage_gteXVXvid3X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("age", gremlingo.P.Gte(gremlingo.T__.V(p["vid3"]).Values("age")))}},
+ "g_V_hasXage_eqXVXvid1X_valuesXnonexistentXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("age", gremlingo.P.Eq(gremlingo.T__.V(p["vid1"]).Values("nonexistent")))}},
+ "g_V_hasXlabel_VXvid1X_labelXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has(gremlingo.T.Label, gremlingo.T__.V(p["vid1"]).Label())}},
+ "g_V_hasXperson_name_VXvid1X_valuesXnameXX_age": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("person", "name", gremlingo.T__.V(p["vid1"]).Values("name")).Values("age")}},
"g_V_properties_hasValueXnullX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Properties().HasValue(nil)}},
"g_V_properties_hasValueXnull_nullX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Properties().HasValue(nil, nil)}},
"g_V_properties_hasValueXnull_joshX_value": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Properties().HasValue(nil, "josh").Value()}},
@@ -1749,6 +1764,16 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[
"g_V_localXoutE_foldX_unfold": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Local(gremlingo.T__.OutE().Fold()).Unfold()}},
"g_V_valueMap_unfold_mapXselectXkeysXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().ValueMap().Unfold().Map(gremlingo.T__.Select(gremlingo.Column.Keys))}},
"g_VX1X_repeatXboth_simplePathX_untilXhasIdX6XX_path_byXnameX_unfold": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Repeat(gremlingo.T__.Both().SimplePath()).Until(gremlingo.T__.HasId(p["vid6"])).Path().By("name").Unfold()}},
+ "g_VXvid1X_outXcreatedX_asXsoftwareX_V_hasXname_selectXsoftwareX_valuesXnameXX_inXcreatedX_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Out("created").As("sw").V().Has("name", gremlingo.T__.Select("sw").Values("name")).In("created").Values("name")}},
+ "g_VXvid1X_VXoutXknowsX_idX_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).V(gremlingo.T__.Out("knows").Id()).Values("name")}},
+ "g_VXvid1X_VXoutXknowsX_hasXname_joshX_idX_valuesXageX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).V(gremlingo.T__.Out("knows").Has("name", "josh").Id()).Values("age")}},
+ "g_VXvid1X_VXoutXknowsX_outXknowsX_idX_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).V(gremlingo.T__.Out("knows").Out("knows").Id()).Values("name")}},
+ "g_VXvid1X_VXoutXcreatedX_idX_valuesXlangX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).V(gremlingo.T__.Out("created").Id()).Values("lang")}},
+ "g_VXvid1X_EXoutE_idX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).E(gremlingo.T__.OutE().Id())}},
+ "g_VXvid1X_EXoutEXknowsX_hasXweight_05X_idX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).E(gremlingo.T__.OutE("knows").Has("weight", 0.5).Id())}},
+ "g_VXvid1X_EXoutXknowsX_outXknowsX_outE_idX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).E(gremlingo.T__.Out("knows").Out("knows").OutE().Id())}},
+ "g_VXVXvid1X_idX_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(gremlingo.T__.V(p["vid1"]).Id()).Values("name")}},
+ "g_EXVXvid1X_outE_idX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E(gremlingo.T__.V(p["vid1"]).OutE().Id())}},
"g_V_valueMap": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().ValueMap()}},
"g_V_valueMapXtrueX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().ValueMap(true)}},
"g_V_valueMap_withXtokensX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().ValueMap().With(gremlingo.WithOptions.Tokens)}},
@@ -2070,6 +2095,17 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[
"g_injectX1_3_100_300X_list": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject([]interface{}{1, 3, 100, 300})}},
"g_injectX1_3_100_300X_set": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(gremlingo.NewSimpleSet(1, 3, 100, 300))}},
"g_injectX1_1X_set": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(gremlingo.NewSimpleSet(1, 1))}},
+ "g_VXvid2X_propertyXalias_VXvid1X_valuesXnameXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid2"]).Property("alias", gremlingo.T__.V(p["vid1"]).Values("name"))}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("alias", "marko")}},
+ "g_VXvid1X_propertyXcreatorCount_VXvid1X_inXcreatedX_countX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Property("creatorCount", gremlingo.T__.V(p["vid1"]).In("created").Count())}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("creatorCount", int64(3))}},
+ "g_VXvid1X_propertyXknownCount_outXknowsX_countX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Property("knownCount", gremlingo.T__.Out("knows").Count())}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("knownCount", int64(2))}},
+ "g_VXvid1X_propertyXcreator_inXcreatedX_valuesXnameXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Property("creator", gremlingo.T__.In("created").Values("name"))}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("creator")}},
+ "g_VXvid2X_propertyXVXvid1X_projectXfriendCount_softwareCreatedXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid2"]).Property(gremlingo.T__.V(p["vid1"]).Project("friendCount", "softwareCreated").By(gremlingo.T__.Out("knows").Count()).By(gremlingo.T__.Out("created").Values("name")))}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("friendCount", int64(2))}, [...]
+ "g_VXvid2X_propertyXVXvid1X_projectXoriginalName_originalLabelX_byXnameX_byXlabelXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid2"]).Property(gremlingo.T__.V(p["vid1"]).Project("originalName", "originalLabel").By(gremlingo.T__.Values("name")).By(gremlingo.T__.Label()))}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid2"]).Has("originalName", "marko")}, f [...]
+ "g_VXvid1X_propertyXlist_friends_outXknowsX_valuesXnameXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Property(gremlingo.Cardinality.List, "friends", gremlingo.T__.Out("knows").Values("name"))}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Properties("friends")}},
+ "g_VXvid1X_propertyXlist_creators_inXcreatedX_valuesXnameXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Property(gremlingo.Cardinality.List, "creators", gremlingo.T__.In("created").Values("name"))}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Properties("creators")}},
+ "g_VXvid1X_propertyXset_langs_outXcreatedX_valuesXlangXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Property(gremlingo.Cardinality.Set, "langs", gremlingo.T__.Out("created").Values("lang"))}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Properties("langs")}},
+ "g_VXvid1X_propertyXsingle_friend_outXknowsX_valuesXnameXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Property(gremlingo.Cardinality.Single, "friend", gremlingo.T__.Out("knows").Values("name"))}},
+ "g_VXvid1X_propertyXVXvid1X_groupX_byXidX_byXvaluesXnameXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Property(gremlingo.T__.V(p["vid1"]).Group().By(gremlingo.T__.Id()).By(gremlingo.T__.Values("name")))}},
"g_io_readXkryoX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Io("data/tinkerpop-modern.kryo").Read()}, 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()}},
"g_io_read_withXreader_gryoX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Io("data/tinkerpop-modern.kryo").With(gremlingo.IO.Reader, gremlingo.IO.Gryo).Read()}, 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()}},
"g_io_readXgraphsonX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Io("data/tinkerpop-modern.json").Read()}, 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()}},
diff --git a/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js b/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js
index aef279b28a..1247cbe825 100644
--- a/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js
+++ b/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js
@@ -533,6 +533,21 @@ const gremlins = {
g_E_hasXlabel_nullX: [function({g}) { return g.E().has(T.label, null) }],
g_V_properties_hasLabelXnullX: [function({g}) { return g.V().properties().hasLabel(null) }],
g_V_hasNotXageX_name: [function({g}) { return g.V().hasNot("age").values("name") }],
+ g_V_hasXname_VXvid1X_valuesXnameXX: [function({g, vid1}) { return g.V().has("name", __.V(vid1).values("name")) }],
+ g_V_hasXname_VXvid1X_outXknowsX_valuesXnameXX: [function({g, vid1}) { return g.V().has("name", __.V(vid1).out("knows").values("name")) }],
+ g_V_hasXage_VXvid1X_outXknowsX_valuesXageXX: [function({g, vid1}) { return g.V().has("age", __.V(vid1).out("knows").values("age")) }],
+ g_V_hasXname_VXvid1X_outXcreatedX_valuesXnameXX: [function({g, vid1}) { return g.V().has("name", __.V(vid1).out("created").values("name")) }],
+ g_V_hasXname_VXvid1X_valuesXnonexistentXX: [function({g, vid1}) { return g.V().has("name", __.V(vid1).values("nonexistent")) }],
+ g_V_hasXname_notXidentityXX: [function({g}) { return g.V().has("name", __.not(__.identity())) }],
+ g_V_hasXage_gtXVXvid1X_valuesXageXXX: [function({g, vid1}) { return g.V().has("age", P.gt(__.V(vid1).values("age"))) }],
+ g_V_hasXage_lteXVXvid2X_valuesXageXXX: [function({g, vid2}) { return g.V().has("age", P.lte(__.V(vid2).values("age"))) }],
+ g_V_hasXage_neqXVXvid3X_valuesXageXXX: [function({g, vid3}) { return g.V().has("age", P.neq(__.V(vid3).values("age"))) }],
+ g_V_hasXname_eqXVXvid1X_valuesXnameXXX: [function({g, vid1}) { return g.V().has("name", P.eq(__.V(vid1).values("name"))) }],
+ g_V_hasXage_ltXVXvid1X_valuesXageXXX: [function({g, vid1}) { return g.V().has("age", P.lt(__.V(vid1).values("age"))) }],
+ g_V_hasXage_gteXVXvid3X_valuesXageXXX: [function({g, vid3}) { return g.V().has("age", P.gte(__.V(vid3).values("age"))) }],
+ g_V_hasXage_eqXVXvid1X_valuesXnonexistentXXX: [function({g, vid1}) { return g.V().has("age", P.eq(__.V(vid1).values("nonexistent"))) }],
+ g_V_hasXlabel_VXvid1X_labelXX: [function({g, vid1}) { return g.V().has(T.label, __.V(vid1).label()) }],
+ g_V_hasXperson_name_VXvid1X_valuesXnameXX_age: [function({g, vid1}) { return g.V().has("person", "name", __.V(vid1).values("name")).values("age") }],
g_V_properties_hasValueXnullX: [function({g}) { return g.V().properties().hasValue(null) }],
g_V_properties_hasValueXnull_nullX: [function({g}) { return g.V().properties().hasValue(null, null) }],
g_V_properties_hasValueXnull_joshX_value: [function({g}) { return g.V().properties().hasValue(null, "josh").value() }],
@@ -1780,6 +1795,16 @@ const gremlins = {
g_V_localXoutE_foldX_unfold: [function({g}) { return g.V().local(__.outE().fold()).unfold() }],
g_V_valueMap_unfold_mapXselectXkeysXX: [function({g}) { return g.V().valueMap().unfold().map(__.select(Column.keys)) }],
g_VX1X_repeatXboth_simplePathX_untilXhasIdX6XX_path_byXnameX_unfold: [function({g, vid6, vid1}) { return g.V(vid1).repeat(__.both().simplePath()).until(__.hasId(vid6)).path().by("name").unfold() }],
+ g_VXvid1X_outXcreatedX_asXsoftwareX_V_hasXname_selectXsoftwareX_valuesXnameXX_inXcreatedX_name: [function({g, vid1}) { return g.V(vid1).out("created").as("sw").V().has("name", __.select("sw").values("name")).in_("created").values("name") }],
+ g_VXvid1X_VXoutXknowsX_idX_name: [function({g, vid1}) { return g.V(vid1).V(__.out("knows").id()).values("name") }],
+ g_VXvid1X_VXoutXknowsX_hasXname_joshX_idX_valuesXageX: [function({g, vid1}) { return g.V(vid1).V(__.out("knows").has("name", "josh").id()).values("age") }],
+ g_VXvid1X_VXoutXknowsX_outXknowsX_idX_name: [function({g, vid1}) { return g.V(vid1).V(__.out("knows").out("knows").id()).values("name") }],
+ g_VXvid1X_VXoutXcreatedX_idX_valuesXlangX: [function({g, vid1}) { return g.V(vid1).V(__.out("created").id()).values("lang") }],
+ g_VXvid1X_EXoutE_idX: [function({g, vid1}) { return g.V(vid1).E(__.outE().id()) }],
+ g_VXvid1X_EXoutEXknowsX_hasXweight_05X_idX: [function({g, vid1}) { return g.V(vid1).E(__.outE("knows").has("weight", 0.5).id()) }],
+ g_VXvid1X_EXoutXknowsX_outXknowsX_outE_idX: [function({g, vid1}) { return g.V(vid1).E(__.out("knows").out("knows").outE().id()) }],
+ g_VXVXvid1X_idX_name: [function({g, vid1}) { return g.V(__.V(vid1).id()).values("name") }],
+ g_EXVXvid1X_outE_idX: [function({g, vid1}) { return g.E(__.V(vid1).outE().id()) }],
g_V_valueMap: [function({g}) { return g.V().valueMap() }],
g_V_valueMapXtrueX: [function({g}) { return g.V().valueMap(true) }],
g_V_valueMap_withXtokensX: [function({g}) { return g.V().valueMap().with_(WithOptions.tokens) }],
@@ -2101,6 +2126,17 @@ const gremlins = {
g_injectX1_3_100_300X_list: [function({g}) { return g.inject([1, 3, 100, 300]) }],
g_injectX1_3_100_300X_set: [function({g}) { return g.inject(new Set([1, 3, 100, 300])) }],
g_injectX1_1X_set: [function({g}) { return g.inject(new Set([1, 1])) }],
+ g_VXvid2X_propertyXalias_VXvid1X_valuesXnameXX: [function({g, vid2, vid1}) { return g.V(vid2).property("alias", __.V(vid1).values("name")) }, function({g, vid2, vid1}) { return g.V().has("alias", "marko") }],
+ g_VXvid1X_propertyXcreatorCount_VXvid1X_inXcreatedX_countX: [function({g, vid1}) { return g.V(vid1).property("creatorCount", __.V(vid1).in_("created").count()) }, function({g, vid1}) { return g.V().has("creatorCount", 3) }],
+ g_VXvid1X_propertyXknownCount_outXknowsX_countX: [function({g, vid1}) { return g.V(vid1).property("knownCount", __.out("knows").count()) }, function({g, vid1}) { return g.V().has("knownCount", 2) }],
+ g_VXvid1X_propertyXcreator_inXcreatedX_valuesXnameXX: [function({g, vid1}) { return g.V(vid1).property("creator", __.in_("created").values("name")) }, function({g, vid1}) { return g.V().has("creator") }],
+ g_VXvid2X_propertyXVXvid1X_projectXfriendCount_softwareCreatedXX: [function({g, vid2, vid1}) { return g.V(vid2).property(__.V(vid1).project("friendCount", "softwareCreated").by(__.out("knows").count()).by(__.out("created").values("name"))) }, function({g, vid2, vid1}) { return g.V().has("friendCount", 2) }, function({g, vid2, vid1}) { return g.V().has("softwareCreated", "lop") }],
+ g_VXvid2X_propertyXVXvid1X_projectXoriginalName_originalLabelX_byXnameX_byXlabelXX: [function({g, vid2, vid1}) { return g.V(vid2).property(__.V(vid1).project("originalName", "originalLabel").by(__.values("name")).by(__.label())) }, function({g, vid2, vid1}) { return g.V(vid2).has("originalName", "marko") }, function({g, vid2, vid1}) { return g.V(vid2).has("originalLabel", "person") }],
+ g_VXvid1X_propertyXlist_friends_outXknowsX_valuesXnameXX: [function({g, vid1}) { return g.V(vid1).property(Cardinality.list, "friends", __.out("knows").values("name")) }, function({g, vid1}) { return g.V(vid1).properties("friends") }],
+ g_VXvid1X_propertyXlist_creators_inXcreatedX_valuesXnameXX: [function({g, vid1}) { return g.V(vid1).property(Cardinality.list, "creators", __.in_("created").values("name")) }, function({g, vid1}) { return g.V(vid1).properties("creators") }],
+ g_VXvid1X_propertyXset_langs_outXcreatedX_valuesXlangXX: [function({g, vid1}) { return g.V(vid1).property(Cardinality.set, "langs", __.out("created").values("lang")) }, function({g, vid1}) { return g.V(vid1).properties("langs") }],
+ g_VXvid1X_propertyXsingle_friend_outXknowsX_valuesXnameXX: [function({g, vid1}) { return g.V(vid1).property(Cardinality.single, "friend", __.out("knows").values("name")) }],
+ g_VXvid1X_propertyXVXvid1X_groupX_byXidX_byXvaluesXnameXXX: [function({g, vid1}) { return g.V(vid1).property(__.V(vid1).group().by(__.id()).by(__.values("name"))) }],
g_io_readXkryoX: [function({g}) { return g.io("data/tinkerpop-modern.kryo").read() }, function({g}) { return g.V() }, function({g}) { return g.E() }],
g_io_read_withXreader_gryoX: [function({g}) { return g.io("data/tinkerpop-modern.kryo").with_(IO.reader, IO.gryo).read() }, function({g}) { return g.V() }, function({g}) { return g.E() }],
g_io_readXgraphsonX: [function({g}) { return g.io("data/tinkerpop-modern.json").read() }, function({g}) { return g.V() }, function({g}) { return g.E() }],
diff --git a/gremlin-language/src/main/antlr4/Gremlin.g4 b/gremlin-language/src/main/antlr4/Gremlin.g4
index 6798ebde55..822cb59481 100644
--- a/gremlin-language/src/main/antlr4/Gremlin.g4
+++ b/gremlin-language/src/main/antlr4/Gremlin.g4
@@ -123,10 +123,12 @@ traversalSourceSpawnMethod_addV
traversalSourceSpawnMethod_E
: K_E LPAREN genericArgumentVarargs RPAREN
+ | K_E LPAREN nestedTraversal RPAREN
;
traversalSourceSpawnMethod_V
: K_V LPAREN genericArgumentVarargs RPAREN
+ | K_V LPAREN nestedTraversal RPAREN
;
traversalSourceSpawnMethod_inject
@@ -313,10 +315,12 @@ traversalMethod
traversalMethod_V
: K_V LPAREN genericArgumentVarargs RPAREN
+ | K_V LPAREN nestedTraversal RPAREN
;
traversalMethod_E
: K_E LPAREN genericArgumentVarargs RPAREN
+ | K_E LPAREN nestedTraversal RPAREN
;
traversalMethod_addE
@@ -547,10 +551,13 @@ traversalMethod_has
: K_HAS LPAREN stringNullableLiteral RPAREN #traversalMethod_has_String
| K_HAS LPAREN stringNullableLiteral COMMA genericArgument RPAREN #traversalMethod_has_String_Object
| K_HAS LPAREN stringNullableLiteral COMMA traversalPredicate RPAREN #traversalMethod_has_String_P
+ | K_HAS LPAREN stringNullableLiteral COMMA nestedTraversal RPAREN #traversalMethod_has_String_Traversal
| K_HAS LPAREN stringNullableArgument COMMA stringNullableLiteral COMMA genericArgument RPAREN #traversalMethod_has_String_String_Object
| K_HAS LPAREN stringNullableArgument COMMA stringNullableLiteral COMMA traversalPredicate RPAREN #traversalMethod_has_String_String_P
+ | K_HAS LPAREN stringNullableArgument COMMA stringNullableLiteral COMMA nestedTraversal RPAREN #traversalMethod_has_String_String_Traversal
| K_HAS LPAREN traversalT COMMA genericArgument RPAREN #traversalMethod_has_T_Object
| K_HAS LPAREN traversalT COMMA traversalPredicate RPAREN #traversalMethod_has_T_P
+ | K_HAS LPAREN traversalT COMMA nestedTraversal RPAREN #traversalMethod_has_T_Traversal
;
traversalMethod_hasId
@@ -767,9 +774,12 @@ traversalMethod_properties
traversalMethod_property
: K_PROPERTY LPAREN traversalCardinality COMMA genericLiteral COMMA genericArgument (COMMA genericArgumentVarargs)? RPAREN #traversalMethod_property_Cardinality_Object_Object_Object
+ | K_PROPERTY LPAREN traversalCardinality COMMA genericLiteral COMMA nestedTraversal RPAREN #traversalMethod_property_Cardinality_Object_Traversal
| K_PROPERTY LPAREN traversalCardinality COMMA genericMapNullableArgument RPAREN # traversalMethod_property_Cardinality_Object
| K_PROPERTY LPAREN genericLiteral COMMA genericArgument (COMMA genericArgumentVarargs)? RPAREN #traversalMethod_property_Object_Object_Object
+ | K_PROPERTY LPAREN genericLiteral COMMA nestedTraversal RPAREN #traversalMethod_property_Object_Traversal
| K_PROPERTY LPAREN genericMapNullableArgument RPAREN # traversalMethod_property_Object
+ | K_PROPERTY LPAREN nestedTraversal RPAREN #traversalMethod_property_Traversal
;
traversalMethod_propertyMap
@@ -1187,10 +1197,12 @@ traversalBiFunction
traversalPredicate_eq
: (K_P DOT K_EQ | K_EQ) LPAREN genericArgument RPAREN
+ | (K_P DOT K_EQ | K_EQ) LPAREN nestedTraversal RPAREN
;
traversalPredicate_neq
: (K_P DOT K_NEQ | K_NEQ) LPAREN genericArgument RPAREN
+ | (K_P DOT K_NEQ | K_NEQ) LPAREN nestedTraversal RPAREN
;
traversalPredicate_typeOf
@@ -1200,40 +1212,49 @@ traversalPredicate_typeOf
traversalPredicate_lt
: (K_P DOT K_LT | K_LT) LPAREN genericArgument RPAREN
+ | (K_P DOT K_LT | K_LT) LPAREN nestedTraversal RPAREN
;
traversalPredicate_lte
: (K_P DOT K_LTE | K_LTE) LPAREN genericArgument RPAREN
+ | (K_P DOT K_LTE | K_LTE) LPAREN nestedTraversal RPAREN
;
traversalPredicate_gt
: (K_P DOT K_GT | K_GT) LPAREN genericArgument RPAREN
+ | (K_P DOT K_GT | K_GT) LPAREN nestedTraversal RPAREN
;
traversalPredicate_gte
: (K_P DOT K_GTE | K_GTE) LPAREN genericArgument RPAREN
+ | (K_P DOT K_GTE | K_GTE) LPAREN nestedTraversal RPAREN
;
traversalPredicate_inside
: (K_P DOT K_INSIDE | K_INSIDE) LPAREN genericArgument COMMA genericArgument RPAREN
+ | (K_P DOT K_INSIDE | K_INSIDE) LPAREN nestedTraversal COMMA nestedTraversal RPAREN
;
traversalPredicate_outside
: (K_P DOT K_OUTSIDE | K_OUTSIDE) LPAREN genericArgument COMMA genericArgument RPAREN
+ | (K_P DOT K_OUTSIDE | K_OUTSIDE) LPAREN nestedTraversal COMMA nestedTraversal RPAREN
;
traversalPredicate_between
: (K_P DOT K_BETWEEN | K_BETWEEN) LPAREN genericArgument COMMA genericArgument RPAREN
+ | (K_P DOT K_BETWEEN | K_BETWEEN) LPAREN nestedTraversal COMMA nestedTraversal RPAREN
;
traversalPredicate_within
: (K_P DOT K_WITHIN | K_WITHIN) LPAREN RPAREN
| (K_P DOT K_WITHIN | K_WITHIN) LPAREN genericArgumentVarargs RPAREN
+ | (K_P DOT K_WITHIN | K_WITHIN) LPAREN nestedTraversal RPAREN
;
traversalPredicate_without
: (K_P DOT K_WITHOUT | K_WITHOUT) LPAREN RPAREN
| (K_P DOT K_WITHOUT | K_WITHOUT) LPAREN genericArgumentVarargs RPAREN
+ | (K_P DOT K_WITHOUT | K_WITHOUT) LPAREN nestedTraversal RPAREN
;
traversalPredicate_not
@@ -1242,26 +1263,32 @@ traversalPredicate_not
traversalPredicate_containing
: (K_TEXTP DOT K_CONTAINING | K_CONTAINING) LPAREN stringArgument RPAREN
+ | (K_TEXTP DOT K_CONTAINING | K_CONTAINING) LPAREN nestedTraversal RPAREN
;
traversalPredicate_notContaining
: (K_TEXTP DOT K_NOTCONTAINING | K_NOTCONTAINING) LPAREN stringArgument RPAREN
+ | (K_TEXTP DOT K_NOTCONTAINING | K_NOTCONTAINING) LPAREN nestedTraversal RPAREN
;
traversalPredicate_startingWith
: (K_TEXTP DOT K_STARTINGWITH | K_STARTINGWITH) LPAREN stringArgument RPAREN
+ | (K_TEXTP DOT K_STARTINGWITH | K_STARTINGWITH) LPAREN nestedTraversal RPAREN
;
traversalPredicate_notStartingWith
: (K_TEXTP DOT K_NOTSTARTINGWITH | K_NOTSTARTINGWITH) LPAREN stringArgument RPAREN
+ | (K_TEXTP DOT K_NOTSTARTINGWITH | K_NOTSTARTINGWITH) LPAREN nestedTraversal RPAREN
;
traversalPredicate_endingWith
: (K_TEXTP DOT K_ENDINGWITH | K_ENDINGWITH) LPAREN stringArgument RPAREN
+ | (K_TEXTP DOT K_ENDINGWITH | K_ENDINGWITH) LPAREN nestedTraversal RPAREN
;
traversalPredicate_notEndingWith
: (K_TEXTP DOT K_NOTENDINGWITH | K_NOTENDINGWITH) LPAREN stringArgument RPAREN
+ | (K_TEXTP DOT K_NOTENDINGWITH | K_NOTENDINGWITH) LPAREN nestedTraversal RPAREN
;
traversalPredicate_regex
diff --git a/gremlin-python/src/main/python/tests/feature/gremlin.py b/gremlin-python/src/main/python/tests/feature/gremlin.py
index 8dd5394e02..5d33607174 100644
--- a/gremlin-python/src/main/python/tests/feature/gremlin.py
+++ b/gremlin-python/src/main/python/tests/feature/gremlin.py
@@ -507,6 +507,21 @@ world.gremlins = {
'g_E_hasXlabel_nullX': [(lambda g:g.E().has(T.label, None))],
'g_V_properties_hasLabelXnullX': [(lambda g:g.V().properties().has_label(None))],
'g_V_hasNotXageX_name': [(lambda g:g.V().has_not('age').values('name'))],
+ 'g_V_hasXname_VXvid1X_valuesXnameXX': [(lambda g, vid1=None:g.V().has('name', __.V(vid1).values('name')))],
+ 'g_V_hasXname_VXvid1X_outXknowsX_valuesXnameXX': [(lambda g, vid1=None:g.V().has('name', __.V(vid1).out('knows').values('name')))],
+ 'g_V_hasXage_VXvid1X_outXknowsX_valuesXageXX': [(lambda g, vid1=None:g.V().has('age', __.V(vid1).out('knows').values('age')))],
+ 'g_V_hasXname_VXvid1X_outXcreatedX_valuesXnameXX': [(lambda g, vid1=None:g.V().has('name', __.V(vid1).out('created').values('name')))],
+ 'g_V_hasXname_VXvid1X_valuesXnonexistentXX': [(lambda g, vid1=None:g.V().has('name', __.V(vid1).values('nonexistent')))],
+ 'g_V_hasXname_notXidentityXX': [(lambda g:g.V().has('name', __.not_(__.identity())))],
+ 'g_V_hasXage_gtXVXvid1X_valuesXageXXX': [(lambda g, vid1=None:g.V().has('age', P.gt(__.V(vid1).values('age'))))],
+ 'g_V_hasXage_lteXVXvid2X_valuesXageXXX': [(lambda g, vid2=None:g.V().has('age', P.lte(__.V(vid2).values('age'))))],
+ 'g_V_hasXage_neqXVXvid3X_valuesXageXXX': [(lambda g, vid3=None:g.V().has('age', P.neq(__.V(vid3).values('age'))))],
+ 'g_V_hasXname_eqXVXvid1X_valuesXnameXXX': [(lambda g, vid1=None:g.V().has('name', P.eq(__.V(vid1).values('name'))))],
+ 'g_V_hasXage_ltXVXvid1X_valuesXageXXX': [(lambda g, vid1=None:g.V().has('age', P.lt(__.V(vid1).values('age'))))],
+ 'g_V_hasXage_gteXVXvid3X_valuesXageXXX': [(lambda g, vid3=None:g.V().has('age', P.gte(__.V(vid3).values('age'))))],
+ 'g_V_hasXage_eqXVXvid1X_valuesXnonexistentXXX': [(lambda g, vid1=None:g.V().has('age', P.eq(__.V(vid1).values('nonexistent'))))],
+ 'g_V_hasXlabel_VXvid1X_labelXX': [(lambda g, vid1=None:g.V().has(T.label, __.V(vid1).label()))],
+ 'g_V_hasXperson_name_VXvid1X_valuesXnameXX_age': [(lambda g, vid1=None:g.V().has('person', 'name', __.V(vid1).values('name')).values('age'))],
'g_V_properties_hasValueXnullX': [(lambda g:g.V().properties().has_value(None))],
'g_V_properties_hasValueXnull_nullX': [(lambda g:g.V().properties().has_value(None, None))],
'g_V_properties_hasValueXnull_joshX_value': [(lambda g:g.V().properties().has_value(None, 'josh').value())],
@@ -1754,6 +1769,16 @@ world.gremlins = {
'g_V_localXoutE_foldX_unfold': [(lambda g:g.V().local(__.out_e().fold()).unfold())],
'g_V_valueMap_unfold_mapXselectXkeysXX': [(lambda g:g.V().value_map().unfold().map(__.select(Column.keys)))],
'g_VX1X_repeatXboth_simplePathX_untilXhasIdX6XX_path_byXnameX_unfold': [(lambda g, vid6=None,vid1=None:g.V(vid1).repeat(__.both().simple_path()).until(__.has_id(vid6)).path().by('name').unfold())],
+ 'g_VXvid1X_outXcreatedX_asXsoftwareX_V_hasXname_selectXsoftwareX_valuesXnameXX_inXcreatedX_name': [(lambda g, vid1=None:g.V(vid1).out('created').as_('sw').V().has('name', __.select('sw').values('name')).in_('created').values('name'))],
+ 'g_VXvid1X_VXoutXknowsX_idX_name': [(lambda g, vid1=None:g.V(vid1).V(__.out('knows').id_()).values('name'))],
+ 'g_VXvid1X_VXoutXknowsX_hasXname_joshX_idX_valuesXageX': [(lambda g, vid1=None:g.V(vid1).V(__.out('knows').has('name', 'josh').id_()).values('age'))],
+ 'g_VXvid1X_VXoutXknowsX_outXknowsX_idX_name': [(lambda g, vid1=None:g.V(vid1).V(__.out('knows').out('knows').id_()).values('name'))],
+ 'g_VXvid1X_VXoutXcreatedX_idX_valuesXlangX': [(lambda g, vid1=None:g.V(vid1).V(__.out('created').id_()).values('lang'))],
+ 'g_VXvid1X_EXoutE_idX': [(lambda g, vid1=None:g.V(vid1).E(__.out_e().id_()))],
+ 'g_VXvid1X_EXoutEXknowsX_hasXweight_05X_idX': [(lambda g, vid1=None:g.V(vid1).E(__.out_e('knows').has('weight', 0.5).id_()))],
+ 'g_VXvid1X_EXoutXknowsX_outXknowsX_outE_idX': [(lambda g, vid1=None:g.V(vid1).E(__.out('knows').out('knows').out_e().id_()))],
+ 'g_VXVXvid1X_idX_name': [(lambda g, vid1=None:g.V(__.V(vid1).id_()).values('name'))],
+ 'g_EXVXvid1X_outE_idX': [(lambda g, vid1=None:g.E(__.V(vid1).out_e().id_()))],
'g_V_valueMap': [(lambda g:g.V().value_map())],
'g_V_valueMapXtrueX': [(lambda g:g.V().value_map(True))],
'g_V_valueMap_withXtokensX': [(lambda g:g.V().value_map().with_(WithOptions.tokens))],
@@ -2075,6 +2100,17 @@ world.gremlins = {
'g_injectX1_3_100_300X_list': [(lambda g:g.inject([1, 3, 100, 300]))],
'g_injectX1_3_100_300X_set': [(lambda g:g.inject({1, 3, 100, 300}))],
'g_injectX1_1X_set': [(lambda g:g.inject({1, 1}))],
+ 'g_VXvid2X_propertyXalias_VXvid1X_valuesXnameXX': [(lambda g, vid2=None,vid1=None:g.V(vid2).property('alias', __.V(vid1).values('name'))), (lambda g, vid2=None,vid1=None:g.V().has('alias', 'marko'))],
+ 'g_VXvid1X_propertyXcreatorCount_VXvid1X_inXcreatedX_countX': [(lambda g, vid1=None:g.V(vid1).property('creatorCount', __.V(vid1).in_('created').count())), (lambda g, vid1=None:g.V().has('creatorCount', long(3)))],
+ 'g_VXvid1X_propertyXknownCount_outXknowsX_countX': [(lambda g, vid1=None:g.V(vid1).property('knownCount', __.out('knows').count())), (lambda g, vid1=None:g.V().has('knownCount', long(2)))],
+ 'g_VXvid1X_propertyXcreator_inXcreatedX_valuesXnameXX': [(lambda g, vid1=None:g.V(vid1).property('creator', __.in_('created').values('name'))), (lambda g, vid1=None:g.V().has('creator'))],
+ 'g_VXvid2X_propertyXVXvid1X_projectXfriendCount_softwareCreatedXX': [(lambda g, vid2=None,vid1=None:g.V(vid2).property(__.V(vid1).project('friendCount', 'softwareCreated').by(__.out('knows').count()).by(__.out('created').values('name')))), (lambda g, vid2=None,vid1=None:g.V().has('friendCount', long(2))), (lambda g, vid2=None,vid1=None:g.V().has('softwareCreated', 'lop'))],
+ 'g_VXvid2X_propertyXVXvid1X_projectXoriginalName_originalLabelX_byXnameX_byXlabelXX': [(lambda g, vid2=None,vid1=None:g.V(vid2).property(__.V(vid1).project('originalName', 'originalLabel').by(__.values('name')).by(__.label()))), (lambda g, vid2=None,vid1=None:g.V(vid2).has('originalName', 'marko')), (lambda g, vid2=None,vid1=None:g.V(vid2).has('originalLabel', 'person'))],
+ 'g_VXvid1X_propertyXlist_friends_outXknowsX_valuesXnameXX': [(lambda g, vid1=None:g.V(vid1).property(Cardinality.list_, 'friends', __.out('knows').values('name'))), (lambda g, vid1=None:g.V(vid1).properties('friends'))],
+ 'g_VXvid1X_propertyXlist_creators_inXcreatedX_valuesXnameXX': [(lambda g, vid1=None:g.V(vid1).property(Cardinality.list_, 'creators', __.in_('created').values('name'))), (lambda g, vid1=None:g.V(vid1).properties('creators'))],
+ 'g_VXvid1X_propertyXset_langs_outXcreatedX_valuesXlangXX': [(lambda g, vid1=None:g.V(vid1).property(Cardinality.set_, 'langs', __.out('created').values('lang'))), (lambda g, vid1=None:g.V(vid1).properties('langs'))],
+ 'g_VXvid1X_propertyXsingle_friend_outXknowsX_valuesXnameXX': [(lambda g, vid1=None:g.V(vid1).property(Cardinality.single, 'friend', __.out('knows').values('name')))],
+ 'g_VXvid1X_propertyXVXvid1X_groupX_byXidX_byXvaluesXnameXXX': [(lambda g, vid1=None:g.V(vid1).property(__.V(vid1).group().by(__.id_()).by(__.values('name'))))],
'g_io_readXkryoX': [(lambda g:g.io('data/tinkerpop-modern.kryo').read()), (lambda g:g.V()), (lambda g:g.E())],
'g_io_read_withXreader_gryoX': [(lambda g:g.io('data/tinkerpop-modern.kryo').with_(IO.reader, IO.gryo).read()), (lambda g:g.V()), (lambda g:g.E())],
'g_io_readXgraphsonX': [(lambda g:g.io('data/tinkerpop-modern.json').read()), (lambda g:g.V()), (lambda g:g.E())],
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json
index 3c9c17c495..d1305a85ce 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json
@@ -9262,6 +9262,244 @@
}
]
},
+ {
+ "scenario": "g_V_hasXname_VXvid1X_valuesXnameXX",
+ "traversals": [
+ {
+ "original": "g.V().has(\"name\", __.V(vid1).values(\"name\"))",
+ "language": "g.V().has(\"name\", __.V(vid1).values(\"name\"))",
+ "canonical": "g.V().has(\"name\", __.V(vid1).values(\"name\"))",
+ "anonymized": "g.V().has(string0, __.V(vid1).values(string0))",
+ "dotnet": "g.V().Has(\"name\", __.V(vid1).Values<object>(\"name\"))",
+ "go": "g.V().Has(\"name\", gremlingo.T__.V(vid1).Values(\"name\"))",
+ "groovy": "g.V().has(\"name\", __.V(vid1).values(\"name\"))",
+ "java": "g.V().has(\"name\", __.V(vid1).values(\"name\"))",
+ "javascript": "g.V().has(\"name\", __.V(vid1).values(\"name\"))",
+ "python": "g.V().has('name', __.V(vid1).values('name'))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_hasXname_VXvid1X_outXknowsX_valuesXnameXX",
+ "traversals": [
+ {
+ "original": "g.V().has(\"name\", __.V(vid1).out(\"knows\").values(\"name\"))",
+ "language": "g.V().has(\"name\", __.V(vid1).out(\"knows\").values(\"name\"))",
+ "canonical": "g.V().has(\"name\", __.V(vid1).out(\"knows\").values(\"name\"))",
+ "anonymized": "g.V().has(string0, __.V(vid1).out(string1).values(string0))",
+ "dotnet": "g.V().Has(\"name\", __.V(vid1).Out(\"knows\").Values<object>(\"name\"))",
+ "go": "g.V().Has(\"name\", gremlingo.T__.V(vid1).Out(\"knows\").Values(\"name\"))",
+ "groovy": "g.V().has(\"name\", __.V(vid1).out(\"knows\").values(\"name\"))",
+ "java": "g.V().has(\"name\", __.V(vid1).out(\"knows\").values(\"name\"))",
+ "javascript": "g.V().has(\"name\", __.V(vid1).out(\"knows\").values(\"name\"))",
+ "python": "g.V().has('name', __.V(vid1).out('knows').values('name'))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_hasXage_VXvid1X_outXknowsX_valuesXageXX",
+ "traversals": [
+ {
+ "original": "g.V().has(\"age\", __.V(vid1).out(\"knows\").values(\"age\"))",
+ "language": "g.V().has(\"age\", __.V(vid1).out(\"knows\").values(\"age\"))",
+ "canonical": "g.V().has(\"age\", __.V(vid1).out(\"knows\").values(\"age\"))",
+ "anonymized": "g.V().has(string0, __.V(vid1).out(string1).values(string0))",
+ "dotnet": "g.V().Has(\"age\", __.V(vid1).Out(\"knows\").Values<object>(\"age\"))",
+ "go": "g.V().Has(\"age\", gremlingo.T__.V(vid1).Out(\"knows\").Values(\"age\"))",
+ "groovy": "g.V().has(\"age\", __.V(vid1).out(\"knows\").values(\"age\"))",
+ "java": "g.V().has(\"age\", __.V(vid1).out(\"knows\").values(\"age\"))",
+ "javascript": "g.V().has(\"age\", __.V(vid1).out(\"knows\").values(\"age\"))",
+ "python": "g.V().has('age', __.V(vid1).out('knows').values('age'))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_hasXname_VXvid1X_valuesXnonexistentXX",
+ "traversals": [
+ {
+ "original": "g.V().has(\"name\", __.V(vid1).values(\"nonexistent\"))",
+ "language": "g.V().has(\"name\", __.V(vid1).values(\"nonexistent\"))",
+ "canonical": "g.V().has(\"name\", __.V(vid1).values(\"nonexistent\"))",
+ "anonymized": "g.V().has(string0, __.V(vid1).values(string1))",
+ "dotnet": "g.V().Has(\"name\", __.V(vid1).Values<object>(\"nonexistent\"))",
+ "go": "g.V().Has(\"name\", gremlingo.T__.V(vid1).Values(\"nonexistent\"))",
+ "groovy": "g.V().has(\"name\", __.V(vid1).values(\"nonexistent\"))",
+ "java": "g.V().has(\"name\", __.V(vid1).values(\"nonexistent\"))",
+ "javascript": "g.V().has(\"name\", __.V(vid1).values(\"nonexistent\"))",
+ "python": "g.V().has('name', __.V(vid1).values('nonexistent'))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_hasXname_notXidentityXX",
+ "traversals": [
+ {
+ "original": "g.V().has(\"name\", __.not(__.identity()))",
+ "language": "g.V().has(\"name\", __.not(__.identity()))",
+ "canonical": "g.V().has(\"name\", __.not(__.identity()))",
+ "anonymized": "g.V().has(string0, __.not(__.identity()))",
+ "dotnet": "g.V().Has(\"name\", __.Not(__.Identity()))",
+ "go": "g.V().Has(\"name\", gremlingo.T__.Not(gremlingo.T__.Identity()))",
+ "groovy": "g.V().has(\"name\", __.not(__.identity()))",
+ "java": "g.V().has(\"name\", __.not(__.identity()))",
+ "javascript": "g.V().has(\"name\", __.not(__.identity()))",
+ "python": "g.V().has('name', __.not_(__.identity()))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_hasXage_gtXVXvid1X_valuesXageXXX",
+ "traversals": [
+ {
+ "original": "g.V().has(\"age\", P.gt(__.V(vid1).values(\"age\")))",
+ "language": "g.V().has(\"age\", P.gt(__.V(vid1).values(\"age\")))",
+ "canonical": "g.V().has(\"age\", P.gt(__.V(vid1).values(\"age\")))",
+ "anonymized": "g.V().has(string0, P.gt(__.V(vid1).values(string0)))",
+ "dotnet": "g.V().Has(\"age\", P.Gt(__.V(vid1).Values<object>(\"age\")))",
+ "go": "g.V().Has(\"age\", gremlingo.P.Gt(gremlingo.T__.V(vid1).Values(\"age\")))",
+ "groovy": "g.V().has(\"age\", P.gt(__.V(vid1).values(\"age\")))",
+ "java": "g.V().has(\"age\", P.gt(__.V(vid1).values(\"age\")))",
+ "javascript": "g.V().has(\"age\", P.gt(__.V(vid1).values(\"age\")))",
+ "python": "g.V().has('age', P.gt(__.V(vid1).values('age')))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_hasXage_lteXVXvid2X_valuesXageXXX",
+ "traversals": [
+ {
+ "original": "g.V().has(\"age\", P.lte(__.V(vid2).values(\"age\")))",
+ "language": "g.V().has(\"age\", P.lte(__.V(vid2).values(\"age\")))",
+ "canonical": "g.V().has(\"age\", P.lte(__.V(vid2).values(\"age\")))",
+ "anonymized": "g.V().has(string0, P.lte(__.V(vid2).values(string0)))",
+ "dotnet": "g.V().Has(\"age\", P.Lte(__.V(vid2).Values<object>(\"age\")))",
+ "go": "g.V().Has(\"age\", gremlingo.P.Lte(gremlingo.T__.V(vid2).Values(\"age\")))",
+ "groovy": "g.V().has(\"age\", P.lte(__.V(vid2).values(\"age\")))",
+ "java": "g.V().has(\"age\", P.lte(__.V(vid2).values(\"age\")))",
+ "javascript": "g.V().has(\"age\", P.lte(__.V(vid2).values(\"age\")))",
+ "python": "g.V().has('age', P.lte(__.V(vid2).values('age')))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_hasXage_neqXVXvid3X_valuesXageXXX",
+ "traversals": [
+ {
+ "original": "g.V().has(\"age\", P.neq(__.V(vid3).values(\"age\")))",
+ "language": "g.V().has(\"age\", P.neq(__.V(vid3).values(\"age\")))",
+ "canonical": "g.V().has(\"age\", P.neq(__.V(vid3).values(\"age\")))",
+ "anonymized": "g.V().has(string0, P.neq(__.V(vid3).values(string0)))",
+ "dotnet": "g.V().Has(\"age\", P.Neq(__.V(vid3).Values<object>(\"age\")))",
+ "go": "g.V().Has(\"age\", gremlingo.P.Neq(gremlingo.T__.V(vid3).Values(\"age\")))",
+ "groovy": "g.V().has(\"age\", P.neq(__.V(vid3).values(\"age\")))",
+ "java": "g.V().has(\"age\", P.neq(__.V(vid3).values(\"age\")))",
+ "javascript": "g.V().has(\"age\", P.neq(__.V(vid3).values(\"age\")))",
+ "python": "g.V().has('age', P.neq(__.V(vid3).values('age')))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_hasXname_eqXVXvid1X_valuesXnameXXX",
+ "traversals": [
+ {
+ "original": "g.V().has(\"name\", P.eq(__.V(vid1).values(\"name\")))",
+ "language": "g.V().has(\"name\", P.eq(__.V(vid1).values(\"name\")))",
+ "canonical": "g.V().has(\"name\", P.eq(__.V(vid1).values(\"name\")))",
+ "anonymized": "g.V().has(string0, P.eq(__.V(vid1).values(string0)))",
+ "dotnet": "g.V().Has(\"name\", P.Eq(__.V(vid1).Values<object>(\"name\")))",
+ "go": "g.V().Has(\"name\", gremlingo.P.Eq(gremlingo.T__.V(vid1).Values(\"name\")))",
+ "groovy": "g.V().has(\"name\", P.eq(__.V(vid1).values(\"name\")))",
+ "java": "g.V().has(\"name\", P.eq(__.V(vid1).values(\"name\")))",
+ "javascript": "g.V().has(\"name\", P.eq(__.V(vid1).values(\"name\")))",
+ "python": "g.V().has('name', P.eq(__.V(vid1).values('name')))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_hasXage_ltXVXvid1X_valuesXageXXX",
+ "traversals": [
+ {
+ "original": "g.V().has(\"age\", P.lt(__.V(vid1).values(\"age\")))",
+ "language": "g.V().has(\"age\", P.lt(__.V(vid1).values(\"age\")))",
+ "canonical": "g.V().has(\"age\", P.lt(__.V(vid1).values(\"age\")))",
+ "anonymized": "g.V().has(string0, P.lt(__.V(vid1).values(string0)))",
+ "dotnet": "g.V().Has(\"age\", P.Lt(__.V(vid1).Values<object>(\"age\")))",
+ "go": "g.V().Has(\"age\", gremlingo.P.Lt(gremlingo.T__.V(vid1).Values(\"age\")))",
+ "groovy": "g.V().has(\"age\", P.lt(__.V(vid1).values(\"age\")))",
+ "java": "g.V().has(\"age\", P.lt(__.V(vid1).values(\"age\")))",
+ "javascript": "g.V().has(\"age\", P.lt(__.V(vid1).values(\"age\")))",
+ "python": "g.V().has('age', P.lt(__.V(vid1).values('age')))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_hasXage_gteXVXvid3X_valuesXageXXX",
+ "traversals": [
+ {
+ "original": "g.V().has(\"age\", P.gte(__.V(vid3).values(\"age\")))",
+ "language": "g.V().has(\"age\", P.gte(__.V(vid3).values(\"age\")))",
+ "canonical": "g.V().has(\"age\", P.gte(__.V(vid3).values(\"age\")))",
+ "anonymized": "g.V().has(string0, P.gte(__.V(vid3).values(string0)))",
+ "dotnet": "g.V().Has(\"age\", P.Gte(__.V(vid3).Values<object>(\"age\")))",
+ "go": "g.V().Has(\"age\", gremlingo.P.Gte(gremlingo.T__.V(vid3).Values(\"age\")))",
+ "groovy": "g.V().has(\"age\", P.gte(__.V(vid3).values(\"age\")))",
+ "java": "g.V().has(\"age\", P.gte(__.V(vid3).values(\"age\")))",
+ "javascript": "g.V().has(\"age\", P.gte(__.V(vid3).values(\"age\")))",
+ "python": "g.V().has('age', P.gte(__.V(vid3).values('age')))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_hasXage_eqXVXvid1X_valuesXnonexistentXXX",
+ "traversals": [
+ {
+ "original": "g.V().has(\"age\", P.eq(__.V(vid1).values(\"nonexistent\")))",
+ "language": "g.V().has(\"age\", P.eq(__.V(vid1).values(\"nonexistent\")))",
+ "canonical": "g.V().has(\"age\", P.eq(__.V(vid1).values(\"nonexistent\")))",
+ "anonymized": "g.V().has(string0, P.eq(__.V(vid1).values(string1)))",
+ "dotnet": "g.V().Has(\"age\", P.Eq(__.V(vid1).Values<object>(\"nonexistent\")))",
+ "go": "g.V().Has(\"age\", gremlingo.P.Eq(gremlingo.T__.V(vid1).Values(\"nonexistent\")))",
+ "groovy": "g.V().has(\"age\", P.eq(__.V(vid1).values(\"nonexistent\")))",
+ "java": "g.V().has(\"age\", P.eq(__.V(vid1).values(\"nonexistent\")))",
+ "javascript": "g.V().has(\"age\", P.eq(__.V(vid1).values(\"nonexistent\")))",
+ "python": "g.V().has('age', P.eq(__.V(vid1).values('nonexistent')))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_hasXlabel_VXvid1X_labelXX",
+ "traversals": [
+ {
+ "original": "g.V().has(T.label, __.V(vid1).label())",
+ "language": "g.V().has(T.label, __.V(vid1).label())",
+ "canonical": "g.V().has(T.label, __.V(vid1).label())",
+ "anonymized": "g.V().has(T.label, __.V(vid1).label())",
+ "dotnet": "g.V().Has(T.Label, __.V(vid1).Label())",
+ "go": "g.V().Has(gremlingo.T.Label, gremlingo.T__.V(vid1).Label())",
+ "groovy": "g.V().has(T.label, __.V(vid1).label())",
+ "java": "g.V().has(T.label, __.V(vid1).label())",
+ "javascript": "g.V().has(T.label, __.V(vid1).label())",
+ "python": "g.V().has(T.label, __.V(vid1).label())"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_hasXperson_name_VXvid1X_valuesXnameXX_age",
+ "traversals": [
+ {
+ "original": "g.V().has(\"person\", \"name\", __.V(vid1).values(\"name\")).values(\"age\")",
+ "language": "g.V().has(\"person\", \"name\", __.V(vid1).values(\"name\")).values(\"age\")",
+ "canonical": "g.V().has(\"person\", \"name\", __.V(vid1).values(\"name\")).values(\"age\")",
+ "anonymized": "g.V().has(string0, string1, __.V(vid1).values(string1)).values(string2)",
+ "dotnet": "g.V().Has(\"person\", \"name\", __.V(vid1).Values<object>(\"name\")).Values<object>(\"age\")",
+ "go": "g.V().Has(\"person\", \"name\", gremlingo.T__.V(vid1).Values(\"name\")).Values(\"age\")",
+ "groovy": "g.V().has(\"person\", \"name\", __.V(vid1).values(\"name\")).values(\"age\")",
+ "java": "g.V().has(\"person\", \"name\", __.V(vid1).values(\"name\")).values(\"age\")",
+ "javascript": "g.V().has(\"person\", \"name\", __.V(vid1).values(\"name\")).values(\"age\")",
+ "python": "g.V().has('person', 'name', __.V(vid1).values('name')).values('age')"
+ }
+ ]
+ },
{
"scenario": "g_V_properties_hasValueXnullX",
"traversals": [
@@ -9449,6 +9687,329 @@
}
]
},
+ {
+ "scenario": "g_V_valuesXageX_isXVXvid1X_valuesXageXX",
+ "traversals": [
+ {
+ "original": "g.V().values(\"age\").is(__.V(vid1).values(\"age\"))",
+ "language": "g.V().values(\"age\").is(__.V(vid1).values(\"age\"))",
+ "canonical": "g.V().values(\"age\").is(__.V(vid1).values(\"age\"))",
+ "anonymized": "g.V().values(string0).is(__.V(vid1).values(string0))",
+ "dotnet": "g.V().Values<object>(\"age\").Is(__.V(vid1).Values<object>(\"age\"))",
+ "go": "g.V().Values(\"age\").Is(gremlingo.T__.V(vid1).Values(\"age\"))",
+ "groovy": "g.V().values(\"age\").is(__.V(vid1).values(\"age\"))",
+ "java": "g.V().values(\"age\").is(__.V(vid1).values(\"age\"))",
+ "javascript": "g.V().values(\"age\").is(__.V(vid1).values(\"age\"))",
+ "python": "g.V().values('age').is_(__.V(vid1).values('age'))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_valuesXnameX_isXVXvid1X_valuesXnameXX",
+ "traversals": [
+ {
+ "original": "g.V().values(\"name\").is(__.V(vid1).values(\"name\"))",
+ "language": "g.V().values(\"name\").is(__.V(vid1).values(\"name\"))",
+ "canonical": "g.V().values(\"name\").is(__.V(vid1).values(\"name\"))",
+ "anonymized": "g.V().values(string0).is(__.V(vid1).values(string0))",
+ "dotnet": "g.V().Values<object>(\"name\").Is(__.V(vid1).Values<object>(\"name\"))",
+ "go": "g.V().Values(\"name\").Is(gremlingo.T__.V(vid1).Values(\"name\"))",
+ "groovy": "g.V().values(\"name\").is(__.V(vid1).values(\"name\"))",
+ "java": "g.V().values(\"name\").is(__.V(vid1).values(\"name\"))",
+ "javascript": "g.V().values(\"name\").is(__.V(vid1).values(\"name\"))",
+ "python": "g.V().values('name').is_(__.V(vid1).values('name'))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_valuesXageX_isXgtXVXvid1X_valuesXageXXX",
+ "traversals": [
+ {
+ "original": "g.V().values(\"age\").is(P.gt(__.V(vid1).values(\"age\")))",
+ "language": "g.V().values(\"age\").is(P.gt(__.V(vid1).values(\"age\")))",
+ "canonical": "g.V().values(\"age\").is(P.gt(__.V(vid1).values(\"age\")))",
+ "anonymized": "g.V().values(string0).is(P.gt(__.V(vid1).values(string0)))",
+ "dotnet": "g.V().Values<object>(\"age\").Is(P.Gt(__.V(vid1).Values<object>(\"age\")))",
+ "go": "g.V().Values(\"age\").Is(gremlingo.P.Gt(gremlingo.T__.V(vid1).Values(\"age\")))",
+ "groovy": "g.V().values(\"age\").is(P.gt(__.V(vid1).values(\"age\")))",
+ "java": "g.V().values(\"age\").is(P.gt(__.V(vid1).values(\"age\")))",
+ "javascript": "g.V().values(\"age\").is(P.gt(__.V(vid1).values(\"age\")))",
+ "python": "g.V().values('age').is_(P.gt(__.V(vid1).values('age')))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_valuesXageX_isXltXVXvid3X_valuesXageXXX",
+ "traversals": [
+ {
+ "original": "g.V().values(\"age\").is(P.lt(__.V(vid3).values(\"age\")))",
+ "language": "g.V().values(\"age\").is(P.lt(__.V(vid3).values(\"age\")))",
+ "canonical": "g.V().values(\"age\").is(P.lt(__.V(vid3).values(\"age\")))",
+ "anonymized": "g.V().values(string0).is(P.lt(__.V(vid3).values(string0)))",
+ "dotnet": "g.V().Values<object>(\"age\").Is(P.Lt(__.V(vid3).Values<object>(\"age\")))",
+ "go": "g.V().Values(\"age\").Is(gremlingo.P.Lt(gremlingo.T__.V(vid3).Values(\"age\")))",
+ "groovy": "g.V().values(\"age\").is(P.lt(__.V(vid3).values(\"age\")))",
+ "java": "g.V().values(\"age\").is(P.lt(__.V(vid3).values(\"age\")))",
+ "javascript": "g.V().values(\"age\").is(P.lt(__.V(vid3).values(\"age\")))",
+ "python": "g.V().values('age').is_(P.lt(__.V(vid3).values('age')))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_valuesXageX_isXneqXVXvid4X_valuesXageXXX",
+ "traversals": [
+ {
+ "original": "g.V().values(\"age\").is(P.neq(__.V(vid4).values(\"age\")))",
+ "language": "g.V().values(\"age\").is(P.neq(__.V(vid4).values(\"age\")))",
+ "canonical": "g.V().values(\"age\").is(P.neq(__.V(vid4).values(\"age\")))",
+ "anonymized": "g.V().values(string0).is(P.neq(__.V(vid4).values(string0)))",
+ "dotnet": "g.V().Values<object>(\"age\").Is(P.Neq(__.V(vid4).Values<object>(\"age\")))",
+ "go": "g.V().Values(\"age\").Is(gremlingo.P.Neq(gremlingo.T__.V(vid4).Values(\"age\")))",
+ "groovy": "g.V().values(\"age\").is(P.neq(__.V(vid4).values(\"age\")))",
+ "java": "g.V().values(\"age\").is(P.neq(__.V(vid4).values(\"age\")))",
+ "javascript": "g.V().values(\"age\").is(P.neq(__.V(vid4).values(\"age\")))",
+ "python": "g.V().values('age').is_(P.neq(__.V(vid4).values('age')))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_valuesXageX_isXwithinXVXvid1X_outXknowsX_valuesXageXXX",
+ "traversals": [
+ {
+ "original": "g.V().values(\"age\").is(P.within(__.V(vid1).out(\"knows\").values(\"age\")))",
+ "language": "g.V().values(\"age\").is(P.within(__.V(vid1).out(\"knows\").values(\"age\")))",
+ "canonical": "g.V().values(\"age\").is(P.within(__.V(vid1).out(\"knows\").values(\"age\")))",
+ "anonymized": "g.V().values(string0).is(P.within(__.V(vid1).out(string1).values(string0)))",
+ "dotnet": "g.V().Values<object>(\"age\").Is(P.Within(__.V(vid1).Out(\"knows\").Values<object>(\"age\")))",
+ "go": "g.V().Values(\"age\").Is(gremlingo.P.Within(gremlingo.T__.V(vid1).Out(\"knows\").Values(\"age\")))",
+ "groovy": "g.V().values(\"age\").is(P.within(__.V(vid1).out(\"knows\").values(\"age\")))",
+ "java": "g.V().values(\"age\").is(P.within(__.V(vid1).out(\"knows\").values(\"age\")))",
+ "javascript": "g.V().values(\"age\").is(P.within(__.V(vid1).out(\"knows\").values(\"age\")))",
+ "python": "g.V().values('age').is_(P.within(__.V(vid1).out('knows').values('age')))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_valuesXageX_isXVXvid1X_valuesXnonexistentXX",
+ "traversals": [
+ {
+ "original": "g.V().values(\"age\").is(__.V(vid1).values(\"nonexistent\"))",
+ "language": "g.V().values(\"age\").is(__.V(vid1).values(\"nonexistent\"))",
+ "canonical": "g.V().values(\"age\").is(__.V(vid1).values(\"nonexistent\"))",
+ "anonymized": "g.V().values(string0).is(__.V(vid1).values(string1))",
+ "dotnet": "g.V().Values<object>(\"age\").Is(__.V(vid1).Values<object>(\"nonexistent\"))",
+ "go": "g.V().Values(\"age\").Is(gremlingo.T__.V(vid1).Values(\"nonexistent\"))",
+ "groovy": "g.V().values(\"age\").is(__.V(vid1).values(\"nonexistent\"))",
+ "java": "g.V().values(\"age\").is(__.V(vid1).values(\"nonexistent\"))",
+ "javascript": "g.V().values(\"age\").is(__.V(vid1).values(\"nonexistent\"))",
+ "python": "g.V().values('age').is_(__.V(vid1).values('nonexistent'))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_hasLabelXpersonX_valuesXageX_chooseXgtXVXvid1X_valuesXageXX_olderX",
+ "traversals": [
+ {
+ "original": "g.V().hasLabel(\"person\").values(\"age\").choose(P.gt(__.V(vid1).values(\"age\")), __.constant(\"older than marko\"), __.constant(\"not older\"))",
+ "language": "g.V().hasLabel(\"person\").values(\"age\").choose(P.gt(__.V(vid1).values(\"age\")), __.constant(\"older than marko\"), __.constant(\"not older\"))",
+ "canonical": "g.V().hasLabel(\"person\").values(\"age\").choose(P.gt(__.V(vid1).values(\"age\")), __.constant(\"older than marko\"), __.constant(\"not older\"))",
+ "anonymized": "g.V().hasLabel(string0).values(string1).choose(P.gt(__.V(vid1).values(string1)), __.constant(string2), __.constant(string3))",
+ "dotnet": "g.V().HasLabel(\"person\").Values<object>(\"age\").Choose<object>(P.Gt(__.V(vid1).Values<object>(\"age\")), __.Constant<object>(\"older than marko\"), __.Constant<object>(\"not older\"))",
+ "go": "g.V().HasLabel(\"person\").Values(\"age\").Choose(gremlingo.P.Gt(gremlingo.T__.V(vid1).Values(\"age\")), gremlingo.T__.Constant(\"older than marko\"), gremlingo.T__.Constant(\"not older\"))",
+ "groovy": "g.V().hasLabel(\"person\").values(\"age\").choose(P.gt(__.V(vid1).values(\"age\")), __.constant(\"older than marko\"), __.constant(\"not older\"))",
+ "java": "g.V().hasLabel(\"person\").values(\"age\").choose(P.gt(__.V(vid1).values(\"age\")), __.constant(\"older than marko\"), __.constant(\"not older\"))",
+ "javascript": "g.V().hasLabel(\"person\").values(\"age\").choose(P.gt(__.V(vid1).values(\"age\")), __.constant(\"older than marko\"), __.constant(\"not older\"))",
+ "python": "g.V().has_label('person').values('age').choose(P.gt(__.V(vid1).values('age')), __.constant('older than marko'), __.constant('not older'))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_hasLabelXpersonX_valuesXageX_chooseXgteXmeanAgeX_aboveX",
+ "traversals": [
+ {
+ "original": "g.V().hasLabel(\"person\").values(\"age\").choose(P.gte(__.V().hasLabel(\"person\").values(\"age\").mean()), __.constant(\"above average\"), __.constant(\"below average\"))",
+ "language": "g.V().hasLabel(\"person\").values(\"age\").choose(P.gte(__.V().hasLabel(\"person\").values(\"age\").mean()), __.constant(\"above average\"), __.constant(\"below average\"))",
+ "canonical": "g.V().hasLabel(\"person\").values(\"age\").choose(P.gte(__.V().hasLabel(\"person\").values(\"age\").mean()), __.constant(\"above average\"), __.constant(\"below average\"))",
+ "anonymized": "g.V().hasLabel(string0).values(string1).choose(P.gte(__.V().hasLabel(string0).values(string1).mean()), __.constant(string2), __.constant(string3))",
+ "dotnet": "g.V().HasLabel(\"person\").Values<object>(\"age\").Choose<object>(P.Gte(__.V().HasLabel(\"person\").Values<object>(\"age\").Mean<object>()), __.Constant<object>(\"above average\"), __.Constant<object>(\"below average\"))",
+ "go": "g.V().HasLabel(\"person\").Values(\"age\").Choose(gremlingo.P.Gte(gremlingo.T__.V().HasLabel(\"person\").Values(\"age\").Mean()), gremlingo.T__.Constant(\"above average\"), gremlingo.T__.Constant(\"below average\"))",
+ "groovy": "g.V().hasLabel(\"person\").values(\"age\").choose(P.gte(__.V().hasLabel(\"person\").values(\"age\").mean()), __.constant(\"above average\"), __.constant(\"below average\"))",
+ "java": "g.V().hasLabel(\"person\").values(\"age\").choose(P.gte(__.V().hasLabel(\"person\").values(\"age\").mean()), __.constant(\"above average\"), __.constant(\"below average\"))",
+ "javascript": "g.V().hasLabel(\"person\").values(\"age\").choose(P.gte(__.V().hasLabel(\"person\").values(\"age\").mean()), __.constant(\"above average\"), __.constant(\"below average\"))",
+ "python": "g.V().has_label('person').values('age').choose(P.gte(__.V().has_label('person').values('age').mean()), __.constant('above average'), __.constant('below average'))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_VXvid1X_outXknowsX_valuesXageX_fold_allXgteXVXvid2X_valuesXageXXX",
+ "traversals": [
+ {
+ "original": "g.V(vid1).out(\"knows\").values(\"age\").fold().all(P.gte(__.V(vid2).values(\"age\")))",
+ "language": "g.V(vid1).out(\"knows\").values(\"age\").fold().all(P.gte(__.V(vid2).values(\"age\")))",
+ "canonical": "g.V(vid1).out(\"knows\").values(\"age\").fold().all(P.gte(__.V(vid2).values(\"age\")))",
+ "anonymized": "g.V(vid1).out(string0).values(string1).fold().all(P.gte(__.V(vid2).values(string1)))",
+ "dotnet": "g.V(vid1).Out(\"knows\").Values<object>(\"age\").Fold().All(P.Gte(__.V(vid2).Values<object>(\"age\")))",
+ "go": "g.V(vid1).Out(\"knows\").Values(\"age\").Fold().All(gremlingo.P.Gte(gremlingo.T__.V(vid2).Values(\"age\")))",
+ "groovy": "g.V(vid1).out(\"knows\").values(\"age\").fold().all(P.gte(__.V(vid2).values(\"age\")))",
+ "java": "g.V(vid1).out(\"knows\").values(\"age\").fold().all(P.gte(__.V(vid2).values(\"age\")))",
+ "javascript": "g.V(vid1).out(\"knows\").values(\"age\").fold().all(P.gte(__.V(vid2).values(\"age\")))",
+ "python": "g.V(vid1).out('knows').values('age').fold().all_(P.gte(__.V(vid2).values('age')))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_VXvid1X_outXknowsX_valuesXageX_fold_allXgtXVXvid2X_valuesXageXXX",
+ "traversals": [
+ {
+ "original": "g.V(vid1).out(\"knows\").values(\"age\").fold().all(P.gt(__.V(vid2).values(\"age\")))",
+ "language": "g.V(vid1).out(\"knows\").values(\"age\").fold().all(P.gt(__.V(vid2).values(\"age\")))",
+ "canonical": "g.V(vid1).out(\"knows\").values(\"age\").fold().all(P.gt(__.V(vid2).values(\"age\")))",
+ "anonymized": "g.V(vid1).out(string0).values(string1).fold().all(P.gt(__.V(vid2).values(string1)))",
+ "dotnet": "g.V(vid1).Out(\"knows\").Values<object>(\"age\").Fold().All(P.Gt(__.V(vid2).Values<object>(\"age\")))",
+ "go": "g.V(vid1).Out(\"knows\").Values(\"age\").Fold().All(gremlingo.P.Gt(gremlingo.T__.V(vid2).Values(\"age\")))",
+ "groovy": "g.V(vid1).out(\"knows\").values(\"age\").fold().all(P.gt(__.V(vid2).values(\"age\")))",
+ "java": "g.V(vid1).out(\"knows\").values(\"age\").fold().all(P.gt(__.V(vid2).values(\"age\")))",
+ "javascript": "g.V(vid1).out(\"knows\").values(\"age\").fold().all(P.gt(__.V(vid2).values(\"age\")))",
+ "python": "g.V(vid1).out('knows').values('age').fold().all_(P.gt(__.V(vid2).values('age')))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_VXvid1X_outXknowsX_valuesXageX_fold_anyXeqXVXvid3X_valuesXageXXX",
+ "traversals": [
+ {
+ "original": "g.V(vid1).out(\"knows\").values(\"age\").fold().any(P.eq(__.V(vid3).values(\"age\")))",
+ "language": "g.V(vid1).out(\"knows\").values(\"age\").fold().any(P.eq(__.V(vid3).values(\"age\")))",
+ "canonical": "g.V(vid1).out(\"knows\").values(\"age\").fold().any(P.eq(__.V(vid3).values(\"age\")))",
+ "anonymized": "g.V(vid1).out(string0).values(string1).fold().any(P.eq(__.V(vid3).values(string1)))",
+ "dotnet": "g.V(vid1).Out(\"knows\").Values<object>(\"age\").Fold().Any(P.Eq(__.V(vid3).Values<object>(\"age\")))",
+ "go": "g.V(vid1).Out(\"knows\").Values(\"age\").Fold().Any(gremlingo.P.Eq(gremlingo.T__.V(vid3).Values(\"age\")))",
+ "groovy": "g.V(vid1).out(\"knows\").values(\"age\").fold().any(P.eq(__.V(vid3).values(\"age\")))",
+ "java": "g.V(vid1).out(\"knows\").values(\"age\").fold().any(P.eq(__.V(vid3).values(\"age\")))",
+ "javascript": "g.V(vid1).out(\"knows\").values(\"age\").fold().any(P.eq(__.V(vid3).values(\"age\")))",
+ "python": "g.V(vid1).out('knows').values('age').fold().any_(P.eq(__.V(vid3).values('age')))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_VXvid1X_outXknowsX_valuesXageX_fold_noneXeqXVXvid4X_valuesXageXXX",
+ "traversals": [
+ {
+ "original": "g.V(vid1).out(\"knows\").values(\"age\").fold().none(P.eq(__.V(vid4).values(\"age\")))",
+ "language": "g.V(vid1).out(\"knows\").values(\"age\").fold().none(P.eq(__.V(vid4).values(\"age\")))",
+ "canonical": "g.V(vid1).out(\"knows\").values(\"age\").fold().none(P.eq(__.V(vid4).values(\"age\")))",
+ "anonymized": "g.V(vid1).out(string0).values(string1).fold().none(P.eq(__.V(vid4).values(string1)))",
+ "dotnet": "g.V(vid1).Out(\"knows\").Values<object>(\"age\").Fold().None(P.Eq(__.V(vid4).Values<object>(\"age\")))",
+ "go": "g.V(vid1).Out(\"knows\").Values(\"age\").Fold().None(gremlingo.P.Eq(gremlingo.T__.V(vid4).Values(\"age\")))",
+ "groovy": "g.V(vid1).out(\"knows\").values(\"age\").fold().none(P.eq(__.V(vid4).values(\"age\")))",
+ "java": "g.V(vid1).out(\"knows\").values(\"age\").fold().none(P.eq(__.V(vid4).values(\"age\")))",
+ "javascript": "g.V(vid1).out(\"knows\").values(\"age\").fold().none(P.eq(__.V(vid4).values(\"age\")))",
+ "python": "g.V(vid1).out('knows').values('age').fold().none(P.eq(__.V(vid4).values('age')))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_VXvid1X_outXknowsX_valuesXageX_fold_noneXeqXVXvid3X_valuesXageXXX",
+ "traversals": [
+ {
+ "original": "g.V(vid1).out(\"knows\").values(\"age\").fold().none(P.eq(__.V(vid3).values(\"age\")))",
+ "language": "g.V(vid1).out(\"knows\").values(\"age\").fold().none(P.eq(__.V(vid3).values(\"age\")))",
+ "canonical": "g.V(vid1).out(\"knows\").values(\"age\").fold().none(P.eq(__.V(vid3).values(\"age\")))",
+ "anonymized": "g.V(vid1).out(string0).values(string1).fold().none(P.eq(__.V(vid3).values(string1)))",
+ "dotnet": "g.V(vid1).Out(\"knows\").Values<object>(\"age\").Fold().None(P.Eq(__.V(vid3).Values<object>(\"age\")))",
+ "go": "g.V(vid1).Out(\"knows\").Values(\"age\").Fold().None(gremlingo.P.Eq(gremlingo.T__.V(vid3).Values(\"age\")))",
+ "groovy": "g.V(vid1).out(\"knows\").values(\"age\").fold().none(P.eq(__.V(vid3).values(\"age\")))",
+ "java": "g.V(vid1).out(\"knows\").values(\"age\").fold().none(P.eq(__.V(vid3).values(\"age\")))",
+ "javascript": "g.V(vid1).out(\"knows\").values(\"age\").fold().none(P.eq(__.V(vid3).values(\"age\")))",
+ "python": "g.V(vid1).out('knows').values('age').fold().none(P.eq(__.V(vid3).values('age')))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_injectXnullX_isXeqXV9999_valuesXnameXXX",
+ "traversals": [
+ {
+ "original": "g.inject(null).is(P.eq(__.V(9999).values(\"name\")))",
+ "language": "g.inject(null).is(P.eq(__.V(9999).values(\"name\")))",
+ "canonical": "g.inject(null).is(P.eq(__.V(9999).values(\"name\")))",
+ "anonymized": "g.inject(object0).is(P.eq(__.V(number0).values(string0)))",
+ "dotnet": "g.Inject<object>(null).Is(P.Eq(__.V(9999).Values<object>(\"name\")))",
+ "go": "g.Inject(nil).Is(gremlingo.P.Eq(gremlingo.T__.V(9999).Values(\"name\")))",
+ "groovy": "g.inject(null).is(P.eq(__.V(9999).values(\"name\")))",
+ "java": "g.inject(null).is(P.eq(__.V(9999).values(\"name\")))",
+ "javascript": "g.inject(null).is(P.eq(__.V(9999).values(\"name\")))",
+ "python": "g.inject(None).is_(P.eq(__.V(9999).values('name')))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_injectXmarkoX_isXV9999_valuesXnameXX",
+ "traversals": [
+ {
+ "original": "g.inject(\"marko\").is(__.V(9999).values(\"name\"))",
+ "language": "g.inject(\"marko\").is(__.V(9999).values(\"name\"))",
+ "canonical": "g.inject(\"marko\").is(__.V(9999).values(\"name\"))",
+ "anonymized": "g.inject(string0).is(__.V(number0).values(string1))",
+ "dotnet": "g.Inject<object>(\"marko\").Is(__.V(9999).Values<object>(\"name\"))",
+ "go": "g.Inject(\"marko\").Is(gremlingo.T__.V(9999).Values(\"name\"))",
+ "groovy": "g.inject(\"marko\").is(__.V(9999).values(\"name\"))",
+ "java": "g.inject(\"marko\").is(__.V(9999).values(\"name\"))",
+ "javascript": "g.inject(\"marko\").is(__.V(9999).values(\"name\"))",
+ "python": "g.inject('marko').is_(__.V(9999).values('name'))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_injectXmarkoX_chooseXeqXV9999_valuesXnameXX_matched_unmatchedX",
+ "traversals": [
+ {
+ "original": "g.inject(\"marko\").choose(P.eq(__.V(9999).values(\"name\")), __.constant(\"matched\"), __.constant(\"unmatched\"))",
+ "language": "g.inject(\"marko\").choose(P.eq(__.V(9999).values(\"name\")), __.constant(\"matched\"), __.constant(\"unmatched\"))",
+ "canonical": "g.inject(\"marko\").choose(P.eq(__.V(9999).values(\"name\")), __.constant(\"matched\"), __.constant(\"unmatched\"))",
+ "anonymized": "g.inject(string0).choose(P.eq(__.V(number0).values(string1)), __.constant(string2), __.constant(string3))",
+ "dotnet": "g.Inject<object>(\"marko\").Choose<object>(P.Eq(__.V(9999).Values<object>(\"name\")), __.Constant<object>(\"matched\"), __.Constant<object>(\"unmatched\"))",
+ "go": "g.Inject(\"marko\").Choose(gremlingo.P.Eq(gremlingo.T__.V(9999).Values(\"name\")), gremlingo.T__.Constant(\"matched\"), gremlingo.T__.Constant(\"unmatched\"))",
+ "groovy": "g.inject(\"marko\").choose(P.eq(__.V(9999).values(\"name\")), __.constant(\"matched\"), __.constant(\"unmatched\"))",
+ "java": "g.inject(\"marko\").choose(P.eq(__.V(9999).values(\"name\")), __.constant(\"matched\"), __.constant(\"unmatched\"))",
+ "javascript": "g.inject(\"marko\").choose(P.eq(__.V(9999).values(\"name\")), __.constant(\"matched\"), __.constant(\"unmatched\"))",
+ "python": "g.inject('marko').choose(P.eq(__.V(9999).values('name')), __.constant('matched'), __.constant('unmatched'))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_injectXlistX_noneXeqXV9999_valuesXnameXXX",
+ "traversals": [
+ {
+ "original": "g.inject([\"marko\",\"josh\"]).none(P.eq(__.V(9999).values(\"name\")))",
+ "language": "g.inject([\"marko\", \"josh\"]).none(P.eq(__.V(9999).values(\"name\")))",
+ "canonical": "g.inject([\"marko\", \"josh\"]).none(P.eq(__.V(9999).values(\"name\")))",
+ "anonymized": "g.inject(list0).none(P.eq(__.V(number0).values(string0)))",
+ "dotnet": "g.Inject<object>(new List<object> { \"marko\", \"josh\" }).None(P.Eq(__.V(9999).Values<object>(\"name\")))",
+ "go": "g.Inject([]interface{}{\"marko\", \"josh\"}).None(gremlingo.P.Eq(gremlingo.T__.V(9999).Values(\"name\")))",
+ "groovy": "g.inject([\"marko\", \"josh\"]).none(P.eq(__.V(9999).values(\"name\")))",
+ "java": "g.inject(new ArrayList<Object>() {{ add(\"marko\"); add(\"josh\"); }}).none(P.eq(__.V(9999).values(\"name\")))",
+ "javascript": "g.inject([\"marko\", \"josh\"]).none(P.eq(__.V(9999).values(\"name\")))",
+ "python": "g.inject(['marko', 'josh']).none(P.eq(__.V(9999).values('name')))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_hasXname_eqXV9999_valuesXnameXXX",
+ "traversals": [
+ {
+ "original": "g.V().has(\"name\", P.eq(__.V(9999).values(\"name\")))",
+ "language": "g.V().has(\"name\", P.eq(__.V(9999).values(\"name\")))",
+ "canonical": "g.V().has(\"name\", P.eq(__.V(9999).values(\"name\")))",
+ "anonymized": "g.V().has(string0, P.eq(__.V(number0).values(string0)))",
+ "dotnet": "g.V().Has(\"name\", P.Eq(__.V(9999).Values<object>(\"name\")))",
+ "go": "g.V().Has(\"name\", gremlingo.P.Eq(gremlingo.T__.V(9999).Values(\"name\")))",
+ "groovy": "g.V().has(\"name\", P.eq(__.V(9999).values(\"name\")))",
+ "java": "g.V().has(\"name\", P.eq(__.V(9999).values(\"name\")))",
+ "javascript": "g.V().has(\"name\", P.eq(__.V(9999).values(\"name\")))",
+ "python": "g.V().has('name', P.eq(__.V(9999).values('name')))"
+ }
+ ]
+ },
{
"scenario": "g_V_valuesXageX_noneXgtX32XX",
"traversals": [
@@ -37289,6 +37850,176 @@
}
]
},
+ {
+ "scenario": "g_VXvid1X_id_VXidentityX_name",
+ "traversals": [
+ {
+ "original": "g.V(vid1).id().V(__.identity()).values(\"name\")",
+ "language": "g.V(vid1).id().V(__.identity()).values(\"name\")",
+ "canonical": "g.V(vid1).id().V(__.identity()).values(\"name\")",
+ "anonymized": "g.V(vid1).id().V(__.identity()).values(string0)",
+ "dotnet": "g.V(vid1).Id().V(__.Identity()).Values<object>(\"name\")",
+ "go": "g.V(vid1).Id().V(gremlingo.T__.Identity()).Values(\"name\")",
+ "groovy": "g.V(vid1).id().V(__.identity()).values(\"name\")",
+ "java": "g.V(vid1).id().V(__.identity()).values(\"name\")",
+ "javascript": "g.V(vid1).id().V(__.identity()).values(\"name\")",
+ "python": "g.V(vid1).id_().V(__.identity()).values('name')"
+ }
+ ]
+ },
+ {
+ "scenario": "g_VXvid1_vid2X_id_VXidentityX_name",
+ "traversals": [
+ {
+ "original": "g.V(vid1, vid2).id().V(__.identity()).values(\"name\")",
+ "language": "g.V(vid1, vid2).id().V(__.identity()).values(\"name\")",
+ "canonical": "g.V(vid1, vid2).id().V(__.identity()).values(\"name\")",
+ "anonymized": "g.V(vid1, vid2).id().V(__.identity()).values(string0)",
+ "dotnet": "g.V(vid1, vid2).Id().V(__.Identity()).Values<object>(\"name\")",
+ "go": "g.V(vid1, vid2).Id().V(gremlingo.T__.Identity()).Values(\"name\")",
+ "groovy": "g.V(vid1, vid2).id().V(__.identity()).values(\"name\")",
+ "java": "g.V(vid1, vid2).id().V(__.identity()).values(\"name\")",
+ "javascript": "g.V(vid1, vid2).id().V(__.identity()).values(\"name\")",
+ "python": "g.V(vid1, vid2).id_().V(__.identity()).values('name')"
+ }
+ ]
+ },
+ {
+ "scenario": "g_VXvid1X_id_asXbookmarkX_V_hasXname_joshX_VXselectXbookmarkXX_name",
+ "traversals": [
+ {
+ "original": "g.V(vid1).id().as(\"bookmark\").V().has(\"name\",\"josh\").V(__.select(\"bookmark\")).values(\"name\")",
+ "language": "g.V(vid1).id().as(\"bookmark\").V().has(\"name\", \"josh\").V(__.select(\"bookmark\")).values(\"name\")",
+ "canonical": "g.V(vid1).id().as(\"bookmark\").V().has(\"name\", \"josh\").V(__.select(\"bookmark\")).values(\"name\")",
+ "anonymized": "g.V(vid1).id().as(string0).V().has(string1, string2).V(__.select(string0)).values(string1)",
+ "dotnet": "g.V(vid1).Id().As(\"bookmark\").V().Has(\"name\", \"josh\").V(__.Select<object>(\"bookmark\")).Values<object>(\"name\")",
+ "go": "g.V(vid1).Id().As(\"bookmark\").V().Has(\"name\", \"josh\").V(gremlingo.T__.Select(\"bookmark\")).Values(\"name\")",
+ "groovy": "g.V(vid1).id().as(\"bookmark\").V().has(\"name\", \"josh\").V(__.select(\"bookmark\")).values(\"name\")",
+ "java": "g.V(vid1).id().as(\"bookmark\").V().has(\"name\", \"josh\").V(__.select(\"bookmark\")).values(\"name\")",
+ "javascript": "g.V(vid1).id().as(\"bookmark\").V().has(\"name\", \"josh\").V(__.select(\"bookmark\")).values(\"name\")",
+ "python": "g.V(vid1).id_().as_('bookmark').V().has('name', 'josh').V(__.select('bookmark')).values('name')"
+ }
+ ]
+ },
+ {
+ "scenario": "g_VXvid1X_VXoutXknowsX_idX_name",
+ "traversals": [
+ {
+ "original": "g.V(vid1).V(__.out(\"knows\").id()).values(\"name\")",
+ "language": "g.V(vid1).V(__.out(\"knows\").id()).values(\"name\")",
+ "canonical": "g.V(vid1).V(__.out(\"knows\").id()).values(\"name\")",
+ "anonymized": "g.V(vid1).V(__.out(string0).id()).values(string1)",
+ "dotnet": "g.V(vid1).V(__.Out(\"knows\").Id()).Values<object>(\"name\")",
+ "go": "g.V(vid1).V(gremlingo.T__.Out(\"knows\").Id()).Values(\"name\")",
+ "groovy": "g.V(vid1).V(__.out(\"knows\").id()).values(\"name\")",
+ "java": "g.V(vid1).V(__.out(\"knows\").id()).values(\"name\")",
+ "javascript": "g.V(vid1).V(__.out(\"knows\").id()).values(\"name\")",
+ "python": "g.V(vid1).V(__.out('knows').id_()).values('name')"
+ }
+ ]
+ },
+ {
+ "scenario": "g_VXvid1X_EXoutE_idX",
+ "traversals": [
+ {
+ "original": "g.V(vid1).E(__.outE().id())",
+ "language": "g.V(vid1).E(__.outE().id())",
+ "canonical": "g.V(vid1).E(__.outE().id())",
+ "anonymized": "g.V(vid1).E(__.outE().id())",
+ "dotnet": "g.V(vid1).E(__.OutE().Id())",
+ "go": "g.V(vid1).E(gremlingo.T__.OutE().Id())",
+ "groovy": "g.V(vid1).E(__.outE().id())",
+ "java": "g.V(vid1).E(__.outE().id())",
+ "javascript": "g.V(vid1).E(__.outE().id())",
+ "python": "g.V(vid1).E(__.out_e().id_())"
+ }
+ ]
+ },
+ {
+ "scenario": "g_injectX9999X_VXidentityX",
+ "traversals": [
+ {
+ "original": "g.inject(9999).V(__.identity())",
+ "language": "g.inject(9999).V(__.identity())",
+ "canonical": "g.inject(9999).V(__.identity())",
+ "anonymized": "g.inject(number0).V(__.identity())",
+ "dotnet": "g.Inject<object>(9999).V(__.Identity())",
+ "go": "g.Inject(9999).V(gremlingo.T__.Identity())",
+ "groovy": "g.inject(9999).V(__.identity())",
+ "java": "g.inject(9999).V(__.identity())",
+ "javascript": "g.inject(9999).V(__.identity())",
+ "python": "g.inject(9999).V(__.identity())"
+ }
+ ]
+ },
+ {
+ "scenario": "g_VXvid1X_outEXknowsX_hasXinV_name_vadasX_id_EXidentityX",
+ "traversals": [
+ {
+ "original": "g.V(vid1).outE(\"knows\").filter(__.inV().has(\"name\",\"vadas\")).id().E(__.identity())",
+ "language": "g.V(vid1).outE(\"knows\").filter(__.inV().has(\"name\", \"vadas\")).id().E(__.identity())",
+ "canonical": "g.V(vid1).outE(\"knows\").filter(__.inV().has(\"name\", \"vadas\")).id().E(__.identity())",
+ "anonymized": "g.V(vid1).outE(string0).filter(__.inV().has(string1, string2)).id().E(__.identity())",
+ "dotnet": "g.V(vid1).OutE(\"knows\").Filter(__.InV().Has(\"name\", \"vadas\")).Id().E(__.Identity())",
+ "go": "g.V(vid1).OutE(\"knows\").Filter(gremlingo.T__.InV().Has(\"name\", \"vadas\")).Id().E(gremlingo.T__.Identity())",
+ "groovy": "g.V(vid1).outE(\"knows\").filter(__.inV().has(\"name\", \"vadas\")).id().E(__.identity())",
+ "java": "g.V(vid1).outE(\"knows\").filter(__.inV().has(\"name\", \"vadas\")).id().E(__.identity())",
+ "javascript": "g.V(vid1).outE(\"knows\").filter(__.inV().has(\"name\", \"vadas\")).id().E(__.identity())",
+ "python": "g.V(vid1).out_e('knows').filter_(__.in_v().has('name', 'vadas')).id_().E(__.identity())"
+ }
+ ]
+ },
+ {
+ "scenario": "g_injectX9999X_EXidentityX",
+ "traversals": [
+ {
+ "original": "g.inject(9999).E(__.identity())",
+ "language": "g.inject(9999).E(__.identity())",
+ "canonical": "g.inject(9999).E(__.identity())",
+ "anonymized": "g.inject(number0).E(__.identity())",
+ "dotnet": "g.Inject<object>(9999).E(__.Identity())",
+ "go": "g.Inject(9999).E(gremlingo.T__.Identity())",
+ "groovy": "g.inject(9999).E(__.identity())",
+ "java": "g.inject(9999).E(__.identity())",
+ "javascript": "g.inject(9999).E(__.identity())",
+ "python": "g.inject(9999).E(__.identity())"
+ }
+ ]
+ },
+ {
+ "scenario": "g_VXVXvid1X_idX_name",
+ "traversals": [
+ {
+ "original": "g.V(__.V(vid1).id()).values(\"name\")",
+ "language": "g.V(__.V(vid1).id()).values(\"name\")",
+ "canonical": "g.V(__.V(vid1).id()).values(\"name\")",
+ "anonymized": "g.V(__.V(vid1).id()).values(string0)",
+ "dotnet": "g.V(__.V(vid1).Id()).Values<object>(\"name\")",
+ "go": "g.V(gremlingo.T__.V(vid1).Id()).Values(\"name\")",
+ "groovy": "g.V(__.V(vid1).id()).values(\"name\")",
+ "java": "g.V(__.V(vid1).id()).values(\"name\")",
+ "javascript": "g.V(__.V(vid1).id()).values(\"name\")",
+ "python": "g.V(__.V(vid1).id_()).values('name')"
+ }
+ ]
+ },
+ {
+ "scenario": "g_EXVXvid1X_outE_idX",
+ "traversals": [
+ {
+ "original": "g.E(__.V(vid1).outE().id())",
+ "language": "g.E(__.V(vid1).outE().id())",
+ "canonical": "g.E(__.V(vid1).outE().id())",
+ "anonymized": "g.E(__.V(vid1).outE().id())",
+ "dotnet": "g.E(__.V(vid1).OutE().Id())",
+ "go": "g.E(gremlingo.T__.V(vid1).OutE().Id())",
+ "groovy": "g.E(__.V(vid1).outE().id())",
+ "java": "g.E(__.V(vid1).outE().id())",
+ "javascript": "g.E(__.V(vid1).outE().id())",
+ "python": "g.E(__.V(vid1).out_e().id_())"
+ }
+ ]
+ },
{
"scenario": "g_V_valueMap",
"traversals": [
@@ -42914,6 +43645,416 @@
}
]
},
+ {
+ "scenario": "g_VXvid2X_propertyXalias_VXvid1X_valuesXnameXX",
+ "traversals": [
+ {
+ "original": "g.addV(\"person\").property(\"name\",\"marko\").property(\"age\",29).addV(\"person\").property(\"name\",\"vadas\").property(\"age\",27).addV(\"software\").property(\"name\",\"lop\").property(\"lang\",\"java\").addV(\"person\").property(\"name\",\"josh\").property(\"age\",32).addV(\"person\").property(\"name\",\"peter\").property(\"age\",35).addV(\"software\").property(\"name\",\"ripple\").property(\"lang\",\"java\")",
+ "language": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\")",
+ "canonical": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\")",
+ "anonymized": "g.addV(string0).property(string1, string2).property(string3, number0).addV(string0).property(string1, string4).property(string3, number1).addV(string5).property(string1, string6).property(string7, string8).addV(string0).property(string1, string9).property(string3, number2).addV(string0).property(string1, string10).property(string3, number3).addV(string5).property(string1, string11).property(string7, string8)",
+ "dotnet": "g.AddV((string) \"person\").Property(\"name\", \"marko\").Property(\"age\", 29).AddV((string) \"person\").Property(\"name\", \"vadas\").Property(\"age\", 27).AddV((string) \"software\").Property(\"name\", \"lop\").Property(\"lang\", \"java\").AddV((string) \"person\").Property(\"name\", \"josh\").Property(\"age\", 32).AddV((string) \"person\").Property(\"name\", \"peter\").Property(\"age\", 35).AddV((string) \"software\").Property(\"name\", \"ripple\").Property [...]
+ "go": "g.AddV(\"person\").Property(\"name\", \"marko\").Property(\"age\", 29).AddV(\"person\").Property(\"name\", \"vadas\").Property(\"age\", 27).AddV(\"software\").Property(\"name\", \"lop\").Property(\"lang\", \"java\").AddV(\"person\").Property(\"name\", \"josh\").Property(\"age\", 32).AddV(\"person\").Property(\"name\", \"peter\").Property(\"age\", 35).AddV(\"software\").Property(\"name\", \"ripple\").Property(\"lang\", \"java\")",
+ "groovy": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\")",
+ "java": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\")",
+ "javascript": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\")",
+ "python": "g.add_v('person').property('name', 'marko').property('age', 29).add_v('person').property('name', 'vadas').property('age', 27).add_v('software').property('name', 'lop').property('lang', 'java').add_v('person').property('name', 'josh').property('age', 32).add_v('person').property('name', 'peter').property('age', 35).add_v('software').property('name', 'ripple').property('lang', 'java')"
+ },
+ {
+ "original": "g.V(vid2).property(\"alias\", __.V(vid1).values(\"name\"))",
+ "language": "g.V(vid2).property(\"alias\", __.V(vid1).values(\"name\"))",
+ "canonical": "g.V(vid2).property(\"alias\", __.V(vid1).values(\"name\"))",
+ "anonymized": "g.V(vid2).property(string0, __.V(vid1).values(string1))",
+ "dotnet": "g.V(vid2).Property(\"alias\", __.V(vid1).Values<object>(\"name\"))",
+ "go": "g.V(vid2).Property(\"alias\", gremlingo.T__.V(vid1).Values(\"name\"))",
+ "groovy": "g.V(vid2).property(\"alias\", __.V(vid1).values(\"name\"))",
+ "java": "g.V(vid2).property(\"alias\", __.V(vid1).values(\"name\"))",
+ "javascript": "g.V(vid2).property(\"alias\", __.V(vid1).values(\"name\"))",
+ "python": "g.V(vid2).property('alias', __.V(vid1).values('name'))"
+ },
+ {
+ "original": "g.V().has(\"alias\", \"marko\")",
+ "language": "g.V().has(\"alias\", \"marko\")",
+ "canonical": "g.V().has(\"alias\", \"marko\")",
+ "anonymized": "g.V().has(string0, string1)",
+ "dotnet": "g.V().Has(\"alias\", \"marko\")",
+ "go": "g.V().Has(\"alias\", \"marko\")",
+ "groovy": "g.V().has(\"alias\", \"marko\")",
+ "java": "g.V().has(\"alias\", \"marko\")",
+ "javascript": "g.V().has(\"alias\", \"marko\")",
+ "python": "g.V().has('alias', 'marko')"
+ }
+ ]
+ },
+ {
+ "scenario": "g_VXvid1X_propertyXcreatorCount_VXvid1X_inXcreatedX_countX",
+ "traversals": [
+ {
+ "original": "g.addV(\"person\").property(\"name\",\"marko\").property(\"age\",29).as(\"marko\").addV(\"person\").property(\"name\",\"vadas\").property(\"age\",27).addV(\"software\").property(\"name\",\"lop\").property(\"lang\",\"java\").as(\"lop\").addV(\"person\").property(\"name\",\"josh\").property(\"age\",32).as(\"josh\").addV(\"person\").property(\"name\",\"peter\").property(\"age\",35).as(\"peter\").addV(\"software\").property(\"name\",\"ripple\").property(\"lang\", [...]
+ "language": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).as(\"peter\").addV(\"software\").property(\"name\", \"ripple\").propert [...]
+ "canonical": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).as(\"peter\").addV(\"software\").property(\"name\", \"ripple\").proper [...]
+ "anonymized": "g.addV(string0).property(string1, string2).property(string3, number0).as(string2).addV(string0).property(string1, string4).property(string3, number1).addV(string5).property(string1, string6).property(string7, string8).as(string6).addV(string0).property(string1, string9).property(string3, number2).as(string9).addV(string0).property(string1, string10).property(string3, number3).as(string10).addV(string5).property(string1, string11).property(string7, string8). [...]
+ "dotnet": "g.AddV((string) \"person\").Property(\"name\", \"marko\").Property(\"age\", 29).As(\"marko\").AddV((string) \"person\").Property(\"name\", \"vadas\").Property(\"age\", 27).AddV((string) \"software\").Property(\"name\", \"lop\").Property(\"lang\", \"java\").As(\"lop\").AddV((string) \"person\").Property(\"name\", \"josh\").Property(\"age\", 32).As(\"josh\").AddV((string) \"person\").Property(\"name\", \"peter\").Property(\"age\", 35).As(\"peter\").AddV((string) [...]
+ "go": "g.AddV(\"person\").Property(\"name\", \"marko\").Property(\"age\", 29).As(\"marko\").AddV(\"person\").Property(\"name\", \"vadas\").Property(\"age\", 27).AddV(\"software\").Property(\"name\", \"lop\").Property(\"lang\", \"java\").As(\"lop\").AddV(\"person\").Property(\"name\", \"josh\").Property(\"age\", 32).As(\"josh\").AddV(\"person\").Property(\"name\", \"peter\").Property(\"age\", 35).As(\"peter\").AddV(\"software\").Property(\"name\", \"ripple\").Property(\"la [...]
+ "groovy": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).as(\"peter\").addV(\"software\").property(\"name\", \"ripple\").property( [...]
+ "java": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).as(\"peter\").addV(\"software\").property(\"name\", \"ripple\").property(\" [...]
+ "javascript": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).as(\"peter\").addV(\"software\").property(\"name\", \"ripple\").prope [...]
+ "python": "g.add_v('person').property('name', 'marko').property('age', 29).as_('marko').add_v('person').property('name', 'vadas').property('age', 27).add_v('software').property('name', 'lop').property('lang', 'java').as_('lop').add_v('person').property('name', 'josh').property('age', 32).as_('josh').add_v('person').property('name', 'peter').property('age', 35).as_('peter').add_v('software').property('name', 'ripple').property('lang', 'java').as_('ripple').add_e('knows').f [...]
+ },
+ {
+ "original": "g.V(vid1).property(\"creatorCount\", __.V(vid1).in(\"created\").count())",
+ "language": "g.V(vid1).property(\"creatorCount\", __.V(vid1).in(\"created\").count())",
+ "canonical": "g.V(vid1).property(\"creatorCount\", __.V(vid1).in(\"created\").count())",
+ "anonymized": "g.V(vid1).property(string0, __.V(vid1).in(string1).count())",
+ "dotnet": "g.V(vid1).Property(\"creatorCount\", __.V(vid1).In(\"created\").Count())",
+ "go": "g.V(vid1).Property(\"creatorCount\", gremlingo.T__.V(vid1).In(\"created\").Count())",
+ "groovy": "g.V(vid1).property(\"creatorCount\", __.V(vid1).in(\"created\").count())",
+ "java": "g.V(vid1).property(\"creatorCount\", __.V(vid1).in(\"created\").count())",
+ "javascript": "g.V(vid1).property(\"creatorCount\", __.V(vid1).in_(\"created\").count())",
+ "python": "g.V(vid1).property('creatorCount', __.V(vid1).in_('created').count())"
+ },
+ {
+ "original": "g.V().has(\"creatorCount\", 3L)",
+ "language": "g.V().has(\"creatorCount\", 3l)",
+ "canonical": "g.V().has(\"creatorCount\", 3l)",
+ "anonymized": "g.V().has(string0, long0)",
+ "dotnet": "g.V().Has(\"creatorCount\", 3l)",
+ "go": "g.V().Has(\"creatorCount\", int64(3))",
+ "groovy": "g.V().has(\"creatorCount\", 3l)",
+ "java": "g.V().has(\"creatorCount\", 3l)",
+ "javascript": "g.V().has(\"creatorCount\", 3)",
+ "python": "g.V().has('creatorCount', long(3))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_VXvid1X_propertyXknownCount_outXknowsX_countX",
+ "traversals": [
+ {
+ "original": "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\").addV(\"person\").property(\"name\",\"josh\").property(\"age\",32).as(\"josh\").addV(\"person\").property(\"name\",\"peter\").property(\"age\",35).addV(\"software\").property(\"name\",\"ripple\").property(\"lang\",\"java\").ad [...]
+ "language": "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\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", [...]
+ "canonical": "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\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", [...]
+ "anonymized": "g.addV(string0).property(string1, string2).property(string3, number0).as(string2).addV(string0).property(string1, string4).property(string3, number1).as(string4).addV(string5).property(string1, string6).property(string7, string8).addV(string0).property(string1, string9).property(string3, number2).as(string9).addV(string0).property(string1, string10).property(string3, number3).addV(string5).property(string1, string11).property(string7, string8).addE(string12 [...]
+ "dotnet": "g.AddV((string) \"person\").Property(\"name\", \"marko\").Property(\"age\", 29).As(\"marko\").AddV((string) \"person\").Property(\"name\", \"vadas\").Property(\"age\", 27).As(\"vadas\").AddV((string) \"software\").Property(\"name\", \"lop\").Property(\"lang\", \"java\").AddV((string) \"person\").Property(\"name\", \"josh\").Property(\"age\", 32).As(\"josh\").AddV((string) \"person\").Property(\"name\", \"peter\").Property(\"age\", 35).AddV((string) \"software\" [...]
+ "go": "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\").AddV(\"person\").Property(\"name\", \"josh\").Property(\"age\", 32).As(\"josh\").AddV(\"person\").Property(\"name\", \"peter\").Property(\"age\", 35).AddV(\"software\").Property(\"name\", \"ripple\").Property(\"lang\", \"java [...]
+ "groovy": "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\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \" [...]
+ "java": "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\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"ja [...]
+ "javascript": "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\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\" [...]
+ "python": "g.add_v('person').property('name', 'marko').property('age', 29).as_('marko').add_v('person').property('name', 'vadas').property('age', 27).as_('vadas').add_v('software').property('name', 'lop').property('lang', 'java').add_v('person').property('name', 'josh').property('age', 32).as_('josh').add_v('person').property('name', 'peter').property('age', 35).add_v('software').property('name', 'ripple').property('lang', 'java').add_e('knows').from_('marko').to('vadas') [...]
+ },
+ {
+ "original": "g.V(vid1).property(\"knownCount\", __.out(\"knows\").count())",
+ "language": "g.V(vid1).property(\"knownCount\", __.out(\"knows\").count())",
+ "canonical": "g.V(vid1).property(\"knownCount\", __.out(\"knows\").count())",
+ "anonymized": "g.V(vid1).property(string0, __.out(string1).count())",
+ "dotnet": "g.V(vid1).Property(\"knownCount\", __.Out(\"knows\").Count())",
+ "go": "g.V(vid1).Property(\"knownCount\", gremlingo.T__.Out(\"knows\").Count())",
+ "groovy": "g.V(vid1).property(\"knownCount\", __.out(\"knows\").count())",
+ "java": "g.V(vid1).property(\"knownCount\", __.out(\"knows\").count())",
+ "javascript": "g.V(vid1).property(\"knownCount\", __.out(\"knows\").count())",
+ "python": "g.V(vid1).property('knownCount', __.out('knows').count())"
+ },
+ {
+ "original": "g.V().has(\"knownCount\", 2L)",
+ "language": "g.V().has(\"knownCount\", 2l)",
+ "canonical": "g.V().has(\"knownCount\", 2l)",
+ "anonymized": "g.V().has(string0, long0)",
+ "dotnet": "g.V().Has(\"knownCount\", 2l)",
+ "go": "g.V().Has(\"knownCount\", int64(2))",
+ "groovy": "g.V().has(\"knownCount\", 2l)",
+ "java": "g.V().has(\"knownCount\", 2l)",
+ "javascript": "g.V().has(\"knownCount\", 2)",
+ "python": "g.V().has('knownCount', long(2))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_VXvid1X_propertyXcreator_inXcreatedX_valuesXnameXX",
+ "traversals": [
+ {
+ "original": "g.addV(\"person\").property(\"name\",\"marko\").property(\"age\",29).as(\"marko\").addV(\"person\").property(\"name\",\"vadas\").property(\"age\",27).addV(\"software\").property(\"name\",\"lop\").property(\"lang\",\"java\").as(\"lop\").addV(\"person\").property(\"name\",\"josh\").property(\"age\",32).as(\"josh\").addV(\"person\").property(\"name\",\"peter\").property(\"age\",35).as(\"peter\").addV(\"software\").property(\"name\",\"ripple\").property(\"lang\", [...]
+ "language": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).as(\"peter\").addV(\"software\").property(\"name\", \"ripple\").propert [...]
+ "canonical": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).as(\"peter\").addV(\"software\").property(\"name\", \"ripple\").proper [...]
+ "anonymized": "g.addV(string0).property(string1, string2).property(string3, number0).as(string2).addV(string0).property(string1, string4).property(string3, number1).addV(string5).property(string1, string6).property(string7, string8).as(string6).addV(string0).property(string1, string9).property(string3, number2).as(string9).addV(string0).property(string1, string10).property(string3, number3).as(string10).addV(string5).property(string1, string11).property(string7, string8). [...]
+ "dotnet": "g.AddV((string) \"person\").Property(\"name\", \"marko\").Property(\"age\", 29).As(\"marko\").AddV((string) \"person\").Property(\"name\", \"vadas\").Property(\"age\", 27).AddV((string) \"software\").Property(\"name\", \"lop\").Property(\"lang\", \"java\").As(\"lop\").AddV((string) \"person\").Property(\"name\", \"josh\").Property(\"age\", 32).As(\"josh\").AddV((string) \"person\").Property(\"name\", \"peter\").Property(\"age\", 35).As(\"peter\").AddV((string) [...]
+ "go": "g.AddV(\"person\").Property(\"name\", \"marko\").Property(\"age\", 29).As(\"marko\").AddV(\"person\").Property(\"name\", \"vadas\").Property(\"age\", 27).AddV(\"software\").Property(\"name\", \"lop\").Property(\"lang\", \"java\").As(\"lop\").AddV(\"person\").Property(\"name\", \"josh\").Property(\"age\", 32).As(\"josh\").AddV(\"person\").Property(\"name\", \"peter\").Property(\"age\", 35).As(\"peter\").AddV(\"software\").Property(\"name\", \"ripple\").Property(\"la [...]
+ "groovy": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).as(\"peter\").addV(\"software\").property(\"name\", \"ripple\").property( [...]
+ "java": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).as(\"peter\").addV(\"software\").property(\"name\", \"ripple\").property(\" [...]
+ "javascript": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).as(\"peter\").addV(\"software\").property(\"name\", \"ripple\").prope [...]
+ "python": "g.add_v('person').property('name', 'marko').property('age', 29).as_('marko').add_v('person').property('name', 'vadas').property('age', 27).add_v('software').property('name', 'lop').property('lang', 'java').as_('lop').add_v('person').property('name', 'josh').property('age', 32).as_('josh').add_v('person').property('name', 'peter').property('age', 35).as_('peter').add_v('software').property('name', 'ripple').property('lang', 'java').as_('ripple').add_e('knows').f [...]
+ },
+ {
+ "original": "g.V(vid1).property(\"creator\", __.in(\"created\").values(\"name\"))",
+ "language": "g.V(vid1).property(\"creator\", __.in(\"created\").values(\"name\"))",
+ "canonical": "g.V(vid1).property(\"creator\", __.in(\"created\").values(\"name\"))",
+ "anonymized": "g.V(vid1).property(string0, __.in(string1).values(string2))",
+ "dotnet": "g.V(vid1).Property(\"creator\", __.In(\"created\").Values<object>(\"name\"))",
+ "go": "g.V(vid1).Property(\"creator\", gremlingo.T__.In(\"created\").Values(\"name\"))",
+ "groovy": "g.V(vid1).property(\"creator\", __.in(\"created\").values(\"name\"))",
+ "java": "g.V(vid1).property(\"creator\", __.in(\"created\").values(\"name\"))",
+ "javascript": "g.V(vid1).property(\"creator\", __.in_(\"created\").values(\"name\"))",
+ "python": "g.V(vid1).property('creator', __.in_('created').values('name'))"
+ },
+ {
+ "original": "g.V().has(\"creator\")",
+ "language": "g.V().has(\"creator\")",
+ "canonical": "g.V().has(\"creator\")",
+ "anonymized": "g.V().has(string0)",
+ "dotnet": "g.V().Has(\"creator\")",
+ "go": "g.V().Has(\"creator\")",
+ "groovy": "g.V().has(\"creator\")",
+ "java": "g.V().has(\"creator\")",
+ "javascript": "g.V().has(\"creator\")",
+ "python": "g.V().has('creator')"
+ }
+ ]
+ },
+ {
+ "scenario": "g_VXvid2X_propertyXVXvid1X_projectXfriendCount_softwareCreatedXX",
+ "traversals": [
+ {
+ "original": "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(\"person\").property(\"name\",\"peter\").property(\"age\",35).as(\"peter\").addV(\"software\").property(\"name\",\"ripple\").prop [...]
+ "language": "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(\"person\").property(\"name\", \"peter\").property(\"age\", 35).as(\"peter\").addV(\"software\").property(\"name\", \"rip [...]
+ "canonical": "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(\"person\").property(\"name\", \"peter\").property(\"age\", 35).as(\"peter\").addV(\"software\").property(\"name\", \"ri [...]
+ "anonymized": "g.addV(string0).property(string1, string2).property(string3, number0).as(string2).addV(string0).property(string1, string4).property(string3, number1).as(string4).addV(string5).property(string1, string6).property(string7, string8).as(string6).addV(string0).property(string1, string9).property(string3, number2).as(string9).addV(string0).property(string1, string10).property(string3, number3).as(string10).addV(string5).property(string1, string11).property(string [...]
+ "dotnet": "g.AddV((string) \"person\").Property(\"name\", \"marko\").Property(\"age\", 29).As(\"marko\").AddV((string) \"person\").Property(\"name\", \"vadas\").Property(\"age\", 27).As(\"vadas\").AddV((string) \"software\").Property(\"name\", \"lop\").Property(\"lang\", \"java\").As(\"lop\").AddV((string) \"person\").Property(\"name\", \"josh\").Property(\"age\", 32).As(\"josh\").AddV((string) \"person\").Property(\"name\", \"peter\").Property(\"age\", 35).As(\"peter\"). [...]
+ "go": "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(\"person\").Property(\"name\", \"peter\").Property(\"age\", 35).As(\"peter\").AddV(\"software\").Property(\"name\", \"ripple\") [...]
+ "groovy": "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(\"person\").property(\"name\", \"peter\").property(\"age\", 35).as(\"peter\").addV(\"software\").property(\"name\", \"rippl [...]
+ "java": "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(\"person\").property(\"name\", \"peter\").property(\"age\", 35).as(\"peter\").addV(\"software\").property(\"name\", \"ripple\ [...]
+ "javascript": "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(\"person\").property(\"name\", \"peter\").property(\"age\", 35).as(\"peter\").addV(\"software\").property(\"name\", \"r [...]
+ "python": "g.add_v('person').property('name', 'marko').property('age', 29).as_('marko').add_v('person').property('name', 'vadas').property('age', 27).as_('vadas').add_v('software').property('name', 'lop').property('lang', 'java').as_('lop').add_v('person').property('name', 'josh').property('age', 32).as_('josh').add_v('person').property('name', 'peter').property('age', 35).as_('peter').add_v('software').property('name', 'ripple').property('lang', 'java').as_('ripple').add [...]
+ },
+ {
+ "original": "g.V(vid2).property(__.V(vid1).project(\"friendCount\",\"softwareCreated\").by(__.out(\"knows\").count()).by(__.out(\"created\").values(\"name\")))",
+ "language": "g.V(vid2).property(__.V(vid1).project(\"friendCount\", \"softwareCreated\").by(__.out(\"knows\").count()).by(__.out(\"created\").values(\"name\")))",
+ "canonical": "g.V(vid2).property(__.V(vid1).project(\"friendCount\", \"softwareCreated\").by(__.out(\"knows\").count()).by(__.out(\"created\").values(\"name\")))",
+ "anonymized": "g.V(vid2).property(__.V(vid1).project(string0, string1).by(__.out(string2).count()).by(__.out(string3).values(string4)))",
+ "dotnet": "g.V(vid2).Property(__.V(vid1).Project<object>(\"friendCount\", \"softwareCreated\").By(__.Out(\"knows\").Count()).By(__.Out(\"created\").Values<object>(\"name\")))",
+ "go": "g.V(vid2).Property(gremlingo.T__.V(vid1).Project(\"friendCount\", \"softwareCreated\").By(gremlingo.T__.Out(\"knows\").Count()).By(gremlingo.T__.Out(\"created\").Values(\"name\")))",
+ "groovy": "g.V(vid2).property(__.V(vid1).project(\"friendCount\", \"softwareCreated\").by(__.out(\"knows\").count()).by(__.out(\"created\").values(\"name\")))",
+ "java": "g.V(vid2).property(__.V(vid1).project(\"friendCount\", \"softwareCreated\").by(__.out(\"knows\").count()).by(__.out(\"created\").values(\"name\")))",
+ "javascript": "g.V(vid2).property(__.V(vid1).project(\"friendCount\", \"softwareCreated\").by(__.out(\"knows\").count()).by(__.out(\"created\").values(\"name\")))",
+ "python": "g.V(vid2).property(__.V(vid1).project('friendCount', 'softwareCreated').by(__.out('knows').count()).by(__.out('created').values('name')))"
+ },
+ {
+ "original": "g.V().has(\"friendCount\", 2L)",
+ "language": "g.V().has(\"friendCount\", 2l)",
+ "canonical": "g.V().has(\"friendCount\", 2l)",
+ "anonymized": "g.V().has(string0, long0)",
+ "dotnet": "g.V().Has(\"friendCount\", 2l)",
+ "go": "g.V().Has(\"friendCount\", int64(2))",
+ "groovy": "g.V().has(\"friendCount\", 2l)",
+ "java": "g.V().has(\"friendCount\", 2l)",
+ "javascript": "g.V().has(\"friendCount\", 2)",
+ "python": "g.V().has('friendCount', long(2))"
+ },
+ {
+ "original": "g.V().has(\"softwareCreated\", \"lop\")",
+ "language": "g.V().has(\"softwareCreated\", \"lop\")",
+ "canonical": "g.V().has(\"softwareCreated\", \"lop\")",
+ "anonymized": "g.V().has(string0, string1)",
+ "dotnet": "g.V().Has(\"softwareCreated\", \"lop\")",
+ "go": "g.V().Has(\"softwareCreated\", \"lop\")",
+ "groovy": "g.V().has(\"softwareCreated\", \"lop\")",
+ "java": "g.V().has(\"softwareCreated\", \"lop\")",
+ "javascript": "g.V().has(\"softwareCreated\", \"lop\")",
+ "python": "g.V().has('softwareCreated', 'lop')"
+ }
+ ]
+ },
+ {
+ "scenario": "g_VXvid2X_propertyXVXvid1X_projectXoriginalName_originalLabelX_byXnameX_byXlabelXX",
+ "traversals": [
+ {
+ "original": "g.addV(\"person\").property(\"name\",\"marko\").property(\"age\",29).as(\"marko\").addV(\"person\").property(\"name\",\"vadas\").property(\"age\",27).addV(\"software\").property(\"name\",\"lop\").property(\"lang\",\"java\").as(\"lop\").addV(\"person\").property(\"name\",\"josh\").property(\"age\",32).addV(\"person\").property(\"name\",\"peter\").property(\"age\",35).addV(\"software\").property(\"name\",\"ripple\").property(\"lang\",\"java\")",
+ "language": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\")",
+ "canonical": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\")",
+ "anonymized": "g.addV(string0).property(string1, string2).property(string3, number0).as(string2).addV(string0).property(string1, string4).property(string3, number1).addV(string5).property(string1, string6).property(string7, string8).as(string6).addV(string0).property(string1, string9).property(string3, number2).addV(string0).property(string1, string10).property(string3, number3).addV(string5).property(string1, string11).property(string7, string8)",
+ "dotnet": "g.AddV((string) \"person\").Property(\"name\", \"marko\").Property(\"age\", 29).As(\"marko\").AddV((string) \"person\").Property(\"name\", \"vadas\").Property(\"age\", 27).AddV((string) \"software\").Property(\"name\", \"lop\").Property(\"lang\", \"java\").As(\"lop\").AddV((string) \"person\").Property(\"name\", \"josh\").Property(\"age\", 32).AddV((string) \"person\").Property(\"name\", \"peter\").Property(\"age\", 35).AddV((string) \"software\").Property(\"na [...]
+ "go": "g.AddV(\"person\").Property(\"name\", \"marko\").Property(\"age\", 29).As(\"marko\").AddV(\"person\").Property(\"name\", \"vadas\").Property(\"age\", 27).AddV(\"software\").Property(\"name\", \"lop\").Property(\"lang\", \"java\").As(\"lop\").AddV(\"person\").Property(\"name\", \"josh\").Property(\"age\", 32).AddV(\"person\").Property(\"name\", \"peter\").Property(\"age\", 35).AddV(\"software\").Property(\"name\", \"ripple\").Property(\"lang\", \"java\")",
+ "groovy": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\")",
+ "java": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\")",
+ "javascript": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\")",
+ "python": "g.add_v('person').property('name', 'marko').property('age', 29).as_('marko').add_v('person').property('name', 'vadas').property('age', 27).add_v('software').property('name', 'lop').property('lang', 'java').as_('lop').add_v('person').property('name', 'josh').property('age', 32).add_v('person').property('name', 'peter').property('age', 35).add_v('software').property('name', 'ripple').property('lang', 'java')"
+ },
+ {
+ "original": "g.V(vid2).property(__.V(vid1).project(\"originalName\",\"originalLabel\").by(__.values(\"name\")).by(__.label()))",
+ "language": "g.V(vid2).property(__.V(vid1).project(\"originalName\", \"originalLabel\").by(__.values(\"name\")).by(__.label()))",
+ "canonical": "g.V(vid2).property(__.V(vid1).project(\"originalName\", \"originalLabel\").by(__.values(\"name\")).by(__.label()))",
+ "anonymized": "g.V(vid2).property(__.V(vid1).project(string0, string1).by(__.values(string2)).by(__.label()))",
+ "dotnet": "g.V(vid2).Property(__.V(vid1).Project<object>(\"originalName\", \"originalLabel\").By(__.Values<object>(\"name\")).By(__.Label()))",
+ "go": "g.V(vid2).Property(gremlingo.T__.V(vid1).Project(\"originalName\", \"originalLabel\").By(gremlingo.T__.Values(\"name\")).By(gremlingo.T__.Label()))",
+ "groovy": "g.V(vid2).property(__.V(vid1).project(\"originalName\", \"originalLabel\").by(__.values(\"name\")).by(__.label()))",
+ "java": "g.V(vid2).property(__.V(vid1).project(\"originalName\", \"originalLabel\").by(__.values(\"name\")).by(__.label()))",
+ "javascript": "g.V(vid2).property(__.V(vid1).project(\"originalName\", \"originalLabel\").by(__.values(\"name\")).by(__.label()))",
+ "python": "g.V(vid2).property(__.V(vid1).project('originalName', 'originalLabel').by(__.values('name')).by(__.label()))"
+ },
+ {
+ "original": "g.V(vid2).has(\"originalName\", \"marko\")",
+ "language": "g.V(vid2).has(\"originalName\", \"marko\")",
+ "canonical": "g.V(vid2).has(\"originalName\", \"marko\")",
+ "anonymized": "g.V(vid2).has(string0, string1)",
+ "dotnet": "g.V(vid2).Has(\"originalName\", \"marko\")",
+ "go": "g.V(vid2).Has(\"originalName\", \"marko\")",
+ "groovy": "g.V(vid2).has(\"originalName\", \"marko\")",
+ "java": "g.V(vid2).has(\"originalName\", \"marko\")",
+ "javascript": "g.V(vid2).has(\"originalName\", \"marko\")",
+ "python": "g.V(vid2).has('originalName', 'marko')"
+ },
+ {
+ "original": "g.V(vid2).has(\"originalLabel\", \"person\")",
+ "language": "g.V(vid2).has(\"originalLabel\", \"person\")",
+ "canonical": "g.V(vid2).has(\"originalLabel\", \"person\")",
+ "anonymized": "g.V(vid2).has(string0, string1)",
+ "dotnet": "g.V(vid2).Has(\"originalLabel\", \"person\")",
+ "go": "g.V(vid2).Has(\"originalLabel\", \"person\")",
+ "groovy": "g.V(vid2).has(\"originalLabel\", \"person\")",
+ "java": "g.V(vid2).has(\"originalLabel\", \"person\")",
+ "javascript": "g.V(vid2).has(\"originalLabel\", \"person\")",
+ "python": "g.V(vid2).has('originalLabel', 'person')"
+ }
+ ]
+ },
+ {
+ "scenario": "g_VXvid1X_propertyXlist_friends_outXknowsX_valuesXnameXX",
+ "traversals": [
+ {
+ "original": "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\").addV(\"person\").property(\"name\",\"josh\").property(\"age\",32).as(\"josh\").addV(\"person\").property(\"name\",\"peter\").property(\"age\",35).addV(\"software\").property(\"name\",\"ripple\").property(\"lang\",\"java\").ad [...]
+ "language": "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\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", [...]
+ "canonical": "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\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", [...]
+ "anonymized": "g.addV(string0).property(string1, string2).property(string3, number0).as(string2).addV(string0).property(string1, string4).property(string3, number1).as(string4).addV(string5).property(string1, string6).property(string7, string8).addV(string0).property(string1, string9).property(string3, number2).as(string9).addV(string0).property(string1, string10).property(string3, number3).addV(string5).property(string1, string11).property(string7, string8).addE(string12 [...]
+ "dotnet": "g.AddV((string) \"person\").Property(\"name\", \"marko\").Property(\"age\", 29).As(\"marko\").AddV((string) \"person\").Property(\"name\", \"vadas\").Property(\"age\", 27).As(\"vadas\").AddV((string) \"software\").Property(\"name\", \"lop\").Property(\"lang\", \"java\").AddV((string) \"person\").Property(\"name\", \"josh\").Property(\"age\", 32).As(\"josh\").AddV((string) \"person\").Property(\"name\", \"peter\").Property(\"age\", 35).AddV((string) \"software\" [...]
+ "go": "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\").AddV(\"person\").Property(\"name\", \"josh\").Property(\"age\", 32).As(\"josh\").AddV(\"person\").Property(\"name\", \"peter\").Property(\"age\", 35).AddV(\"software\").Property(\"name\", \"ripple\").Property(\"lang\", \"java [...]
+ "groovy": "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\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \" [...]
+ "java": "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\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"ja [...]
+ "javascript": "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\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\" [...]
+ "python": "g.add_v('person').property('name', 'marko').property('age', 29).as_('marko').add_v('person').property('name', 'vadas').property('age', 27).as_('vadas').add_v('software').property('name', 'lop').property('lang', 'java').add_v('person').property('name', 'josh').property('age', 32).as_('josh').add_v('person').property('name', 'peter').property('age', 35).add_v('software').property('name', 'ripple').property('lang', 'java').add_e('knows').from_('marko').to('vadas') [...]
+ },
+ {
+ "original": "g.V(vid1).property(Cardinality.list, \"friends\", __.out(\"knows\").values(\"name\"))",
+ "language": "g.V(vid1).property(Cardinality.list, \"friends\", __.out(\"knows\").values(\"name\"))",
+ "canonical": "g.V(vid1).property(Cardinality.list, \"friends\", __.out(\"knows\").values(\"name\"))",
+ "anonymized": "g.V(vid1).property(Cardinality.list, string0, __.out(string1).values(string2))",
+ "dotnet": "g.V(vid1).Property(Cardinality.List, \"friends\", __.Out(\"knows\").Values<object>(\"name\"))",
+ "go": "g.V(vid1).Property(gremlingo.Cardinality.List, \"friends\", gremlingo.T__.Out(\"knows\").Values(\"name\"))",
+ "groovy": "g.V(vid1).property(Cardinality.list, \"friends\", __.out(\"knows\").values(\"name\"))",
+ "java": "g.V(vid1).property(Cardinality.list, \"friends\", __.out(\"knows\").values(\"name\"))",
+ "javascript": "g.V(vid1).property(Cardinality.list, \"friends\", __.out(\"knows\").values(\"name\"))",
+ "python": "g.V(vid1).property(Cardinality.list_, 'friends', __.out('knows').values('name'))"
+ },
+ {
+ "original": "g.V(vid1).properties(\"friends\")",
+ "language": "g.V(vid1).properties(\"friends\")",
+ "canonical": "g.V(vid1).properties(\"friends\")",
+ "anonymized": "g.V(vid1).properties(string0)",
+ "dotnet": "g.V(vid1).Properties<object>(\"friends\")",
+ "go": "g.V(vid1).Properties(\"friends\")",
+ "groovy": "g.V(vid1).properties(\"friends\")",
+ "java": "g.V(vid1).properties(\"friends\")",
+ "javascript": "g.V(vid1).properties(\"friends\")",
+ "python": "g.V(vid1).properties('friends')"
+ }
+ ]
+ },
+ {
+ "scenario": "g_VXvid1X_propertyXset_langs_outXcreatedX_valuesXlangXX",
+ "traversals": [
+ {
+ "original": "g.addV(\"person\").property(\"name\",\"marko\").property(\"age\",29).addV(\"person\").property(\"name\",\"vadas\").property(\"age\",27).addV(\"software\").property(\"name\",\"lop\").property(\"lang\",\"java\").as(\"lop\").addV(\"person\").property(\"name\",\"josh\").property(\"age\",32).as(\"josh\").addV(\"person\").property(\"name\",\"peter\").property(\"age\",35).addV(\"software\").property(\"name\",\"ripple\").property(\"lang\",\"java\").as(\"ripple\").add [...]
+ "language": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").as(\"r [...]
+ "canonical": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").as(\" [...]
+ "anonymized": "g.addV(string0).property(string1, string2).property(string3, number0).addV(string0).property(string1, string4).property(string3, number1).addV(string5).property(string1, string6).property(string7, string8).as(string6).addV(string0).property(string1, string9).property(string3, number2).as(string9).addV(string0).property(string1, string10).property(string3, number3).addV(string5).property(string1, string11).property(string7, string8).as(string11).addE(string1 [...]
+ "dotnet": "g.AddV((string) \"person\").Property(\"name\", \"marko\").Property(\"age\", 29).AddV((string) \"person\").Property(\"name\", \"vadas\").Property(\"age\", 27).AddV((string) \"software\").Property(\"name\", \"lop\").Property(\"lang\", \"java\").As(\"lop\").AddV((string) \"person\").Property(\"name\", \"josh\").Property(\"age\", 32).As(\"josh\").AddV((string) \"person\").Property(\"name\", \"peter\").Property(\"age\", 35).AddV((string) \"software\").Property(\"nam [...]
+ "go": "g.AddV(\"person\").Property(\"name\", \"marko\").Property(\"age\", 29).AddV(\"person\").Property(\"name\", \"vadas\").Property(\"age\", 27).AddV(\"software\").Property(\"name\", \"lop\").Property(\"lang\", \"java\").As(\"lop\").AddV(\"person\").Property(\"name\", \"josh\").Property(\"age\", 32).As(\"josh\").AddV(\"person\").Property(\"name\", \"peter\").Property(\"age\", 35).AddV(\"software\").Property(\"name\", \"ripple\").Property(\"lang\", \"java\").As(\"ripple\ [...]
+ "groovy": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").as(\"rip [...]
+ "java": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").as(\"rippl [...]
+ "javascript": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").as(\ [...]
+ "python": "g.add_v('person').property('name', 'marko').property('age', 29).add_v('person').property('name', 'vadas').property('age', 27).add_v('software').property('name', 'lop').property('lang', 'java').as_('lop').add_v('person').property('name', 'josh').property('age', 32).as_('josh').add_v('person').property('name', 'peter').property('age', 35).add_v('software').property('name', 'ripple').property('lang', 'java').as_('ripple').add_e('created').from_('josh').to('lop').a [...]
+ },
+ {
+ "original": "g.V(vid1).property(Cardinality.set, \"langs\", __.out(\"created\").values(\"lang\"))",
+ "language": "g.V(vid1).property(Cardinality.set, \"langs\", __.out(\"created\").values(\"lang\"))",
+ "canonical": "g.V(vid1).property(Cardinality.set, \"langs\", __.out(\"created\").values(\"lang\"))",
+ "anonymized": "g.V(vid1).property(Cardinality.set, string0, __.out(string1).values(string2))",
+ "dotnet": "g.V(vid1).Property(Cardinality.Set, \"langs\", __.Out(\"created\").Values<object>(\"lang\"))",
+ "go": "g.V(vid1).Property(gremlingo.Cardinality.Set, \"langs\", gremlingo.T__.Out(\"created\").Values(\"lang\"))",
+ "groovy": "g.V(vid1).property(Cardinality.set, \"langs\", __.out(\"created\").values(\"lang\"))",
+ "java": "g.V(vid1).property(Cardinality.set, \"langs\", __.out(\"created\").values(\"lang\"))",
+ "javascript": "g.V(vid1).property(Cardinality.set, \"langs\", __.out(\"created\").values(\"lang\"))",
+ "python": "g.V(vid1).property(Cardinality.set_, 'langs', __.out('created').values('lang'))"
+ },
+ {
+ "original": "g.V(vid1).properties(\"langs\")",
+ "language": "g.V(vid1).properties(\"langs\")",
+ "canonical": "g.V(vid1).properties(\"langs\")",
+ "anonymized": "g.V(vid1).properties(string0)",
+ "dotnet": "g.V(vid1).Properties<object>(\"langs\")",
+ "go": "g.V(vid1).Properties(\"langs\")",
+ "groovy": "g.V(vid1).properties(\"langs\")",
+ "java": "g.V(vid1).properties(\"langs\")",
+ "javascript": "g.V(vid1).properties(\"langs\")",
+ "python": "g.V(vid1).properties('langs')"
+ }
+ ]
+ },
+ {
+ "scenario": "g_VXvid1X_propertyXsingle_friend_outXknowsX_valuesXnameXX",
+ "traversals": [
+ {
+ "original": "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\").addV(\"person\").property(\"name\",\"josh\").property(\"age\",32).as(\"josh\").addV(\"person\").property(\"name\",\"peter\").property(\"age\",35).addV(\"software\").property(\"name\",\"ripple\").property(\"lang\",\"java\").ad [...]
+ "language": "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\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", [...]
+ "canonical": "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\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", [...]
+ "anonymized": "g.addV(string0).property(string1, string2).property(string3, number0).as(string2).addV(string0).property(string1, string4).property(string3, number1).as(string4).addV(string5).property(string1, string6).property(string7, string8).addV(string0).property(string1, string9).property(string3, number2).as(string9).addV(string0).property(string1, string10).property(string3, number3).addV(string5).property(string1, string11).property(string7, string8).addE(string12 [...]
+ "dotnet": "g.AddV((string) \"person\").Property(\"name\", \"marko\").Property(\"age\", 29).As(\"marko\").AddV((string) \"person\").Property(\"name\", \"vadas\").Property(\"age\", 27).As(\"vadas\").AddV((string) \"software\").Property(\"name\", \"lop\").Property(\"lang\", \"java\").AddV((string) \"person\").Property(\"name\", \"josh\").Property(\"age\", 32).As(\"josh\").AddV((string) \"person\").Property(\"name\", \"peter\").Property(\"age\", 35).AddV((string) \"software\" [...]
+ "go": "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\").AddV(\"person\").Property(\"name\", \"josh\").Property(\"age\", 32).As(\"josh\").AddV(\"person\").Property(\"name\", \"peter\").Property(\"age\", 35).AddV(\"software\").Property(\"name\", \"ripple\").Property(\"lang\", \"java [...]
+ "groovy": "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\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \" [...]
+ "java": "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\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"ja [...]
+ "javascript": "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\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\" [...]
+ "python": "g.add_v('person').property('name', 'marko').property('age', 29).as_('marko').add_v('person').property('name', 'vadas').property('age', 27).as_('vadas').add_v('software').property('name', 'lop').property('lang', 'java').add_v('person').property('name', 'josh').property('age', 32).as_('josh').add_v('person').property('name', 'peter').property('age', 35).add_v('software').property('name', 'ripple').property('lang', 'java').add_e('knows').from_('marko').to('vadas') [...]
+ },
+ {
+ "original": "g.V(vid1).property(Cardinality.single, \"friend\", __.out(\"knows\").values(\"name\"))",
+ "language": "g.V(vid1).property(Cardinality.single, \"friend\", __.out(\"knows\").values(\"name\"))",
+ "canonical": "g.V(vid1).property(Cardinality.single, \"friend\", __.out(\"knows\").values(\"name\"))",
+ "anonymized": "g.V(vid1).property(Cardinality.single, string0, __.out(string1).values(string2))",
+ "dotnet": "g.V(vid1).Property(Cardinality.Single, \"friend\", __.Out(\"knows\").Values<object>(\"name\"))",
+ "go": "g.V(vid1).Property(gremlingo.Cardinality.Single, \"friend\", gremlingo.T__.Out(\"knows\").Values(\"name\"))",
+ "groovy": "g.V(vid1).property(Cardinality.single, \"friend\", __.out(\"knows\").values(\"name\"))",
+ "java": "g.V(vid1).property(Cardinality.single, \"friend\", __.out(\"knows\").values(\"name\"))",
+ "javascript": "g.V(vid1).property(Cardinality.single, \"friend\", __.out(\"knows\").values(\"name\"))",
+ "python": "g.V(vid1).property(Cardinality.single, 'friend', __.out('knows').values('name'))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_VXvid1X_propertyXVXvid1X_groupX_byXidX_byXvaluesXnameXXX",
+ "traversals": [
+ {
+ "original": "g.addV(\"person\").property(\"name\",\"marko\").property(\"age\",29)",
+ "language": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29)",
+ "canonical": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29)",
+ "anonymized": "g.addV(string0).property(string1, string2).property(string3, number0)",
+ "dotnet": "g.AddV((string) \"person\").Property(\"name\", \"marko\").Property(\"age\", 29)",
+ "go": "g.AddV(\"person\").Property(\"name\", \"marko\").Property(\"age\", 29)",
+ "groovy": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29)",
+ "java": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29)",
+ "javascript": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29)",
+ "python": "g.add_v('person').property('name', 'marko').property('age', 29)"
+ },
+ {
+ "original": "g.V(vid1).property(__.V(vid1).group().by(__.id()).by(__.values(\"name\")))",
+ "language": "g.V(vid1).property(__.V(vid1).group().by(__.id()).by(__.values(\"name\")))",
+ "canonical": "g.V(vid1).property(__.V(vid1).group().by(__.id()).by(__.values(\"name\")))",
+ "anonymized": "g.V(vid1).property(__.V(vid1).group().by(__.id()).by(__.values(string0)))",
+ "dotnet": "g.V(vid1).Property(__.V(vid1).Group<object, object>().By(__.Id()).By(__.Values<object>(\"name\")))",
+ "go": "g.V(vid1).Property(gremlingo.T__.V(vid1).Group().By(gremlingo.T__.Id()).By(gremlingo.T__.Values(\"name\")))",
+ "groovy": "g.V(vid1).property(__.V(vid1).group().by(__.id()).by(__.values(\"name\")))",
+ "java": "g.V(vid1).property(__.V(vid1).group().by(__.id()).by(__.values(\"name\")))",
+ "javascript": "g.V(vid1).property(__.V(vid1).group().by(__.id()).by(__.values(\"name\")))",
+ "python": "g.V(vid1).property(__.V(vid1).group().by(__.id_()).by(__.values('name')))"
+ }
+ ]
+ },
{
"scenario": "g_io_readXkryoX",
"traversals": [
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/HasTraversal.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/HasTraversal.feature
new file mode 100644
index 0000000000..4d38167e4d
--- /dev/null
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/HasTraversal.feature
@@ -0,0 +1,203 @@
+# 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.
+
+@StepClassFilter @StepHas
+Feature: Step - has() with traversal arguments
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_hasXname_VXvid1X_valuesXnameXX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V().has("name", __.V(vid1).values("name"))
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | v[marko] |
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_hasXname_VXvid1X_outXknowsX_valuesXnameXX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V().has("name", __.V(vid1).out("knows").values("name"))
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | v[vadas] |
+ | v[josh] |
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_hasXage_VXvid1X_outXknowsX_valuesXageXX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V().has("age", __.V(vid1).out("knows").values("age"))
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | v[vadas] |
+ | v[josh] |
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_hasXname_VXvid1X_valuesXnonexistentXX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V().has("name", __.V(vid1).values("nonexistent"))
+ """
+ When iterated to list
+ Then the result should be empty
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_hasXname_notXidentityXX
+ Given the modern graph
+ And the traversal of
+ """
+ g.V().has("name", __.not(__.identity()))
+ """
+ When iterated to list
+ Then the result should be empty
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_hasXage_gtXVXvid1X_valuesXageXXX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V().has("age", P.gt(__.V(vid1).values("age")))
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | v[josh] |
+ | v[peter] |
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_hasXage_lteXVXvid2X_valuesXageXXX
+ Given the modern graph
+ And using the parameter vid2 defined as "v[vadas].id"
+ And the traversal of
+ """
+ g.V().has("age", P.lte(__.V(vid2).values("age")))
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | v[vadas] |
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_hasXage_neqXVXvid3X_valuesXageXXX
+ Given the modern graph
+ And using the parameter vid3 defined as "v[josh].id"
+ And the traversal of
+ """
+ g.V().has("age", P.neq(__.V(vid3).values("age")))
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | v[marko] |
+ | v[vadas] |
+ | v[peter] |
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_hasXname_eqXVXvid1X_valuesXnameXXX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V().has("name", P.eq(__.V(vid1).values("name")))
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | v[marko] |
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_hasXage_ltXVXvid1X_valuesXageXXX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V().has("age", P.lt(__.V(vid1).values("age")))
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | v[vadas] |
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_hasXage_gteXVXvid3X_valuesXageXXX
+ Given the modern graph
+ And using the parameter vid3 defined as "v[josh].id"
+ And the traversal of
+ """
+ g.V().has("age", P.gte(__.V(vid3).values("age")))
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | v[josh] |
+ | v[peter] |
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_hasXage_eqXVXvid1X_valuesXnonexistentXXX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V().has("age", P.eq(__.V(vid1).values("nonexistent")))
+ """
+ When iterated to list
+ Then the result should be empty
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_hasXlabel_VXvid1X_labelXX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V().has(T.label, __.V(vid1).label())
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | v[marko] |
+ | v[vadas] |
+ | v[josh] |
+ | v[peter] |
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_hasXperson_name_VXvid1X_valuesXnameXX_age
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V().has("person", "name", __.V(vid1).values("name")).values("age")
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | d[29].i |
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/IsTraversal.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/IsTraversal.feature
new file mode 100644
index 0000000000..495067b6cb
--- /dev/null
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/IsTraversal.feature
@@ -0,0 +1,257 @@
+# 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.
+
+@StepClassFilter @StepIs
+Feature: Step - is() with traversal-bearing predicates
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_valuesXageX_isXVXvid1X_valuesXageXX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V().values("age").is(__.V(vid1).values("age"))
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | d[29].i |
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_valuesXnameX_isXVXvid1X_valuesXnameXX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V().values("name").is(__.V(vid1).values("name"))
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | marko |
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_valuesXageX_isXgtXVXvid1X_valuesXageXXX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V().values("age").is(P.gt(__.V(vid1).values("age")))
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | d[32].i |
+ | d[35].i |
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_valuesXageX_isXltXVXvid3X_valuesXageXXX
+ Given the modern graph
+ And using the parameter vid3 defined as "v[josh].id"
+ And the traversal of
+ """
+ g.V().values("age").is(P.lt(__.V(vid3).values("age")))
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | d[29].i |
+ | d[27].i |
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_valuesXageX_isXneqXVXvid4X_valuesXageXXX
+ Given the modern graph
+ And using the parameter vid4 defined as "v[peter].id"
+ And the traversal of
+ """
+ g.V().values("age").is(P.neq(__.V(vid4).values("age")))
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | d[29].i |
+ | d[27].i |
+ | d[32].i |
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_valuesXageX_isXwithinXVXvid1X_outXknowsX_valuesXageXXX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V().values("age").is(P.within(__.V(vid1).out("knows").values("age")))
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | d[27].i |
+ | d[32].i |
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_valuesXageX_isXVXvid1X_valuesXnonexistentXX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V().values("age").is(__.V(vid1).values("nonexistent"))
+ """
+ When iterated to list
+ Then the result should be empty
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_hasLabelXpersonX_valuesXageX_chooseXgtXVXvid1X_valuesXageXX_olderX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V().hasLabel("person").values("age").choose(P.gt(__.V(vid1).values("age")), __.constant("older than marko"), __.constant("not older"))
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | not older |
+ | not older |
+ | older than marko |
+ | older than marko |
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_hasLabelXpersonX_valuesXageX_chooseXgteXmeanAgeX_aboveX
+ Given the modern graph
+ And the traversal of
+ """
+ g.V().hasLabel("person").values("age").choose(P.gte(__.V().hasLabel("person").values("age").mean()), __.constant("above average"), __.constant("below average"))
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | below average |
+ | below average |
+ | above average |
+ | above average |
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_VXvid1X_outXknowsX_valuesXageX_fold_allXgteXVXvid2X_valuesXageXXX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And using the parameter vid2 defined as "v[vadas].id"
+ And the traversal of
+ """
+ g.V(vid1).out("knows").values("age").fold().all(P.gte(__.V(vid2).values("age")))
+ """
+ When iterated to list
+ Then the result should have a count of 1
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_VXvid1X_outXknowsX_valuesXageX_fold_allXgtXVXvid2X_valuesXageXXX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And using the parameter vid2 defined as "v[vadas].id"
+ And the traversal of
+ """
+ g.V(vid1).out("knows").values("age").fold().all(P.gt(__.V(vid2).values("age")))
+ """
+ When iterated to list
+ Then the result should be empty
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_VXvid1X_outXknowsX_valuesXageX_fold_anyXeqXVXvid3X_valuesXageXXX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And using the parameter vid3 defined as "v[josh].id"
+ And the traversal of
+ """
+ g.V(vid1).out("knows").values("age").fold().any(P.eq(__.V(vid3).values("age")))
+ """
+ When iterated to list
+ Then the result should have a count of 1
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_VXvid1X_outXknowsX_valuesXageX_fold_noneXeqXVXvid4X_valuesXageXXX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And using the parameter vid4 defined as "v[peter].id"
+ And the traversal of
+ """
+ g.V(vid1).out("knows").values("age").fold().none(P.eq(__.V(vid4).values("age")))
+ """
+ When iterated to list
+ Then the result should have a count of 1
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_VXvid1X_outXknowsX_valuesXageX_fold_noneXeqXVXvid3X_valuesXageXXX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And using the parameter vid3 defined as "v[josh].id"
+ And the traversal of
+ """
+ g.V(vid1).out("knows").values("age").fold().none(P.eq(__.V(vid3).values("age")))
+ """
+ When iterated to list
+ Then the result should be empty
+
+ # Empty-result handling: predicate should treat "no results" as "no match", not null.
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_injectXnullX_isXeqXV9999_valuesXnameXXX
+ Given the modern graph
+ And the traversal of
+ """
+ g.inject(null).is(P.eq(__.V(9999).values("name")))
+ """
+ When iterated to list
+ Then the result should be empty
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_injectXmarkoX_isXV9999_valuesXnameXX
+ Given the modern graph
+ And the traversal of
+ """
+ g.inject("marko").is(__.V(9999).values("name"))
+ """
+ When iterated to list
+ Then the result should be empty
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_injectXmarkoX_chooseXeqXV9999_valuesXnameXX_matched_unmatchedX
+ Given the modern graph
+ And the traversal of
+ """
+ g.inject("marko").choose(P.eq(__.V(9999).values("name")), __.constant("matched"), __.constant("unmatched"))
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | unmatched |
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_injectXlistX_noneXeqXV9999_valuesXnameXXX
+ Given the modern graph
+ And the traversal of
+ """
+ g.inject(["marko","josh"]).none(P.eq(__.V(9999).values("name")))
+ """
+ When iterated to list
+ Then the result should have a count of 1
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_hasXname_eqXV9999_valuesXnameXXX
+ Given the modern graph
+ And the traversal of
+ """
+ g.V().has("name", P.eq(__.V(9999).values("name")))
+ """
+ When iterated to list
+ Then the result should be empty
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/VETraversal.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/VETraversal.feature
new file mode 100644
index 0000000000..7bddadb221
--- /dev/null
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/VETraversal.feature
@@ -0,0 +1,143 @@
+# 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.
+
+@StepClassMap @StepVertex @StepE
+Feature: Step - V(traversal) and E(traversal)
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_VXvid1X_id_VXidentityX_name
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V(vid1).id().V(__.identity()).values("name")
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | marko |
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_VXvid1_vid2X_id_VXidentityX_name
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And using the parameter vid2 defined as "v[josh].id"
+ And the traversal of
+ """
+ g.V(vid1, vid2).id().V(__.identity()).values("name")
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | marko |
+ | josh |
+
+ # Use as()/select() to bookmark a vertex ID and return to it later via V(select()).
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_VXvid1X_id_asXbookmarkX_V_hasXname_joshX_VXselectXbookmarkXX_name
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V(vid1).id().as("bookmark").V().has("name","josh").V(__.select("bookmark")).values("name")
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | marko |
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_VXvid1X_VXoutXknowsX_idX_name
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V(vid1).V(__.out("knows").id()).values("name")
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | vadas |
+ | josh |
+
+ @GraphComputerVerificationMidENotSupported
+ Scenario: g_VXvid1X_EXoutE_idX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V(vid1).E(__.outE().id())
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | e[marko-created->lop] |
+ | e[marko-knows->josh] |
+ | e[marko-knows->vadas] |
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_injectX9999X_VXidentityX
+ Given the modern graph
+ And the traversal of
+ """
+ g.inject(9999).V(__.identity())
+ """
+ When iterated to list
+ Then the result should be empty
+
+ @GraphComputerVerificationMidENotSupported
+ Scenario: g_VXvid1X_outEXknowsX_hasXinV_name_vadasX_id_EXidentityX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V(vid1).outE("knows").filter(__.inV().has("name","vadas")).id().E(__.identity())
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | e[marko-knows->vadas] |
+
+ @GraphComputerVerificationMidENotSupported
+ Scenario: g_injectX9999X_EXidentityX
+ Given the modern graph
+ And the traversal of
+ """
+ g.inject(9999).E(__.identity())
+ """
+ When iterated to list
+ Then the result should be empty
+
+ Scenario: g_VXVXvid1X_idX_name
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V(__.V(vid1).id()).values("name")
+ """
+ When iterated to list
+ Then the traversal will raise an error
+
+ Scenario: g_EXVXvid1X_outE_idX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.E(__.V(vid1).outE().id())
+ """
+ When iterated to list
+ Then the traversal will raise an error
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/sideEffect/PropertyTraversal.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/sideEffect/PropertyTraversal.feature
new file mode 100644
index 0000000000..8c420205bf
--- /dev/null
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/sideEffect/PropertyTraversal.feature
@@ -0,0 +1,253 @@
+# 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.
+
+@StepClassSideEffect @StepAddProperty
+Feature: Step - property() with traversal arguments
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_VXvid2X_propertyXalias_VXvid1X_valuesXnameXX
+ Given the empty graph
+ And the graph initializer of
+ """
+ g.addV("person").property("name","marko").property("age",29).
+ addV("person").property("name","vadas").property("age",27).
+ addV("software").property("name","lop").property("lang","java").
+ addV("person").property("name","josh").property("age",32).
+ addV("person").property("name","peter").property("age",35).
+ addV("software").property("name","ripple").property("lang","java")
+ """
+ And using the parameter vid1 defined as "v[marko].id"
+ And using the parameter vid2 defined as "v[josh].id"
+ And the traversal of
+ """
+ g.V(vid2).property("alias", __.V(vid1).values("name"))
+ """
+ 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(\"alias\", \"marko\")"
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_VXvid1X_propertyXcreatorCount_VXvid1X_inXcreatedX_countX
+ 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).
+ addV("software").property("name","lop").property("lang","java").as("lop").
+ addV("person").property("name","josh").property("age",32).as("josh").
+ addV("person").property("name","peter").property("age",35).as("peter").
+ addV("software").property("name","ripple").property("lang","java").as("ripple").
+ addE("knows").from("marko").to(__.V().has("name","vadas")).
+ addE("knows").from("marko").to("josh").
+ addE("created").from("marko").to("lop").
+ addE("created").from("josh").to("lop").
+ addE("created").from("josh").to("ripple").
+ addE("created").from("peter").to("lop")
+ """
+ And using the parameter vid1 defined as "v[lop].id"
+ And the traversal of
+ """
+ g.V(vid1).property("creatorCount", __.V(vid1).in("created").count())
+ """
+ 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(\"creatorCount\", 3L)"
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_VXvid1X_propertyXknownCount_outXknowsX_countX
+ 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").
+ addV("person").property("name","josh").property("age",32).as("josh").
+ addV("person").property("name","peter").property("age",35).
+ addV("software").property("name","ripple").property("lang","java").
+ addE("knows").from("marko").to("vadas").
+ addE("knows").from("marko").to("josh")
+ """
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V(vid1).property("knownCount", __.out("knows").count())
+ """
+ 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(\"knownCount\", 2L)"
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_VXvid1X_propertyXcreator_inXcreatedX_valuesXnameXX
+ 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).
+ addV("software").property("name","lop").property("lang","java").as("lop").
+ addV("person").property("name","josh").property("age",32).as("josh").
+ addV("person").property("name","peter").property("age",35).as("peter").
+ addV("software").property("name","ripple").property("lang","java").as("ripple").
+ addE("knows").from("marko").to(__.V().has("name","vadas")).
+ addE("knows").from("marko").to("josh").
+ addE("created").from("marko").to("lop").
+ addE("created").from("josh").to("lop").
+ addE("created").from("josh").to("ripple").
+ addE("created").from("peter").to("lop")
+ """
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V(vid1).property("creator", __.in("created").values("name"))
+ """
+ When iterated to list
+ Then the result should have a count of 1
+ And the graph should return 0 for count of "g.V().has(\"creator\")"
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_VXvid2X_propertyXVXvid1X_projectXfriendCount_softwareCreatedXX
+ 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("person").property("name","peter").property("age",35).as("peter").
+ addV("software").property("name","ripple").property("lang","java").as("ripple").
+ addE("knows").from("marko").to("vadas").
+ addE("knows").from("marko").to("josh").
+ addE("created").from("marko").to("lop").
+ addE("created").from("josh").to("lop").
+ addE("created").from("josh").to("ripple").
+ addE("created").from("peter").to("lop")
+ """
+ And using the parameter vid1 defined as "v[marko].id"
+ And using the parameter vid2 defined as "v[josh].id"
+ And the traversal of
+ """
+ g.V(vid2).property(__.V(vid1).project("friendCount","softwareCreated").by(__.out("knows").count()).by(__.out("created").values("name")))
+ """
+ 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(\"friendCount\", 2L)"
+ And the graph should return 1 for count of "g.V().has(\"softwareCreated\", \"lop\")"
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_VXvid2X_propertyXVXvid1X_projectXoriginalName_originalLabelX_byXnameX_byXlabelXX
+ 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).
+ addV("software").property("name","lop").property("lang","java").as("lop").
+ addV("person").property("name","josh").property("age",32).
+ addV("person").property("name","peter").property("age",35).
+ addV("software").property("name","ripple").property("lang","java")
+ """
+ And using the parameter vid1 defined as "v[marko].id"
+ And using the parameter vid2 defined as "v[lop].id"
+ And the traversal of
+ """
+ g.V(vid2).property(__.V(vid1).project("originalName","originalLabel").by(__.values("name")).by(__.label()))
+ """
+ When iterated to list
+ Then the result should have a count of 1
+ And the graph should return 1 for count of "g.V(vid2).has(\"originalName\", \"marko\")"
+ And the graph should return 1 for count of "g.V(vid2).has(\"originalLabel\", \"person\")"
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_VXvid1X_propertyXlist_friends_outXknowsX_valuesXnameXX
+ 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").
+ addV("person").property("name","josh").property("age",32).as("josh").
+ addV("person").property("name","peter").property("age",35).
+ addV("software").property("name","ripple").property("lang","java").
+ addE("knows").from("marko").to("vadas").
+ addE("knows").from("marko").to("josh")
+ """
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V(vid1).property(Cardinality.list, "friends", __.out("knows").values("name"))
+ """
+ When iterated to list
+ Then the result should have a count of 1
+ And the graph should return 2 for count of "g.V(vid1).properties(\"friends\")"
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_VXvid1X_propertyXset_langs_outXcreatedX_valuesXlangXX
+ Given the empty graph
+ And the graph initializer of
+ """
+ g.addV("person").property("name","marko").property("age",29).
+ addV("person").property("name","vadas").property("age",27).
+ addV("software").property("name","lop").property("lang","java").as("lop").
+ addV("person").property("name","josh").property("age",32).as("josh").
+ addV("person").property("name","peter").property("age",35).
+ addV("software").property("name","ripple").property("lang","java").as("ripple").
+ addE("created").from("josh").to("lop").
+ addE("created").from("josh").to("ripple")
+ """
+ And using the parameter vid1 defined as "v[josh].id"
+ And the traversal of
+ """
+ g.V(vid1).property(Cardinality.set, "langs", __.out("created").values("lang"))
+ """
+ When iterated to list
+ Then the result should have a count of 1
+ And the graph should return 1 for count of "g.V(vid1).properties(\"langs\")"
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_VXvid1X_propertyXsingle_friend_outXknowsX_valuesXnameXX
+ 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").
+ addV("person").property("name","josh").property("age",32).as("josh").
+ addV("person").property("name","peter").property("age",35).
+ addV("software").property("name","ripple").property("lang","java").
+ addE("knows").from("marko").to("vadas").
+ addE("knows").from("marko").to("josh")
+ """
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V(vid1).property(Cardinality.single, "friend", __.out("knows").values("name"))
+ """
+ When iterated to list
+ Then the traversal will raise an error
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_VXvid1X_propertyXVXvid1X_groupX_byXidX_byXvaluesXnameXXX
+ Given the empty graph
+ And the graph initializer of
+ """
+ g.addV("person").property("name","marko").property("age",29)
+ """
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V(vid1).property(__.V(vid1).group().by(__.id()).by(__.values("name")))
+ """
+ When iterated to list
+ Then the traversal will raise an error
diff --git a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/sideEffect/TinkerGraphStep.java b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/sideEffect/TinkerGraphStep.java
index a950daeefe..fc7c64b060 100644
--- a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/sideEffect/TinkerGraphStep.java
+++ b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/sideEffect/TinkerGraphStep.java
@@ -59,6 +59,14 @@ public final class TinkerGraphStep<S, E extends Element> extends GraphStep<S, E>
super(originalGraphStep.getTraversal(), originalGraphStep.getReturnClass(), originalGraphStep.isStartStep(), originalGraphStep.getIds());
originalGraphStep.getLabels().forEach(this::addLabel);
+ // preserve the idTraversal if the original GraphStep had one
+ if (originalGraphStep instanceof GraphStep) {
+ final GraphStep<S, E> gs = (GraphStep<S, E>) originalGraphStep;
+ if (gs.getIdTraversal() != null) {
+ this.setIdTraversal(gs.getIdTraversal());
+ }
+ }
+
// we used to only setIteratorSupplier() if there were no ids OR the first id was instanceof Element,
// but that allowed the filter in g.V(v).has('k','v') to be ignored. this created problems for
// PartitionStrategy which wants to prevent someone from passing "v" from one TraversalSource to
diff --git a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/optimization/TinkerGraphStepStrategy.java b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/optimization/TinkerGraphStepStrategy.java
index c9e19593a7..8194adc4e0 100644
--- a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/optimization/TinkerGraphStepStrategy.java
+++ b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/optimization/TinkerGraphStepStrategy.java
@@ -54,8 +54,15 @@ public final class TinkerGraphStepStrategy extends AbstractTraversalStrategy<Tra
Step<?, ?> currentStep = tinkerGraphStep.getNextStep();
while (currentStep instanceof HasStep || currentStep instanceof NoOpBarrierStep) {
if (currentStep instanceof HasStep) {
- List<HasContainer> hasContainers = ((HasContainerHolder) currentStep).getHasContainers();
- for (HasContainer hasContainer : hasContainers) {
+ final List<HasContainer> hasContainers = ((HasContainerHolder) currentStep).getHasContainers();
+
+ // skip folding if any HasContainer holds a child traversal — its value
+ // is dynamic (resolved per-traverser) and cannot be pushed into TinkerGraphStep
+ if (hasContainers.stream().anyMatch(HasContainer::hasTraversal)) {
+ break;
+ }
+
+ for (final HasContainer hasContainer : hasContainers) {
if (!GraphStep.processHasContainerIds(tinkerGraphStep, hasContainer))
tinkerGraphStep.addHasContainer(hasContainer);
}
diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/optimization/TinkerGraphStepStrategyTraversalTest.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/optimization/TinkerGraphStepStrategyTraversalTest.java
new file mode 100644
index 0000000000..5fdfa6fdfd
--- /dev/null
+++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/optimization/TinkerGraphStepStrategyTraversalTest.java
@@ -0,0 +1,154 @@
+/*
+ * 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.tinkergraph.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.TraversalStrategies;
+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.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.process.traversal.step.filter.HasStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer;
+import org.apache.tinkerpop.gremlin.process.traversal.util.DefaultTraversalStrategies;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.tinkergraph.process.traversal.step.sideEffect.TinkerGraphStep;
+import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.List;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.greaterThanOrEqualTo;
+import static org.hamcrest.Matchers.hasSize;
+
+/**
+ * Property 9: Traversal-bearing HasContainers are not folded into GraphStep.
+ * <p>
+ * For any traversal of the form {@code g.V().has(key, traversal)} or {@code g.V().has(key, P.eq(traversal))},
+ * after applying {@link TinkerGraphStepStrategy}, the {@link HasStep} SHALL remain as a separate step in the
+ * traversal plan and SHALL NOT be folded into the {@link TinkerGraphStep}.
+ * <p>
+ * <b>Validates: Requirements 8.1, 8.2, 8.3</b>
+ */
+public class TinkerGraphStepStrategyTraversalTest {
+
+ private Graph graph;
+ private GraphTraversalSource g;
+
+ @Before
+ public void setup() {
+ graph = TinkerGraph.open();
+ g = graph.traversal();
+ }
+
+ @After
+ public void teardown() throws Exception {
+ graph.close();
+ }
+
+ /**
+ * Applies TinkerGraphStepStrategy to the given traversal and returns the step list.
+ */
+ private List<Step> applyStrategy(final Traversal.Admin<?, ?> traversal) {
+ final TraversalStrategies strategies = new DefaultTraversalStrategies();
+ strategies.addStrategies(TinkerGraphStepStrategy.instance());
+ traversal.setStrategies(strategies);
+ traversal.applyStrategies();
+ return traversal.getSteps();
+ }
+
+ @Test
+ public void shouldNotFoldTraversalBearingHasContainerIntoGraphStep() {
+ // g.V().has("name", __.constant("marko")) — traversal-bearing HasContainer
+ final GraphTraversal<Vertex, Vertex> traversal = g.V().has("name", __.constant("marko"));
+ final List<Step> steps = applyStrategy(traversal.asAdmin());
+
+ // The traversal plan should contain at least 2 steps:
+ // TinkerGraphStep (replacing GraphStep) and HasStep (not folded)
+ assertThat(steps, hasSize(greaterThanOrEqualTo(2)));
+ assertThat(steps.get(0), instanceOf(TinkerGraphStep.class));
+
+ // The HasStep should remain as a separate step
+ final boolean hasStepPresent = steps.stream().anyMatch(s -> s instanceof HasStep);
+ assertThat("HasStep with traversal-bearing HasContainer should NOT be folded into TinkerGraphStep",
+ hasStepPresent, is(true));
+
+ // The TinkerGraphStep should have no folded HasContainers
+ final TinkerGraphStep<?, ?> tinkerGraphStep = (TinkerGraphStep<?, ?>) steps.get(0);
+ assertThat("TinkerGraphStep should have no folded HasContainers for traversal-bearing has()",
+ tinkerGraphStep.getHasContainers(), hasSize(0));
+ }
+
+ @Test
+ public void shouldStillFoldLiteralHasContainerIntoGraphStep() {
+ // g.V().has("name", "marko") — literal HasContainer should still be folded
+ final GraphTraversal<Vertex, Vertex> traversal = g.V().has("name", "marko");
+ final List<Step> steps = applyStrategy(traversal.asAdmin());
+
+ // After folding, the HasStep should be absorbed into TinkerGraphStep
+ assertThat(steps, hasSize(1));
+ assertThat(steps.get(0), instanceOf(TinkerGraphStep.class));
+
+ // The TinkerGraphStep should have the folded HasContainer
+ final TinkerGraphStep<?, ?> tinkerGraphStep = (TinkerGraphStep<?, ?>) steps.get(0);
+ assertThat(tinkerGraphStep.getHasContainers(), hasSize(1));
+ }
+
+ @Test
+ public void shouldNotFoldPredicateWithTraversalIntoGraphStep() {
+ // g.V().has("name", P.eq(__.constant("marko"))) — predicate with traversal
+ final GraphTraversal<Vertex, Vertex> traversal =
+ g.V().has("name", org.apache.tinkerpop.gremlin.process.traversal.P.eq(__.constant("marko").asAdmin()));
+ final List<Step> steps = applyStrategy(traversal.asAdmin());
+
+ // The HasStep should remain as a separate step
+ assertThat(steps, hasSize(greaterThanOrEqualTo(2)));
+ assertThat(steps.get(0), instanceOf(TinkerGraphStep.class));
+
+ final boolean hasStepPresent = steps.stream().anyMatch(s -> s instanceof HasStep);
+ assertThat("HasStep with P.eq(traversal) should NOT be folded into TinkerGraphStep",
+ hasStepPresent, is(true));
+ }
+
+ @Test
+ public void shouldFoldLiteralHasButNotTraversalHasInMixedTraversal() {
+ // g.V().has("name", "marko").has("age", __.constant(29))
+ // The literal has("name", "marko") should be folded, but has("age", traversal) should not
+ final GraphTraversal<Vertex, Vertex> traversal =
+ g.V().has("name", "marko").has("age", __.constant(29));
+ final List<Step> steps = applyStrategy(traversal.asAdmin());
+
+ // TinkerGraphStep should have the literal "name" HasContainer folded
+ assertThat(steps.get(0), instanceOf(TinkerGraphStep.class));
+ final TinkerGraphStep<?, ?> tinkerGraphStep = (TinkerGraphStep<?, ?>) steps.get(0);
+ assertThat(tinkerGraphStep.getHasContainers(), hasSize(1));
+
+ // The traversal-bearing HasStep for "age" should remain
+ final boolean hasStepPresent = steps.stream().anyMatch(s -> s instanceof HasStep);
+ assertThat("Traversal-bearing HasStep should remain as separate step",
+ hasStepPresent, is(true));
+ }
+
+}
(tinkerpop) 14/14: restrict P(Traversal) in union()
Posted by xi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
xiazcy pushed a commit to branch steps-taking-traversal-poc
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit 4a7f23e52cce919177d548b1876458efd963475e
Author: Yang Xia <xi...@gmail.com>
AuthorDate: Thu Jun 4 22:21:26 2026 -0700
restrict P(Traversal) in union()
---
.../traversal/dsl/graph/GraphTraversal.java | 8 +++
.../Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs | 10 ++--
gremlin-go/driver/cucumber/gremlin.go | 6 +--
.../gremlin-javascript/test/cucumber/gremlin.js | 6 +--
.../src/main/python/tests/feature/gremlin.py | 6 +--
.../gremlin/language/translator/translations.json | 60 +++++++++++-----------
.../test/features/filter/IsTraversal.feature | 6 +--
7 files changed, 55 insertions(+), 47 deletions(-)
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
index e015e708cb..fcf46d23f4 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
@@ -4112,6 +4112,10 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
if (choosePredicate.isParameterized()) {
throw new IllegalArgumentException("Parameterized predicates are not supported by choose()");
}
+ if (choosePredicate.hasTraversal()) {
+ throw new IllegalArgumentException("Traversal-bearing predicates are not supported by choose(). " +
+ "Use choose(__.is(P.op(traversal)), trueChoice, falseChoice) instead.");
+ }
this.asAdmin().getGremlinLang().addStep(Symbols.choose, choosePredicate, trueChoice, falseChoice);
return this.asAdmin().addStep(new ChooseStep<E, E2, Boolean>(this.asAdmin(), (Traversal.Admin<E, ?>) __.is(choosePredicate), (Traversal.Admin<E, E2>) trueChoice, (Traversal.Admin<E, E2>) falseChoice));
}
@@ -4149,6 +4153,10 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
if (choosePredicate.isParameterized()) {
throw new IllegalArgumentException("Parameterized predicates are not supported by choose()");
}
+ if (choosePredicate.hasTraversal()) {
+ throw new IllegalArgumentException("Traversal-bearing predicates are not supported by choose(). " +
+ "Use choose(__.is(P.op(traversal)), trueChoice) instead.");
+ }
this.asAdmin().getGremlinLang().addStep(Symbols.choose, choosePredicate, trueChoice);
return this.asAdmin().addStep(new ChooseStep<E, E2, Boolean>(this.asAdmin(), (Traversal.Admin<E, ?>) __.is(choosePredicate), (Traversal.Admin<E, E2>) trueChoice, (Traversal.Admin<E, E2>) __.identity()));
}
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
index e6040f7ba8..8881b5da07 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
@@ -589,8 +589,8 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
{"g_V_valuesXageX_isXneqXVXvid4X_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Is(P.Neq(__.V(p["vid4"]).Values<object>("age")))}},
{"g_V_valuesXageX_isXwithinXVXvid1X_outXknowsX_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Is(P.Within(__.V(p["vid1"]).Out("knows").Values<object>("age").Fold()))}},
{"g_V_valuesXageX_isXVXvid1X_valuesXnonexistentXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Is(__.V(p["vid1"]).Values<object>("nonexistent"))}},
- {"g_V_hasLabelXpersonX_valuesXageX_chooseXgtXVXvid1X_valuesXageXX_olderX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Values<object>("age").Choose<object>(P.Gt(__.V(p["vid1"]).Values<object>("age")), __.Constant<object>("older than marko"), __.Constant<object>("not older"))}},
- {"g_V_hasLabelXpersonX_valuesXageX_chooseXgteXmeanAgeX_aboveX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Values<object>("age").Choose<object>(P.Gte(__.V().HasLabel("person").Values<object>("age").Mean<object>()), __.Constant<object>("above average"), __.Constant<object>("below average"))}},
+ {"g_V_hasLabelXpersonX_valuesXageX_chooseXgtXVXvid1X_valuesXageXX_olderX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Values<object>("age").Choose<object>(__.Is(P.Gt(__.V(p["vid1"]).Values<object>("age"))), __.Constant<object>("older than marko"), __.Constant<object>("not older"))}},
+ {"g_V_hasLabelXpersonX_valuesXageX_chooseXgteXmeanAgeX_aboveX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Values<object>("age").Choose<object>(__.Is(P.Gte(__.V().HasLabel("person").Values<object>("age").Mean<object>())), __.Constant<object>("above average"), __.Constant<object>("below average"))}},
{"g_VXvid1X_outXknowsX_valuesXageX_fold_allXgteXVXvid2X_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out("knows").Values<object>("age").Fold().All(P.Gte(__.V(p["vid2"]).Values<object>("age")))}},
{"g_VXvid1X_outXknowsX_valuesXageX_fold_allXgtXVXvid2X_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out("knows").Values<object>("age").Fold().All(P.Gt(__.V(p["vid2"]).Values<object>("age")))}},
{"g_VXvid1X_outXknowsX_valuesXageX_fold_anyXeqXVXvid3X_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out("knows").Values<object>("age").Fold().Any(P.Eq(__.V(p["vid3"]).Values<object>("age")))}},
@@ -598,7 +598,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
{"g_VXvid1X_outXknowsX_valuesXageX_fold_noneXeqXVXvid3X_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out("knows").Values<object>("age").Fold().None(P.Eq(__.V(p["vid3"]).Values<object>("age")))}},
{"g_injectXnullX_isXeqXV9999_valuesXnameXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(null).Is(P.Eq(__.V(9999).Values<object>("name")))}},
{"g_injectXmarkoX_isXV9999_valuesXnameXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>("marko").Is(__.V(9999).Values<object>("name"))}},
- {"g_injectXmarkoX_chooseXeqXV9999_valuesXnameXX_matched_unmatchedX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>("marko").Choose<object>(P.Eq(__.V(9999).Values<object>("name")), __.Constant<object>("matched"), __.Constant<object>("unmatched"))}},
+ {"g_injectXmarkoX_chooseXeqXV9999_valuesXnameXX_matched_unmatchedX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>("marko").Choose<object>(__.Is(P.Eq(__.V(9999).Values<object>("name"))), __.Constant<object>("matched"), __.Constant<object>("unmatched"))}},
{"g_injectXlistX_noneXeqXV9999_valuesXnameXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(new List<object> { "marko", "josh" }).None(P.Eq(__.V(9999).Values<object>("name")))}},
{"g_V_hasXname_eqXV9999_valuesXnameXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name", P.Eq(__.V(9999).Values<object>("name")))}},
{"g_V_valuesXageX_isXwithoutXVXvid1X_valuesXageX_VXvid2X_valuesXageXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Is(P.Without(__.V(p["vid1"]).Values<object>("age"), __.V(p["vid2"]).Values<object>("age")))}},
@@ -1012,9 +1012,9 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
{"g_addV_propertyXsingle_mapX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV().Property(Cardinality.Single, new Dictionary<object, object> {{ "name", "foo" }, { "age", 42 }}), (g,p) =>g.V().Has("name", "foo")}},
{"g_V_hasXname_fooX_propertyXname_setXbarX_age_43X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV().Property(Cardinality.Single, "name", "foo").Property("age", 42), (g,p) =>g.V().Has("name", "foo").Property(new Dictionary<object, object> {{ "name", CardinalityValue.Set("bar") }, { "age", 43 }}), (g,p) =>g.V().Has("name", "foo"), (g,p) =>g.V().Has("name", "bar"), (g,p) =>g.V().Has("age", 43), (g,p) =>g.V().Has("age", 42)}},
{"g_V_hasXname_fooX_propertyXset_name_bar_age_singleX43XX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV().Property(Cardinality.Single, "name", "foo").Property("age", 42), (g,p) =>g.V().Has("name", "foo").Property(Cardinality.Set, new Dictionary<object, object> {{ "name", "bar" }, { "age", CardinalityValue.Single(43) }}), (g,p) =>g.V().Has("name", "foo"), (g,p) =>g.V().Has("name", "bar"), (g,p) =>g.V().Has("age", 43), (g,p) [...]
- {"g_addV_propertyXnullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) "person").Property(null), (g,p) =>g.V().HasLabel("person").Values<object>()}},
+ {"g_addV_propertyXnullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) "person").Property((IDictionary<object, object>) null), (g,p) =>g.V().HasLabel("person").Values<object>()}},
{"g_addV_propertyXemptyX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) "person").Property(new Dictionary<object, object> {}), (g,p) =>g.V().HasLabel("person").Values<object>()}},
- {"g_addV_propertyXset_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) "foo").Property(Cardinality.Set, null), (g,p) =>g.V().HasLabel("foo").Values<object>()}},
+ {"g_addV_propertyXset_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) "foo").Property(Cardinality.Set, (IDictionary<object, object>) null), (g,p) =>g.V().HasLabel("foo").Values<object>()}},
{"g_addV_propertyXset_emptyX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) "foo").Property(Cardinality.Set, new Dictionary<object, object> {}), (g,p) =>g.V().HasLabel("person").Values<object>()}},
{"g_addVXpersonX_propertyXname_joshX_propertyXage_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) "person").Property("name", "josh").Property("age", null), (g,p) =>g.V().Has("person", "age", (object) null)}},
{"g_addVXpersonX_propertyXname_markoX_propertyXfriendWeight_null_acl_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) "person").Property("name", "marko").Property("friendWeight", null, "acl", null), (g,p) =>g.V().Has("person", "name", "marko").Has("friendWeight", (object) null), (g,p) =>g.V().Has("person", "name", "marko").Properties<object>("friendWeight").Has("acl", (object) null), (g,p) =>g.V().Has("person", [...]
diff --git a/gremlin-go/driver/cucumber/gremlin.go b/gremlin-go/driver/cucumber/gremlin.go
index 1a7bf90d0c..21fdbd5b0a 100644
--- a/gremlin-go/driver/cucumber/gremlin.go
+++ b/gremlin-go/driver/cucumber/gremlin.go
@@ -559,8 +559,8 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[
"g_V_valuesXageX_isXneqXVXvid4X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Is(gremlingo.P.Neq(gremlingo.T__.V(p["vid4"]).Values("age")))}},
"g_V_valuesXageX_isXwithinXVXvid1X_outXknowsX_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Is(gremlingo.P.Within(gremlingo.T__.V(p["vid1"]).Out("knows").Values("age").Fold()))}},
"g_V_valuesXageX_isXVXvid1X_valuesXnonexistentXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Is(gremlingo.T__.V(p["vid1"]).Values("nonexistent"))}},
- "g_V_hasLabelXpersonX_valuesXageX_chooseXgtXVXvid1X_valuesXageXX_olderX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("person").Values("age").Choose(gremlingo.P.Gt(gremlingo.T__.V(p["vid1"]).Values("age")), gremlingo.T__.Constant("older than marko"), gremlingo.T__.Constant("not older"))}},
- "g_V_hasLabelXpersonX_valuesXageX_chooseXgteXmeanAgeX_aboveX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("person").Values("age").Choose(gremlingo.P.Gte(gremlingo.T__.V().HasLabel("person").Values("age").Mean()), gremlingo.T__.Constant("above average"), gremlingo.T__.Constant("below average"))}},
+ "g_V_hasLabelXpersonX_valuesXageX_chooseXgtXVXvid1X_valuesXageXX_olderX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("person").Values("age").Choose(gremlingo.T__.Is(gremlingo.P.Gt(gremlingo.T__.V(p["vid1"]).Values("age"))), gremlingo.T__.Constant("older than marko"), gremlingo.T__.Constant("not older"))}},
+ "g_V_hasLabelXpersonX_valuesXageX_chooseXgteXmeanAgeX_aboveX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("person").Values("age").Choose(gremlingo.T__.Is(gremlingo.P.Gte(gremlingo.T__.V().HasLabel("person").Values("age").Mean())), gremlingo.T__.Constant("above average"), gremlingo.T__.Constant("below average"))}},
"g_VXvid1X_outXknowsX_valuesXageX_fold_allXgteXVXvid2X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Out("knows").Values("age").Fold().All(gremlingo.P.Gte(gremlingo.T__.V(p["vid2"]).Values("age")))}},
"g_VXvid1X_outXknowsX_valuesXageX_fold_allXgtXVXvid2X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Out("knows").Values("age").Fold().All(gremlingo.P.Gt(gremlingo.T__.V(p["vid2"]).Values("age")))}},
"g_VXvid1X_outXknowsX_valuesXageX_fold_anyXeqXVXvid3X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Out("knows").Values("age").Fold().Any(gremlingo.P.Eq(gremlingo.T__.V(p["vid3"]).Values("age")))}},
@@ -568,7 +568,7 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[
"g_VXvid1X_outXknowsX_valuesXageX_fold_noneXeqXVXvid3X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Out("knows").Values("age").Fold().None(gremlingo.P.Eq(gremlingo.T__.V(p["vid3"]).Values("age")))}},
"g_injectXnullX_isXeqXV9999_valuesXnameXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(nil).Is(gremlingo.P.Eq(gremlingo.T__.V(9999).Values("name")))}},
"g_injectXmarkoX_isXV9999_valuesXnameXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject("marko").Is(gremlingo.T__.V(9999).Values("name"))}},
- "g_injectXmarkoX_chooseXeqXV9999_valuesXnameXX_matched_unmatchedX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject("marko").Choose(gremlingo.P.Eq(gremlingo.T__.V(9999).Values("name")), gremlingo.T__.Constant("matched"), gremlingo.T__.Constant("unmatched"))}},
+ "g_injectXmarkoX_chooseXeqXV9999_valuesXnameXX_matched_unmatchedX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject("marko").Choose(gremlingo.T__.Is(gremlingo.P.Eq(gremlingo.T__.V(9999).Values("name"))), gremlingo.T__.Constant("matched"), gremlingo.T__.Constant("unmatched"))}},
"g_injectXlistX_noneXeqXV9999_valuesXnameXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject([]interface{}{"marko", "josh"}).None(gremlingo.P.Eq(gremlingo.T__.V(9999).Values("name")))}},
"g_V_hasXname_eqXV9999_valuesXnameXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.P.Eq(gremlingo.T__.V(9999).Values("name")))}},
"g_V_valuesXageX_isXwithoutXVXvid1X_valuesXageX_VXvid2X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Is(gremlingo.P.Without(gremlingo.T__.V(p["vid1"]).Values("age"), gremlingo.T__.V(p["vid2"]).Values("age")))}},
diff --git a/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js b/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js
index ea9b014ee2..dbdbb02d55 100644
--- a/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js
+++ b/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js
@@ -590,8 +590,8 @@ const gremlins = {
g_V_valuesXageX_isXneqXVXvid4X_valuesXageXXX: [function({g, vid4}) { return g.V().values("age").is(P.neq(__.V(vid4).values("age"))) }],
g_V_valuesXageX_isXwithinXVXvid1X_outXknowsX_valuesXageXXX: [function({g, vid1}) { return g.V().values("age").is(P.within(__.V(vid1).out("knows").values("age").fold())) }],
g_V_valuesXageX_isXVXvid1X_valuesXnonexistentXX: [function({g, vid1}) { return g.V().values("age").is(__.V(vid1).values("nonexistent")) }],
- g_V_hasLabelXpersonX_valuesXageX_chooseXgtXVXvid1X_valuesXageXX_olderX: [function({g, vid1}) { return g.V().hasLabel("person").values("age").choose(P.gt(__.V(vid1).values("age")), __.constant("older than marko"), __.constant("not older")) }],
- g_V_hasLabelXpersonX_valuesXageX_chooseXgteXmeanAgeX_aboveX: [function({g}) { return g.V().hasLabel("person").values("age").choose(P.gte(__.V().hasLabel("person").values("age").mean()), __.constant("above average"), __.constant("below average")) }],
+ g_V_hasLabelXpersonX_valuesXageX_chooseXgtXVXvid1X_valuesXageXX_olderX: [function({g, vid1}) { return g.V().hasLabel("person").values("age").choose(__.is(P.gt(__.V(vid1).values("age"))), __.constant("older than marko"), __.constant("not older")) }],
+ g_V_hasLabelXpersonX_valuesXageX_chooseXgteXmeanAgeX_aboveX: [function({g}) { return g.V().hasLabel("person").values("age").choose(__.is(P.gte(__.V().hasLabel("person").values("age").mean())), __.constant("above average"), __.constant("below average")) }],
g_VXvid1X_outXknowsX_valuesXageX_fold_allXgteXVXvid2X_valuesXageXXX: [function({g, vid2, vid1}) { return g.V(vid1).out("knows").values("age").fold().all(P.gte(__.V(vid2).values("age"))) }],
g_VXvid1X_outXknowsX_valuesXageX_fold_allXgtXVXvid2X_valuesXageXXX: [function({g, vid2, vid1}) { return g.V(vid1).out("knows").values("age").fold().all(P.gt(__.V(vid2).values("age"))) }],
g_VXvid1X_outXknowsX_valuesXageX_fold_anyXeqXVXvid3X_valuesXageXXX: [function({g, vid3, vid1}) { return g.V(vid1).out("knows").values("age").fold().any(P.eq(__.V(vid3).values("age"))) }],
@@ -599,7 +599,7 @@ const gremlins = {
g_VXvid1X_outXknowsX_valuesXageX_fold_noneXeqXVXvid3X_valuesXageXXX: [function({g, vid3, vid1}) { return g.V(vid1).out("knows").values("age").fold().none(P.eq(__.V(vid3).values("age"))) }],
g_injectXnullX_isXeqXV9999_valuesXnameXXX: [function({g}) { return g.inject(null).is(P.eq(__.V(9999).values("name"))) }],
g_injectXmarkoX_isXV9999_valuesXnameXX: [function({g}) { return g.inject("marko").is(__.V(9999).values("name")) }],
- g_injectXmarkoX_chooseXeqXV9999_valuesXnameXX_matched_unmatchedX: [function({g}) { return g.inject("marko").choose(P.eq(__.V(9999).values("name")), __.constant("matched"), __.constant("unmatched")) }],
+ g_injectXmarkoX_chooseXeqXV9999_valuesXnameXX_matched_unmatchedX: [function({g}) { return g.inject("marko").choose(__.is(P.eq(__.V(9999).values("name"))), __.constant("matched"), __.constant("unmatched")) }],
g_injectXlistX_noneXeqXV9999_valuesXnameXXX: [function({g}) { return g.inject(["marko", "josh"]).none(P.eq(__.V(9999).values("name"))) }],
g_V_hasXname_eqXV9999_valuesXnameXXX: [function({g}) { return g.V().has("name", P.eq(__.V(9999).values("name"))) }],
g_V_valuesXageX_isXwithoutXVXvid1X_valuesXageX_VXvid2X_valuesXageXXX: [function({g, vid2, vid1}) { return g.V().values("age").is(P.without(__.V(vid1).values("age"), __.V(vid2).values("age"))) }],
diff --git a/gremlin-python/src/main/python/tests/feature/gremlin.py b/gremlin-python/src/main/python/tests/feature/gremlin.py
index eb3fcb11df..b7057b9ebc 100644
--- a/gremlin-python/src/main/python/tests/feature/gremlin.py
+++ b/gremlin-python/src/main/python/tests/feature/gremlin.py
@@ -564,8 +564,8 @@ world.gremlins = {
'g_V_valuesXageX_isXneqXVXvid4X_valuesXageXXX': [(lambda g, vid4=None:g.V().values('age').is_(P.neq(__.V(vid4).values('age'))))],
'g_V_valuesXageX_isXwithinXVXvid1X_outXknowsX_valuesXageXXX': [(lambda g, vid1=None:g.V().values('age').is_(P.within(__.V(vid1).out('knows').values('age').fold())))],
'g_V_valuesXageX_isXVXvid1X_valuesXnonexistentXX': [(lambda g, vid1=None:g.V().values('age').is_(__.V(vid1).values('nonexistent')))],
- 'g_V_hasLabelXpersonX_valuesXageX_chooseXgtXVXvid1X_valuesXageXX_olderX': [(lambda g, vid1=None:g.V().has_label('person').values('age').choose(P.gt(__.V(vid1).values('age')), __.constant('older than marko'), __.constant('not older')))],
- 'g_V_hasLabelXpersonX_valuesXageX_chooseXgteXmeanAgeX_aboveX': [(lambda g:g.V().has_label('person').values('age').choose(P.gte(__.V().has_label('person').values('age').mean()), __.constant('above average'), __.constant('below average')))],
+ 'g_V_hasLabelXpersonX_valuesXageX_chooseXgtXVXvid1X_valuesXageXX_olderX': [(lambda g, vid1=None:g.V().has_label('person').values('age').choose(__.is_(P.gt(__.V(vid1).values('age'))), __.constant('older than marko'), __.constant('not older')))],
+ 'g_V_hasLabelXpersonX_valuesXageX_chooseXgteXmeanAgeX_aboveX': [(lambda g:g.V().has_label('person').values('age').choose(__.is_(P.gte(__.V().has_label('person').values('age').mean())), __.constant('above average'), __.constant('below average')))],
'g_VXvid1X_outXknowsX_valuesXageX_fold_allXgteXVXvid2X_valuesXageXXX': [(lambda g, vid2=None,vid1=None:g.V(vid1).out('knows').values('age').fold().all_(P.gte(__.V(vid2).values('age'))))],
'g_VXvid1X_outXknowsX_valuesXageX_fold_allXgtXVXvid2X_valuesXageXXX': [(lambda g, vid2=None,vid1=None:g.V(vid1).out('knows').values('age').fold().all_(P.gt(__.V(vid2).values('age'))))],
'g_VXvid1X_outXknowsX_valuesXageX_fold_anyXeqXVXvid3X_valuesXageXXX': [(lambda g, vid3=None,vid1=None:g.V(vid1).out('knows').values('age').fold().any_(P.eq(__.V(vid3).values('age'))))],
@@ -573,7 +573,7 @@ world.gremlins = {
'g_VXvid1X_outXknowsX_valuesXageX_fold_noneXeqXVXvid3X_valuesXageXXX': [(lambda g, vid3=None,vid1=None:g.V(vid1).out('knows').values('age').fold().none(P.eq(__.V(vid3).values('age'))))],
'g_injectXnullX_isXeqXV9999_valuesXnameXXX': [(lambda g:g.inject(None).is_(P.eq(__.V(9999).values('name'))))],
'g_injectXmarkoX_isXV9999_valuesXnameXX': [(lambda g:g.inject('marko').is_(__.V(9999).values('name')))],
- 'g_injectXmarkoX_chooseXeqXV9999_valuesXnameXX_matched_unmatchedX': [(lambda g:g.inject('marko').choose(P.eq(__.V(9999).values('name')), __.constant('matched'), __.constant('unmatched')))],
+ 'g_injectXmarkoX_chooseXeqXV9999_valuesXnameXX_matched_unmatchedX': [(lambda g:g.inject('marko').choose(__.is_(P.eq(__.V(9999).values('name'))), __.constant('matched'), __.constant('unmatched')))],
'g_injectXlistX_noneXeqXV9999_valuesXnameXXX': [(lambda g:g.inject(['marko', 'josh']).none(P.eq(__.V(9999).values('name'))))],
'g_V_hasXname_eqXV9999_valuesXnameXXX': [(lambda g:g.V().has('name', P.eq(__.V(9999).values('name'))))],
'g_V_valuesXageX_isXwithoutXVXvid1X_valuesXageX_VXvid2X_valuesXageXXX': [(lambda g, vid2=None,vid1=None:g.V().values('age').is_(P.without(__.V(vid1).values('age'), __.V(vid2).values('age'))))],
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json
index f59fb17768..64e585b07c 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json
@@ -10235,16 +10235,16 @@
"scenario": "g_V_hasLabelXpersonX_valuesXageX_chooseXgtXVXvid1X_valuesXageXX_olderX",
"traversals": [
{
- "original": "g.V().hasLabel(\"person\").values(\"age\").choose(P.gt(__.V(vid1).values(\"age\")), __.constant(\"older than marko\"), __.constant(\"not older\"))",
- "language": "g.V().hasLabel(\"person\").values(\"age\").choose(P.gt(__.V(vid1).values(\"age\")), __.constant(\"older than marko\"), __.constant(\"not older\"))",
- "canonical": "g.V().hasLabel(\"person\").values(\"age\").choose(P.gt(__.V(vid1).values(\"age\")), __.constant(\"older than marko\"), __.constant(\"not older\"))",
- "anonymized": "g.V().hasLabel(string0).values(string1).choose(P.gt(__.V(vid1).values(string1)), __.constant(string2), __.constant(string3))",
- "dotnet": "g.V().HasLabel(\"person\").Values<object>(\"age\").Choose<object>(P.Gt(__.V(vid1).Values<object>(\"age\")), __.Constant<object>(\"older than marko\"), __.Constant<object>(\"not older\"))",
- "go": "g.V().HasLabel(\"person\").Values(\"age\").Choose(gremlingo.P.Gt(gremlingo.T__.V(vid1).Values(\"age\")), gremlingo.T__.Constant(\"older than marko\"), gremlingo.T__.Constant(\"not older\"))",
- "groovy": "g.V().hasLabel(\"person\").values(\"age\").choose(P.gt(__.V(vid1).values(\"age\")), __.constant(\"older than marko\"), __.constant(\"not older\"))",
- "java": "g.V().hasLabel(\"person\").values(\"age\").choose(P.gt(__.V(vid1).values(\"age\")), __.constant(\"older than marko\"), __.constant(\"not older\"))",
- "javascript": "g.V().hasLabel(\"person\").values(\"age\").choose(P.gt(__.V(vid1).values(\"age\")), __.constant(\"older than marko\"), __.constant(\"not older\"))",
- "python": "g.V().has_label('person').values('age').choose(P.gt(__.V(vid1).values('age')), __.constant('older than marko'), __.constant('not older'))"
+ "original": "g.V().hasLabel(\"person\").values(\"age\").choose(__.is(P.gt(__.V(vid1).values(\"age\"))), __.constant(\"older than marko\"), __.constant(\"not older\"))",
+ "language": "g.V().hasLabel(\"person\").values(\"age\").choose(__.is(P.gt(__.V(vid1).values(\"age\"))), __.constant(\"older than marko\"), __.constant(\"not older\"))",
+ "canonical": "g.V().hasLabel(\"person\").values(\"age\").choose(__.is(P.gt(__.V(vid1).values(\"age\"))), __.constant(\"older than marko\"), __.constant(\"not older\"))",
+ "anonymized": "g.V().hasLabel(string0).values(string1).choose(__.is(P.gt(__.V(vid1).values(string1))), __.constant(string2), __.constant(string3))",
+ "dotnet": "g.V().HasLabel(\"person\").Values<object>(\"age\").Choose<object>(__.Is(P.Gt(__.V(vid1).Values<object>(\"age\"))), __.Constant<object>(\"older than marko\"), __.Constant<object>(\"not older\"))",
+ "go": "g.V().HasLabel(\"person\").Values(\"age\").Choose(gremlingo.T__.Is(gremlingo.P.Gt(gremlingo.T__.V(vid1).Values(\"age\"))), gremlingo.T__.Constant(\"older than marko\"), gremlingo.T__.Constant(\"not older\"))",
+ "groovy": "g.V().hasLabel(\"person\").values(\"age\").choose(__.is(P.gt(__.V(vid1).values(\"age\"))), __.constant(\"older than marko\"), __.constant(\"not older\"))",
+ "java": "g.V().hasLabel(\"person\").values(\"age\").choose(__.is(P.gt(__.V(vid1).values(\"age\"))), __.constant(\"older than marko\"), __.constant(\"not older\"))",
+ "javascript": "g.V().hasLabel(\"person\").values(\"age\").choose(__.is(P.gt(__.V(vid1).values(\"age\"))), __.constant(\"older than marko\"), __.constant(\"not older\"))",
+ "python": "g.V().has_label('person').values('age').choose(__.is_(P.gt(__.V(vid1).values('age'))), __.constant('older than marko'), __.constant('not older'))"
}
]
},
@@ -10252,16 +10252,16 @@
"scenario": "g_V_hasLabelXpersonX_valuesXageX_chooseXgteXmeanAgeX_aboveX",
"traversals": [
{
- "original": "g.V().hasLabel(\"person\").values(\"age\").choose(P.gte(__.V().hasLabel(\"person\").values(\"age\").mean()), __.constant(\"above average\"), __.constant(\"below average\"))",
- "language": "g.V().hasLabel(\"person\").values(\"age\").choose(P.gte(__.V().hasLabel(\"person\").values(\"age\").mean()), __.constant(\"above average\"), __.constant(\"below average\"))",
- "canonical": "g.V().hasLabel(\"person\").values(\"age\").choose(P.gte(__.V().hasLabel(\"person\").values(\"age\").mean()), __.constant(\"above average\"), __.constant(\"below average\"))",
- "anonymized": "g.V().hasLabel(string0).values(string1).choose(P.gte(__.V().hasLabel(string0).values(string1).mean()), __.constant(string2), __.constant(string3))",
- "dotnet": "g.V().HasLabel(\"person\").Values<object>(\"age\").Choose<object>(P.Gte(__.V().HasLabel(\"person\").Values<object>(\"age\").Mean<object>()), __.Constant<object>(\"above average\"), __.Constant<object>(\"below average\"))",
- "go": "g.V().HasLabel(\"person\").Values(\"age\").Choose(gremlingo.P.Gte(gremlingo.T__.V().HasLabel(\"person\").Values(\"age\").Mean()), gremlingo.T__.Constant(\"above average\"), gremlingo.T__.Constant(\"below average\"))",
- "groovy": "g.V().hasLabel(\"person\").values(\"age\").choose(P.gte(__.V().hasLabel(\"person\").values(\"age\").mean()), __.constant(\"above average\"), __.constant(\"below average\"))",
- "java": "g.V().hasLabel(\"person\").values(\"age\").choose(P.gte(__.V().hasLabel(\"person\").values(\"age\").mean()), __.constant(\"above average\"), __.constant(\"below average\"))",
- "javascript": "g.V().hasLabel(\"person\").values(\"age\").choose(P.gte(__.V().hasLabel(\"person\").values(\"age\").mean()), __.constant(\"above average\"), __.constant(\"below average\"))",
- "python": "g.V().has_label('person').values('age').choose(P.gte(__.V().has_label('person').values('age').mean()), __.constant('above average'), __.constant('below average'))"
+ "original": "g.V().hasLabel(\"person\").values(\"age\").choose(__.is(P.gte(__.V().hasLabel(\"person\").values(\"age\").mean())), __.constant(\"above average\"), __.constant(\"below average\"))",
+ "language": "g.V().hasLabel(\"person\").values(\"age\").choose(__.is(P.gte(__.V().hasLabel(\"person\").values(\"age\").mean())), __.constant(\"above average\"), __.constant(\"below average\"))",
+ "canonical": "g.V().hasLabel(\"person\").values(\"age\").choose(__.is(P.gte(__.V().hasLabel(\"person\").values(\"age\").mean())), __.constant(\"above average\"), __.constant(\"below average\"))",
+ "anonymized": "g.V().hasLabel(string0).values(string1).choose(__.is(P.gte(__.V().hasLabel(string0).values(string1).mean())), __.constant(string2), __.constant(string3))",
+ "dotnet": "g.V().HasLabel(\"person\").Values<object>(\"age\").Choose<object>(__.Is(P.Gte(__.V().HasLabel(\"person\").Values<object>(\"age\").Mean<object>())), __.Constant<object>(\"above average\"), __.Constant<object>(\"below average\"))",
+ "go": "g.V().HasLabel(\"person\").Values(\"age\").Choose(gremlingo.T__.Is(gremlingo.P.Gte(gremlingo.T__.V().HasLabel(\"person\").Values(\"age\").Mean())), gremlingo.T__.Constant(\"above average\"), gremlingo.T__.Constant(\"below average\"))",
+ "groovy": "g.V().hasLabel(\"person\").values(\"age\").choose(__.is(P.gte(__.V().hasLabel(\"person\").values(\"age\").mean())), __.constant(\"above average\"), __.constant(\"below average\"))",
+ "java": "g.V().hasLabel(\"person\").values(\"age\").choose(__.is(P.gte(__.V().hasLabel(\"person\").values(\"age\").mean())), __.constant(\"above average\"), __.constant(\"below average\"))",
+ "javascript": "g.V().hasLabel(\"person\").values(\"age\").choose(__.is(P.gte(__.V().hasLabel(\"person\").values(\"age\").mean())), __.constant(\"above average\"), __.constant(\"below average\"))",
+ "python": "g.V().has_label('person').values('age').choose(__.is_(P.gte(__.V().has_label('person').values('age').mean())), __.constant('above average'), __.constant('below average'))"
}
]
},
@@ -10388,16 +10388,16 @@
"scenario": "g_injectXmarkoX_chooseXeqXV9999_valuesXnameXX_matched_unmatchedX",
"traversals": [
{
- "original": "g.inject(\"marko\").choose(P.eq(__.V(9999).values(\"name\")), __.constant(\"matched\"), __.constant(\"unmatched\"))",
- "language": "g.inject(\"marko\").choose(P.eq(__.V(9999).values(\"name\")), __.constant(\"matched\"), __.constant(\"unmatched\"))",
- "canonical": "g.inject(\"marko\").choose(P.eq(__.V(9999).values(\"name\")), __.constant(\"matched\"), __.constant(\"unmatched\"))",
- "anonymized": "g.inject(string0).choose(P.eq(__.V(number0).values(string1)), __.constant(string2), __.constant(string3))",
- "dotnet": "g.Inject<object>(\"marko\").Choose<object>(P.Eq(__.V(9999).Values<object>(\"name\")), __.Constant<object>(\"matched\"), __.Constant<object>(\"unmatched\"))",
- "go": "g.Inject(\"marko\").Choose(gremlingo.P.Eq(gremlingo.T__.V(9999).Values(\"name\")), gremlingo.T__.Constant(\"matched\"), gremlingo.T__.Constant(\"unmatched\"))",
- "groovy": "g.inject(\"marko\").choose(P.eq(__.V(9999).values(\"name\")), __.constant(\"matched\"), __.constant(\"unmatched\"))",
- "java": "g.inject(\"marko\").choose(P.eq(__.V(9999).values(\"name\")), __.constant(\"matched\"), __.constant(\"unmatched\"))",
- "javascript": "g.inject(\"marko\").choose(P.eq(__.V(9999).values(\"name\")), __.constant(\"matched\"), __.constant(\"unmatched\"))",
- "python": "g.inject('marko').choose(P.eq(__.V(9999).values('name')), __.constant('matched'), __.constant('unmatched'))"
+ "original": "g.inject(\"marko\").choose(__.is(P.eq(__.V(9999).values(\"name\"))), __.constant(\"matched\"), __.constant(\"unmatched\"))",
+ "language": "g.inject(\"marko\").choose(__.is(P.eq(__.V(9999).values(\"name\"))), __.constant(\"matched\"), __.constant(\"unmatched\"))",
+ "canonical": "g.inject(\"marko\").choose(__.is(P.eq(__.V(9999).values(\"name\"))), __.constant(\"matched\"), __.constant(\"unmatched\"))",
+ "anonymized": "g.inject(string0).choose(__.is(P.eq(__.V(number0).values(string1))), __.constant(string2), __.constant(string3))",
+ "dotnet": "g.Inject<object>(\"marko\").Choose<object>(__.Is(P.Eq(__.V(9999).Values<object>(\"name\"))), __.Constant<object>(\"matched\"), __.Constant<object>(\"unmatched\"))",
+ "go": "g.Inject(\"marko\").Choose(gremlingo.T__.Is(gremlingo.P.Eq(gremlingo.T__.V(9999).Values(\"name\"))), gremlingo.T__.Constant(\"matched\"), gremlingo.T__.Constant(\"unmatched\"))",
+ "groovy": "g.inject(\"marko\").choose(__.is(P.eq(__.V(9999).values(\"name\"))), __.constant(\"matched\"), __.constant(\"unmatched\"))",
+ "java": "g.inject(\"marko\").choose(__.is(P.eq(__.V(9999).values(\"name\"))), __.constant(\"matched\"), __.constant(\"unmatched\"))",
+ "javascript": "g.inject(\"marko\").choose(__.is(P.eq(__.V(9999).values(\"name\"))), __.constant(\"matched\"), __.constant(\"unmatched\"))",
+ "python": "g.inject('marko').choose(__.is_(P.eq(__.V(9999).values('name'))), __.constant('matched'), __.constant('unmatched'))"
}
]
},
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/IsTraversal.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/IsTraversal.feature
index 4a70f2ba24..6872769c9b 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/IsTraversal.feature
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/IsTraversal.feature
@@ -118,7 +118,7 @@ Feature: Step - is() with traversal-bearing predicates
And using the parameter vid1 defined as "v[marko].id"
And the traversal of
"""
- g.V().hasLabel("person").values("age").choose(P.gt(__.V(vid1).values("age")), __.constant("older than marko"), __.constant("not older"))
+ g.V().hasLabel("person").values("age").choose(__.is(P.gt(__.V(vid1).values("age"))), __.constant("older than marko"), __.constant("not older"))
"""
When iterated to list
Then the result should be unordered
@@ -133,7 +133,7 @@ Feature: Step - is() with traversal-bearing predicates
Given the modern graph
And the traversal of
"""
- g.V().hasLabel("person").values("age").choose(P.gte(__.V().hasLabel("person").values("age").mean()), __.constant("above average"), __.constant("below average"))
+ g.V().hasLabel("person").values("age").choose(__.is(P.gte(__.V().hasLabel("person").values("age").mean())), __.constant("above average"), __.constant("below average"))
"""
When iterated to list
Then the result should be unordered
@@ -229,7 +229,7 @@ Feature: Step - is() with traversal-bearing predicates
Given the modern graph
And the traversal of
"""
- g.inject("marko").choose(P.eq(__.V(9999).values("name")), __.constant("matched"), __.constant("unmatched"))
+ g.inject("marko").choose(__.is(P.eq(__.V(9999).values("name"))), __.constant("matched"), __.constant("unmatched"))
"""
When iterated to list
Then the result should be unordered
(tinkerpop) 08/14: add compile time check & strategy verification to prevent child traversal mutating steps
Posted by xi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
xiazcy pushed a commit to branch steps-taking-traversal-poc
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit 433c2e4e3ebb9e3370b6eb9f98a22dc3de0b5e62
Author: Yang Xia <xi...@gmail.com>
AuthorDate: Wed May 27 12:10:39 2026 -0700
add compile time check & strategy verification to prevent child traversal mutating steps
---
.../tinkerpop/gremlin/process/traversal/P.java | 15 ++
.../tinkerpop/gremlin/process/traversal/TextP.java | 7 +
.../process/traversal/TraversalStrategies.java | 2 +
.../traversal/dsl/graph/GraphTraversal.java | 7 +
.../traversal/dsl/graph/GraphTraversalSource.java | 3 +
.../traversal/step/sideEffect/AddPropertyStep.java | 9 +
.../ChildTraversalVerificationStrategy.java | 90 +++++++
.../traversal/util/ChildTraversalContext.java | 42 ++++
.../traversal/util/ChildTraversalValidator.java | 111 +++++++++
.../ChildTraversalVerificationStrategyTest.java | 69 ++++++
.../util/ChildTraversalValidatorTest.java | 228 +++++++++++++++++
.../Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs | 16 ++
gremlin-go/driver/cucumber/gremlin.go | 16 ++
.../gremlin-javascript/test/cucumber/gremlin.js | 16 ++
.../src/main/python/tests/feature/gremlin.py | 16 ++
.../gremlin/language/translator/translations.json | 272 +++++++++++++++++++++
.../filter/ChildTraversalVerification.feature | 202 +++++++++++++++
17 files changed, 1121 insertions(+)
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java
index 24b7016ae1..80779cd56a 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java
@@ -26,6 +26,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.util.AndP;
import org.apache.tinkerpop.gremlin.process.traversal.util.ConnectiveP;
import org.apache.tinkerpop.gremlin.structure.util.CloseableIterator;
import org.apache.tinkerpop.gremlin.process.traversal.util.OrP;
+import org.apache.tinkerpop.gremlin.process.traversal.util.ChildTraversalValidator;
import java.io.Serializable;
import java.util.ArrayList;
@@ -725,6 +726,7 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
* @since 4.0.0
*/
public static <V> P<V> eq(final Traversal<?, ?> traversalValue) {
+ ChildTraversalValidator.validateFilterContext(traversalValue.asAdmin());
return new P(Compare.eq, traversalValue.asAdmin());
}
@@ -734,6 +736,7 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
* @since 4.0.0
*/
public static <V> P<V> neq(final Traversal<?, ?> traversalValue) {
+ ChildTraversalValidator.validateFilterContext(traversalValue.asAdmin());
return new P(Compare.neq, traversalValue.asAdmin());
}
@@ -743,6 +746,7 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
* @since 4.0.0
*/
public static <V> P<V> lt(final Traversal<?, ?> traversalValue) {
+ ChildTraversalValidator.validateFilterContext(traversalValue.asAdmin());
return new P(Compare.lt, traversalValue.asAdmin());
}
@@ -752,6 +756,7 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
* @since 4.0.0
*/
public static <V> P<V> lte(final Traversal<?, ?> traversalValue) {
+ ChildTraversalValidator.validateFilterContext(traversalValue.asAdmin());
return new P(Compare.lte, traversalValue.asAdmin());
}
@@ -761,6 +766,7 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
* @since 4.0.0
*/
public static <V> P<V> gt(final Traversal<?, ?> traversalValue) {
+ ChildTraversalValidator.validateFilterContext(traversalValue.asAdmin());
return new P(Compare.gt, traversalValue.asAdmin());
}
@@ -770,6 +776,7 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
* @since 4.0.0
*/
public static <V> P<V> gte(final Traversal<?, ?> traversalValue) {
+ ChildTraversalValidator.validateFilterContext(traversalValue.asAdmin());
return new P(Compare.gte, traversalValue.asAdmin());
}
@@ -779,6 +786,7 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
* @since 4.0.0
*/
public static <V> P<V> within(final Traversal<?, ?> traversalValue) {
+ ChildTraversalValidator.validateFilterContext(traversalValue.asAdmin());
return new P(Contains.within, traversalValue.asAdmin());
}
@@ -797,6 +805,9 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
traversals.add(tv.asAdmin());
}
}
+ for (final Traversal.Admin<?, ?> tv : traversals) {
+ ChildTraversalValidator.validateFilterContext(tv);
+ }
return new P(Contains.within, traversals);
}
@@ -806,6 +817,7 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
* @since 4.0.0
*/
public static <V> P<V> without(final Traversal<?, ?> traversalValue) {
+ ChildTraversalValidator.validateFilterContext(traversalValue.asAdmin());
return new P(Contains.without, traversalValue.asAdmin());
}
@@ -824,6 +836,9 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
traversals.add(tv.asAdmin());
}
}
+ for (final Traversal.Admin<?, ?> tv : traversals) {
+ ChildTraversalValidator.validateFilterContext(tv);
+ }
return new P(Contains.without, traversals);
}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TextP.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TextP.java
index 8ec80a7c62..dcbe70a0cd 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TextP.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TextP.java
@@ -19,6 +19,7 @@
package org.apache.tinkerpop.gremlin.process.traversal;
import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
+import org.apache.tinkerpop.gremlin.process.traversal.util.ChildTraversalValidator;
import java.util.Collection;
import java.util.Map;
@@ -92,6 +93,7 @@ public class TextP extends P<String> {
* @since 4.0.0
*/
public static TextP startingWith(final Traversal<?, ?> traversalValue) {
+ ChildTraversalValidator.validateFilterContext(traversalValue.asAdmin());
return new TextP(Text.startingWith, traversalValue.asAdmin());
}
@@ -119,6 +121,7 @@ public class TextP extends P<String> {
* @since 4.0.0
*/
public static TextP notStartingWith(final Traversal<?, ?> traversalValue) {
+ ChildTraversalValidator.validateFilterContext(traversalValue.asAdmin());
return new TextP(Text.notStartingWith, traversalValue.asAdmin());
}
@@ -146,6 +149,7 @@ public class TextP extends P<String> {
* @since 4.0.0
*/
public static TextP endingWith(final Traversal<?, ?> traversalValue) {
+ ChildTraversalValidator.validateFilterContext(traversalValue.asAdmin());
return new TextP(Text.endingWith, traversalValue.asAdmin());
}
@@ -173,6 +177,7 @@ public class TextP extends P<String> {
* @since 4.0.0
*/
public static TextP notEndingWith(final Traversal<?, ?> traversalValue) {
+ ChildTraversalValidator.validateFilterContext(traversalValue.asAdmin());
return new TextP(Text.notEndingWith, traversalValue.asAdmin());
}
@@ -200,6 +205,7 @@ public class TextP extends P<String> {
* @since 4.0.0
*/
public static TextP containing(final Traversal<?, ?> traversalValue) {
+ ChildTraversalValidator.validateFilterContext(traversalValue.asAdmin());
return new TextP(Text.containing, traversalValue.asAdmin());
}
@@ -227,6 +233,7 @@ public class TextP extends P<String> {
* @since 4.0.0
*/
public static TextP notContaining(final Traversal<?, ?> traversalValue) {
+ ChildTraversalValidator.validateFilterContext(traversalValue.asAdmin());
return new TextP(Text.notContaining, traversalValue.asAdmin());
}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalStrategies.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalStrategies.java
index bccb983665..e3f0d90ff6 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalStrategies.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalStrategies.java
@@ -52,6 +52,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.Path
import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.PathRetractionStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.ProductiveByStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.RepeatUnrollStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ChildTraversalVerificationStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ComputerVerificationStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.EdgeLabelVerificationStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.LambdaRestrictionStrategy;
@@ -287,6 +288,7 @@ public interface TraversalStrategies extends Serializable, Cloneable, Iterable<T
LazyBarrierStrategy.instance(),
ProfileStrategy.instance(),
StandardVerificationStrategy.instance(),
+ ChildTraversalVerificationStrategy.instance(),
GValueReductionStrategy.instance());
registerStrategies(Graph.class, graphStrategies);
registerStrategies(EmptyGraph.class, new DefaultTraversalStrategies());
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
index 97129c4ba0..8364cb8332 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
@@ -209,6 +209,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.util.WithOptions;
import org.apache.tinkerpop.gremlin.process.traversal.traverser.util.TraverserSet;
import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalMetrics;
+import org.apache.tinkerpop.gremlin.process.traversal.util.ChildTraversalValidator;
import org.apache.tinkerpop.gremlin.structure.Column;
import org.apache.tinkerpop.gremlin.structure.Direction;
import org.apache.tinkerpop.gremlin.structure.Edge;
@@ -426,6 +427,7 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
*/
public default GraphTraversal<S, Vertex> V(final Traversal<?, ?> traversal) {
if (null == traversal) return V(new Object[]{ null });
+ ChildTraversalValidator.validateLookupContext(traversal.asAdmin());
this.asAdmin().getGremlinLang().addStep(Symbols.V, traversal);
return this.asAdmin().addStep(new GraphStep<>(this.asAdmin(), Vertex.class, false, traversal.asAdmin()));
}
@@ -465,6 +467,7 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
*/
public default GraphTraversal<S, Edge> E(final Traversal<?, ?> traversal) {
if (null == traversal) return E(new Object[]{ null });
+ ChildTraversalValidator.validateLookupContext(traversal.asAdmin());
this.asAdmin().getGremlinLang().addStep(Symbols.E, traversal);
return this.asAdmin().addStep(new GraphStep<>(this.asAdmin(), Edge.class, false, traversal.asAdmin()));
}
@@ -2715,6 +2718,7 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
*/
public default GraphTraversal<S, E> has(final String propertyKey, final Traversal<?, ?> traversal) {
if (null == traversal) return has(propertyKey, (Object) null);
+ ChildTraversalValidator.validateFilterContext(traversal.asAdmin());
this.asAdmin().getGremlinLang().addStep(Symbols.has, propertyKey, traversal);
final HasContainer hasContainer = new HasContainer(propertyKey, traversal.asAdmin());
return this.asAdmin().addStep(new HasStep(this.asAdmin(), hasContainer));
@@ -2735,6 +2739,7 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
if (null == accessor)
throw new IllegalArgumentException("The T accessor value of has(T,Traversal) cannot be null");
if (null == traversal) return has(accessor, (Object) null);
+ ChildTraversalValidator.validateFilterContext(traversal.asAdmin());
this.asAdmin().getGremlinLang().addStep(Symbols.has, accessor, traversal);
final HasContainer hasContainer = new HasContainer(accessor.getAccessor(), traversal.asAdmin());
@@ -2787,6 +2792,7 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
*/
public default GraphTraversal<S, E> has(final String label, final String propertyKey, final Traversal<?, ?> traversal) {
if (null == traversal) return has(label, propertyKey, (Object) null);
+ ChildTraversalValidator.validateFilterContext(traversal.asAdmin());
this.asAdmin().getGremlinLang().addStep(Symbols.has, label, propertyKey, traversal);
TraversalHelper.addHasContainer(this.asAdmin(), new HasContainer(T.label.getAccessor(), P.eq(label)));
final HasContainer hasContainer = new HasContainer(propertyKey, traversal.asAdmin());
@@ -3936,6 +3942,7 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
*/
public default GraphTraversal<S, E> property(final Traversal<?, ?> mapTraversal) {
if (null == mapTraversal) return this;
+ ChildTraversalValidator.validateMutationContext(mapTraversal.asAdmin());
this.asAdmin().getGremlinLang().addStep(Symbols.property, mapTraversal);
this.asAdmin().addStep(new AddPropertyStepPlaceholder(this.asAdmin(), null, "~traversalMap", mapTraversal.asAdmin()));
return this;
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 b0991a67b9..96a9ae7980 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
@@ -42,6 +42,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.InjectStep
import org.apache.tinkerpop.gremlin.process.traversal.step.map.GraphStepContract;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.RequirementsStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
+import org.apache.tinkerpop.gremlin.process.traversal.util.ChildTraversalValidator;
import org.apache.tinkerpop.gremlin.structure.Direction;
import org.apache.tinkerpop.gremlin.structure.Edge;
import org.apache.tinkerpop.gremlin.structure.Graph;
@@ -548,6 +549,7 @@ public class GraphTraversalSource implements TraversalSource {
*/
public GraphTraversal<Vertex, Vertex> V(final Traversal<?, ?> traversal) {
if (null == traversal) return V(new Object[]{ null });
+ ChildTraversalValidator.validateLookupContext(traversal.asAdmin());
final GraphTraversalSource clone = this.clone();
clone.gremlinLang.addStep(GraphTraversal.Symbols.V, traversal);
final GraphTraversal.Admin<Vertex, Vertex> traversalAdmin = new DefaultGraphTraversal<>(clone);
@@ -586,6 +588,7 @@ public class GraphTraversalSource implements TraversalSource {
*/
public GraphTraversal<Edge, Edge> E(final Traversal<?, ?> traversal) {
if (null == traversal) return E(new Object[]{ null });
+ ChildTraversalValidator.validateLookupContext(traversal.asAdmin());
final GraphTraversalSource clone = this.clone();
clone.gremlinLang.addStep(GraphTraversal.Symbols.E, traversal);
final GraphTraversal.Admin<Edge, Edge> traversalAdmin = new DefaultGraphTraversal<>(clone);
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AddPropertyStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AddPropertyStep.java
index bc83ca4b0c..0c7f30c919 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AddPropertyStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AddPropertyStep.java
@@ -148,6 +148,15 @@ public class AddPropertyStep<S extends Element> extends SideEffectStep<S> implem
return;
}
+ // Runtime validation for property(traversal) — the Map-producing form uses sentinel key "~traversalMap".
+ // If the traversal did NOT produce a Map, reject it to prevent the sentinel key from leaking as a real property.
+ if ("~traversalMap".equals(key)) {
+ final Object result = results.get(0);
+ throw new IllegalArgumentException(
+ "property(traversal) requires the traversal to produce a Map, but got: " +
+ (result == null ? "null" : result.getClass().getSimpleName()));
+ }
+
// Multi-result handling with cardinality awareness
if (results.size() > 1) {
// Determine effective cardinality
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ChildTraversalVerificationStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ChildTraversalVerificationStrategy.java
new file mode 100644
index 0000000000..95ba0cc642
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ChildTraversalVerificationStrategy.java
@@ -0,0 +1,90 @@
+/*
+ * 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.verification;
+
+import org.apache.tinkerpop.gremlin.process.traversal.Step;
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
+import org.apache.tinkerpop.gremlin.process.traversal.step.filter.AllStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.filter.AnyStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.filter.HasStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.filter.IsStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.filter.NoneStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.GraphStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.AddPropertyStepContract;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.util.ChildTraversalContext;
+import org.apache.tinkerpop.gremlin.process.traversal.util.ChildTraversalValidator;
+
+/**
+ * A verification strategy that validates child traversals do not contain disallowed mutating steps
+ * based on the context in which they are used. This serves as a safety net for cases where
+ * construction-time validation is bypassed (e.g., programmatic traversal construction).
+ * <p>
+ * Context classification:
+ * <ul>
+ * <li>{@code HasStep}, {@code IsStep}, {@code AllStep}, {@code AnyStep}, {@code NoneStep} → FILTER</li>
+ * <li>{@code GraphStep} with idTraversal → LOOKUP</li>
+ * <li>{@code AddPropertyStepContract} → MUTATION</li>
+ * </ul>
+ */
+public final class ChildTraversalVerificationStrategy
+ extends AbstractTraversalStrategy<TraversalStrategy.VerificationStrategy>
+ implements TraversalStrategy.VerificationStrategy {
+
+ private static final ChildTraversalVerificationStrategy INSTANCE = new ChildTraversalVerificationStrategy();
+
+ private ChildTraversalVerificationStrategy() {
+ }
+
+ @Override
+ public void apply(final Traversal.Admin<?, ?> traversal) {
+ for (final Step<?, ?> step : traversal.getSteps()) {
+ if (step instanceof TraversalParent) {
+ final ChildTraversalContext context = classifyContext(step);
+ if (context != ChildTraversalContext.NONE) {
+ for (final Traversal.Admin<?, ?> child : ((TraversalParent) step).getLocalChildren()) {
+ try {
+ ChildTraversalValidator.validateRecursive(child, context);
+ } catch (final IllegalArgumentException e) {
+ throw new VerificationException(e.getMessage(), traversal);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private ChildTraversalContext classifyContext(final Step<?, ?> step) {
+ if (step instanceof HasStep || step instanceof IsStep ||
+ step instanceof AllStep || step instanceof AnyStep || step instanceof NoneStep) {
+ return ChildTraversalContext.FILTER;
+ } else if (step instanceof GraphStep && ((GraphStep<?, ?>) step).getIdTraversal() != null) {
+ return ChildTraversalContext.LOOKUP;
+ } else if (step instanceof AddPropertyStepContract) {
+ return ChildTraversalContext.MUTATION;
+ }
+ return ChildTraversalContext.NONE;
+ }
+
+ public static ChildTraversalVerificationStrategy instance() {
+ return INSTANCE;
+ }
+}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ChildTraversalContext.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ChildTraversalContext.java
new file mode 100644
index 0000000000..fbb489813f
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ChildTraversalContext.java
@@ -0,0 +1,42 @@
+/*
+ * 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.util;
+
+/**
+ * Classifies the context in which a child traversal is used, determining what validation rules apply.
+ *
+ * <ul>
+ * <li>{@link #FILTER} — child traversals inside {@code has()}, {@code is()}, {@code all()}, {@code any()},
+ * {@code none()}, or {@code choose()} predicates. No {@link org.apache.tinkerpop.gremlin.process.traversal.step.Mutating}
+ * steps are allowed.</li>
+ * <li>{@link #LOOKUP} — child traversals inside {@code V(traversal)} or {@code E(traversal)}. No
+ * {@link org.apache.tinkerpop.gremlin.process.traversal.step.Mutating} steps are allowed.</li>
+ * <li>{@link #MUTATION} — child traversals inside {@code property(traversal)}. Only
+ * {@link org.apache.tinkerpop.gremlin.process.traversal.step.filter.DropStep} is blocked; other mutating
+ * steps are permitted because the traversal intentionally produces values from graph state.</li>
+ * <li>{@link #NONE} — not a child-traversal-bearing step, or a step whose children are not validated
+ * (e.g., {@code mergeV}, {@code mergeE}).</li>
+ * </ul>
+ */
+public enum ChildTraversalContext {
+ FILTER,
+ LOOKUP,
+ MUTATION,
+ NONE
+}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ChildTraversalValidator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ChildTraversalValidator.java
new file mode 100644
index 0000000000..95c422eabe
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ChildTraversalValidator.java
@@ -0,0 +1,111 @@
+/*
+ * 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.util;
+
+import org.apache.tinkerpop.gremlin.process.traversal.Step;
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.step.Mutating;
+import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
+import org.apache.tinkerpop.gremlin.process.traversal.step.filter.DropStep;
+
+/**
+ * Validates child traversals to ensure they do not contain disallowed steps based on the context
+ * in which they are used. This utility is shared between construction-time validation (in API methods)
+ * and strategy-time validation ({@code ChildTraversalVerificationStrategy}).
+ * <p>
+ * Validation rules:
+ * <ul>
+ * <li><b>FILTER / LOOKUP context:</b> No steps implementing {@link Mutating} are allowed at any nesting depth.</li>
+ * <li><b>MUTATION context:</b> Only {@link DropStep} is blocked; other mutating steps are permitted.</li>
+ * </ul>
+ * <p>
+ * Recursion walks both {@link TraversalParent#getLocalChildren()} and
+ * {@link TraversalParent#getGlobalChildren()} to detect mutations nested inside
+ * {@code map()}, {@code union()}, {@code choose()}, {@code coalesce()}, or any other parent step.
+ */
+public final class ChildTraversalValidator {
+
+ private ChildTraversalValidator() {
+ // static utility
+ }
+
+ /**
+ * Validates a child traversal used in filter context (has, is, all, any, none, choose predicate).
+ * Throws {@link IllegalArgumentException} if any {@link Mutating} step is found.
+ */
+ public static void validateFilterContext(final Traversal.Admin<?, ?> child) {
+ validateRecursive(child, ChildTraversalContext.FILTER);
+ }
+
+ /**
+ * Validates a child traversal used in lookup context (V(traversal), E(traversal)).
+ * Throws {@link IllegalArgumentException} if any {@link Mutating} step is found.
+ */
+ public static void validateLookupContext(final Traversal.Admin<?, ?> child) {
+ validateRecursive(child, ChildTraversalContext.LOOKUP);
+ }
+
+ /**
+ * Validates a child traversal used in mutation context (property(traversal)).
+ * Throws {@link IllegalArgumentException} if a {@link DropStep} is found.
+ */
+ public static void validateMutationContext(final Traversal.Admin<?, ?> child) {
+ validateRecursive(child, ChildTraversalContext.MUTATION);
+ }
+
+ /**
+ * Recursively validates all steps in the child traversal and its nested children.
+ */
+ public static void validateRecursive(final Traversal.Admin<?, ?> child,
+ final ChildTraversalContext context) {
+ for (final Step<?, ?> step : child.getSteps()) {
+ validateStep(step, context);
+ if (step instanceof TraversalParent) {
+ for (final Traversal.Admin<?, ?> nested : ((TraversalParent) step).getLocalChildren()) {
+ validateRecursive(nested, context);
+ }
+ for (final Traversal.Admin<?, ?> nested : ((TraversalParent) step).getGlobalChildren()) {
+ validateRecursive(nested, context);
+ }
+ }
+ }
+ }
+
+ private static void validateStep(final Step<?, ?> step, final ChildTraversalContext context) {
+ switch (context) {
+ case FILTER:
+ case LOOKUP:
+ if (step instanceof Mutating) {
+ throw new IllegalArgumentException(
+ "Child traversal in " + context.name().toLowerCase() + " context contains mutating step " +
+ step.getClass().getSimpleName() + ". Mutating steps are not allowed in this context.");
+ }
+ break;
+ case MUTATION:
+ if (step instanceof DropStep) {
+ throw new IllegalArgumentException(
+ "Child traversal in mutation context contains DropStep. " +
+ "Destructive steps are not allowed inside property(traversal).");
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ChildTraversalVerificationStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ChildTraversalVerificationStrategyTest.java
new file mode 100644
index 0000000000..feb0688283
--- /dev/null
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ChildTraversalVerificationStrategyTest.java
@@ -0,0 +1,69 @@
+/*
+ * 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.verification;
+
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph;
+import org.junit.Test;
+
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+
+/**
+ * Tests for the ChildTraversalVerificationStrategy (strategy-time layer).
+ */
+public class ChildTraversalVerificationStrategyTest {
+
+ private final GraphTraversalSource g = EmptyGraph.instance().traversal();
+
+ @Test
+ public void shouldBeRegisteredByDefault() {
+ // The strategy should be present in the default Graph strategy set (not EmptyGraph which has none)
+ assertTrue(TraversalStrategies.GlobalCache
+ .getStrategies(Graph.class)
+ .getStrategy(ChildTraversalVerificationStrategy.class).isPresent());
+ }
+
+ @Test
+ public void shouldBeRemovableViaWithoutStrategies() {
+ // Users should be able to remove the strategy if needed
+ final GraphTraversalSource gNoVerify = g.withoutStrategies(ChildTraversalVerificationStrategy.class);
+ assertFalse(gNoVerify.getStrategies().getStrategy(ChildTraversalVerificationStrategy.class).isPresent());
+ }
+
+ @Test
+ public void shouldNotRejectValidReadOnlyTraversal() {
+ // Valid traversal should pass strategy application without error
+ final Traversal.Admin<?, ?> traversal = g.V().has("name", __.V().values("name")).asAdmin();
+ traversal.applyStrategies();
+ // If we get here without exception, the test passes
+ }
+
+ @Test
+ public void shouldNotRejectValidLookupTraversal() {
+ // Valid V(traversal) should pass
+ final Traversal.Admin<?, ?> traversal = g.V().V(__.out("knows").id()).asAdmin();
+ traversal.applyStrategies();
+ }
+}
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/ChildTraversalValidatorTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/ChildTraversalValidatorTest.java
new file mode 100644
index 0000000000..e3b385dd48
--- /dev/null
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/ChildTraversalValidatorTest.java
@@ -0,0 +1,228 @@
+/*
+ * 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.util;
+
+import org.apache.tinkerpop.gremlin.process.traversal.P;
+import org.apache.tinkerpop.gremlin.process.traversal.TextP;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph;
+import org.junit.Test;
+
+import static org.junit.Assert.assertThrows;
+
+/**
+ * Tests for construction-time child traversal validation.
+ */
+public class ChildTraversalValidatorTest {
+
+ private final GraphTraversalSource g = EmptyGraph.instance().traversal();
+
+ // ===== FILTER CONTEXT: should reject mutating steps =====
+
+ @Test
+ public void shouldRejectAddVInHasTraversal() {
+ assertThrows(IllegalArgumentException.class, () ->
+ g.V().has("name", __.addV("x").values("name")));
+ }
+
+ @Test
+ public void shouldRejectDropInHasTraversal() {
+ assertThrows(IllegalArgumentException.class, () ->
+ g.V().has("name", __.V().drop().constant("x")));
+ }
+
+ @Test
+ public void shouldRejectNestedMutatingInHasTraversal() {
+ assertThrows(IllegalArgumentException.class, () ->
+ g.V().has("name", __.V().map(__.addV("x")).values("name")));
+ }
+
+ @Test
+ public void shouldRejectMutatingInHasWithTAccessor() {
+ assertThrows(IllegalArgumentException.class, () ->
+ g.V().has(org.apache.tinkerpop.gremlin.structure.T.label, __.addV("x").label()));
+ }
+
+ @Test
+ public void shouldRejectMutatingInHasWithLabel() {
+ assertThrows(IllegalArgumentException.class, () ->
+ g.V().has("person", "name", __.addV("x").values("name")));
+ }
+
+ // ===== LOOKUP CONTEXT: should reject mutating steps =====
+
+ @Test
+ public void shouldRejectAddVInMidTraversalV() {
+ assertThrows(IllegalArgumentException.class, () ->
+ g.V().V(__.addV("x").id()));
+ }
+
+ @Test
+ public void shouldRejectAddVInMidTraversalE() {
+ assertThrows(IllegalArgumentException.class, () ->
+ g.V().E(__.addV("x").id()));
+ }
+
+ @Test
+ public void shouldRejectAddVInStartStepV() {
+ assertThrows(IllegalArgumentException.class, () ->
+ g.V(__.addV("x").id()));
+ }
+
+ @Test
+ public void shouldRejectAddVInStartStepE() {
+ assertThrows(IllegalArgumentException.class, () ->
+ g.E(__.addV("x").id()));
+ }
+
+ // ===== P FACTORY METHODS: should reject mutating steps =====
+
+ @Test
+ public void shouldRejectMutatingInPEq() {
+ assertThrows(IllegalArgumentException.class, () ->
+ P.eq(__.addV("x").values("name")));
+ }
+
+ @Test
+ public void shouldRejectMutatingInPNeq() {
+ assertThrows(IllegalArgumentException.class, () ->
+ P.neq(__.addV("x").values("name")));
+ }
+
+ @Test
+ public void shouldRejectMutatingInPGt() {
+ assertThrows(IllegalArgumentException.class, () ->
+ P.gt(__.addV("x").values("age")));
+ }
+
+ @Test
+ public void shouldRejectMutatingInPLt() {
+ assertThrows(IllegalArgumentException.class, () ->
+ P.lt(__.addV("x").values("age")));
+ }
+
+ @Test
+ public void shouldRejectMutatingInPGte() {
+ assertThrows(IllegalArgumentException.class, () ->
+ P.gte(__.addV("x").values("age")));
+ }
+
+ @Test
+ public void shouldRejectMutatingInPLte() {
+ assertThrows(IllegalArgumentException.class, () ->
+ P.lte(__.addV("x").values("age")));
+ }
+
+ @Test
+ public void shouldRejectMutatingInPWithin() {
+ assertThrows(IllegalArgumentException.class, () ->
+ P.within(__.addV("x").values("name")));
+ }
+
+ @Test
+ public void shouldRejectMutatingInPWithout() {
+ assertThrows(IllegalArgumentException.class, () ->
+ P.without(__.addV("x").values("name")));
+ }
+
+ @Test
+ public void shouldRejectMutatingInMultiTraversalWithin() {
+ assertThrows(IllegalArgumentException.class, () ->
+ P.within(__.V().values("name"), __.addV("x").values("name")));
+ }
+
+ @Test
+ public void shouldRejectMutatingInMultiTraversalWithout() {
+ assertThrows(IllegalArgumentException.class, () ->
+ P.without(__.V().values("name"), __.addV("x").values("name")));
+ }
+
+ // ===== TextP FACTORY METHODS: should reject mutating steps =====
+
+ @Test
+ public void shouldRejectMutatingInTextPStartingWith() {
+ assertThrows(IllegalArgumentException.class, () ->
+ TextP.startingWith(__.addV("x").values("name")));
+ }
+
+ @Test
+ public void shouldRejectMutatingInTextPContaining() {
+ assertThrows(IllegalArgumentException.class, () ->
+ TextP.containing(__.addV("x").values("name")));
+ }
+
+ // ===== MUTATION CONTEXT: should reject DropStep but allow other mutations =====
+
+ @Test
+ public void shouldRejectDropInPropertyTraversal() {
+ assertThrows(IllegalArgumentException.class, () ->
+ g.V().property(__.V().map(__.drop()).project("x").by("name")));
+ }
+
+ @Test
+ public void shouldRejectNestedDropInPropertyTraversal() {
+ assertThrows(IllegalArgumentException.class, () ->
+ g.V().property(__.V().union(__.drop(), __.constant("x")).project("k").by()));
+ }
+
+ // ===== VALID TRAVERSALS: should pass without error =====
+
+ @Test
+ public void shouldAllowReadOnlyHasTraversal() {
+ // Should not throw
+ g.V().has("name", __.V().values("name"));
+ }
+
+ @Test
+ public void shouldAllowNavigationInHasTraversal() {
+ // Should not throw
+ g.V().has("name", __.V().out("knows").values("name"));
+ }
+
+ @Test
+ public void shouldAllowReadOnlyLookupTraversal() {
+ // Should not throw
+ g.V().V(__.out("knows").id());
+ }
+
+ @Test
+ public void shouldAllowReadOnlyStartStepV() {
+ // Should not throw
+ g.V(__.V().id());
+ }
+
+ @Test
+ public void shouldAllowReadOnlyPredicate() {
+ // Should not throw
+ P.eq(__.V().values("age"));
+ }
+
+ @Test
+ public void shouldAllowAddVInMutationContext() {
+ // addV is allowed in property(traversal) — only DropStep is blocked
+ g.V().property(__.V().addV("temp").project("k").by("name"));
+ }
+
+ @Test
+ public void shouldAllowReadOnlyPropertyTraversal() {
+ // Should not throw
+ g.V().property(__.V().project("name").by("name"));
+ }
+}
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
index e349b0f622..d460dcadeb 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
@@ -373,6 +373,22 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
{"g_injectX7X_anyXeqX7XX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(7).Any(P.Eq(7))}},
{"g_injectXnull_nullX_anyXeqXnullXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(new List<object> { null, null }).Any(P.Eq(null))}},
{"g_injectX3_threeX_anyXeqX3XX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(new List<object> { 3, "three" }).Any(P.Eq(3))}},
+ {"g_V_hasXname_addVXxX_valuesXnameXX_rejected", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name", __.AddV((string) "x").Values<object>("name"))}},
+ {"g_V_hasXname_V_drop_constantXxXX_rejected", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name", __.V().Drop().Constant<object>("x"))}},
+ {"g_V_hasXname_V_mapXaddVXxXX_valuesXnameXX_rejected", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name", __.V().Map<object>(__.AddV((string) "x")).Values<object>("name"))}},
+ {"g_V_hasXname_eqXaddVXxX_valuesXnameXXX_rejected", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name", P.Eq(__.AddV((string) "x").Values<object>("name")))}},
+ {"g_V_hasXname_withinXaddVXxX_valuesXnameXXX_rejected", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name", P.Within(__.AddV((string) "x").Values<object>("name")))}},
+ {"g_V_hasXage_gtXaddVXxX_valuesXageXXX_rejected", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("age", P.Gt(__.AddV((string) "x").Values<object>("age")))}},
+ {"g_V_valuesXageX_isXaddVXxX_valuesXageXX_rejected", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Is(__.AddV((string) "x").Values<object>("age"))}},
+ {"g_V_valuesXageX_isXgtXaddVXxX_valuesXageXXX_rejected", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Is(P.Gt(__.AddV((string) "x").Values<object>("age")))}},
+ {"g_V_VXaddVXxX_idX_rejected", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().V(__.AddV((string) "x").Id())}},
+ {"g_V_EXaddVXxX_idX_rejected", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().E(__.AddV((string) "x").Id())}},
+ {"g_VXaddVXxX_idX_rejected", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(__.AddV((string) "x").Id())}},
+ {"g_EXaddVXxX_idX_rejected", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E(__.AddV((string) "x").Id())}},
+ {"g_V_propertyXV_mapXdropX_projectXxX_byXnameXX_rejected", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Property((ITraversal) __.V().Map<object>(__.Drop()).Project<object>("x").By("name"))}},
+ {"g_V_hasXname_VXvid1X_valuesXnameXX_passes_verification", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name", __.V(p["vid1"]).Values<object>("name"))}},
+ {"g_V_hasXage_gtXVXvid1X_valuesXageXXX_passes_verification", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("age", P.Gt(__.V(p["vid1"]).Values<object>("age")))}},
+ {"g_V_VXoutXknowsX_idX_valuesXnameX_passes_verification", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).V(__.Out("knows").Id()).Values<object>("name")}},
{"g_V_coinX1_0X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Coin(1.0)}},
{"g_V_coinX1X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Coin(1)}},
{"g_V_coinX0X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Coin(0.0)}},
diff --git a/gremlin-go/driver/cucumber/gremlin.go b/gremlin-go/driver/cucumber/gremlin.go
index 1ff3d19a48..60808e97d4 100644
--- a/gremlin-go/driver/cucumber/gremlin.go
+++ b/gremlin-go/driver/cucumber/gremlin.go
@@ -343,6 +343,22 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[
"g_injectX7X_anyXeqX7XX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(7).Any(gremlingo.P.Eq(7))}},
"g_injectXnull_nullX_anyXeqXnullXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject([]interface{}{nil, nil}).Any(gremlingo.P.Eq(nil))}},
"g_injectX3_threeX_anyXeqX3XX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject([]interface{}{3, "three"}).Any(gremlingo.P.Eq(3))}},
+ "g_V_hasXname_addVXxX_valuesXnameXX_rejected": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.T__.AddV("x").Values("name"))}},
+ "g_V_hasXname_V_drop_constantXxXX_rejected": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.T__.V().Drop().Constant("x"))}},
+ "g_V_hasXname_V_mapXaddVXxXX_valuesXnameXX_rejected": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.T__.V().Map(gremlingo.T__.AddV("x")).Values("name"))}},
+ "g_V_hasXname_eqXaddVXxX_valuesXnameXXX_rejected": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.P.Eq(gremlingo.T__.AddV("x").Values("name")))}},
+ "g_V_hasXname_withinXaddVXxX_valuesXnameXXX_rejected": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.P.Within(gremlingo.T__.AddV("x").Values("name")))}},
+ "g_V_hasXage_gtXaddVXxX_valuesXageXXX_rejected": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("age", gremlingo.P.Gt(gremlingo.T__.AddV("x").Values("age")))}},
+ "g_V_valuesXageX_isXaddVXxX_valuesXageXX_rejected": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Is(gremlingo.T__.AddV("x").Values("age"))}},
+ "g_V_valuesXageX_isXgtXaddVXxX_valuesXageXXX_rejected": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Is(gremlingo.P.Gt(gremlingo.T__.AddV("x").Values("age")))}},
+ "g_V_VXaddVXxX_idX_rejected": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().V(gremlingo.T__.AddV("x").Id())}},
+ "g_V_EXaddVXxX_idX_rejected": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().E(gremlingo.T__.AddV("x").Id())}},
+ "g_VXaddVXxX_idX_rejected": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(gremlingo.T__.AddV("x").Id())}},
+ "g_EXaddVXxX_idX_rejected": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E(gremlingo.T__.AddV("x").Id())}},
+ "g_V_propertyXV_mapXdropX_projectXxX_byXnameXX_rejected": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Property(gremlingo.T__.V().Map(gremlingo.T__.Drop()).Project("x").By("name"))}},
+ "g_V_hasXname_VXvid1X_valuesXnameXX_passes_verification": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.T__.V(p["vid1"]).Values("name"))}},
+ "g_V_hasXage_gtXVXvid1X_valuesXageXXX_passes_verification": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("age", gremlingo.P.Gt(gremlingo.T__.V(p["vid1"]).Values("age")))}},
+ "g_V_VXoutXknowsX_idX_valuesXnameX_passes_verification": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).V(gremlingo.T__.Out("knows").Id()).Values("name")}},
"g_V_coinX1_0X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Coin(1.0)}},
"g_V_coinX1X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Coin(1)}},
"g_V_coinX0X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Coin(0.0)}},
diff --git a/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js b/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js
index 3dc2da180a..c2a1640ae4 100644
--- a/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js
+++ b/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js
@@ -374,6 +374,22 @@ const gremlins = {
g_injectX7X_anyXeqX7XX: [function({g}) { return g.inject(7).any(P.eq(7)) }],
g_injectXnull_nullX_anyXeqXnullXX: [function({g}) { return g.inject([null, null]).any(P.eq(null)) }],
g_injectX3_threeX_anyXeqX3XX: [function({g}) { return g.inject([3, "three"]).any(P.eq(3)) }],
+ g_V_hasXname_addVXxX_valuesXnameXX_rejected: [function({g}) { return g.V().has("name", __.addV("x").values("name")) }],
+ g_V_hasXname_V_drop_constantXxXX_rejected: [function({g}) { return g.V().has("name", __.V().drop().constant("x")) }],
+ g_V_hasXname_V_mapXaddVXxXX_valuesXnameXX_rejected: [function({g}) { return g.V().has("name", __.V().map(__.addV("x")).values("name")) }],
+ g_V_hasXname_eqXaddVXxX_valuesXnameXXX_rejected: [function({g}) { return g.V().has("name", P.eq(__.addV("x").values("name"))) }],
+ g_V_hasXname_withinXaddVXxX_valuesXnameXXX_rejected: [function({g}) { return g.V().has("name", P.within(__.addV("x").values("name"))) }],
+ g_V_hasXage_gtXaddVXxX_valuesXageXXX_rejected: [function({g}) { return g.V().has("age", P.gt(__.addV("x").values("age"))) }],
+ g_V_valuesXageX_isXaddVXxX_valuesXageXX_rejected: [function({g}) { return g.V().values("age").is(__.addV("x").values("age")) }],
+ g_V_valuesXageX_isXgtXaddVXxX_valuesXageXXX_rejected: [function({g}) { return g.V().values("age").is(P.gt(__.addV("x").values("age"))) }],
+ g_V_VXaddVXxX_idX_rejected: [function({g}) { return g.V().V(__.addV("x").id()) }],
+ g_V_EXaddVXxX_idX_rejected: [function({g}) { return g.V().E(__.addV("x").id()) }],
+ g_VXaddVXxX_idX_rejected: [function({g}) { return g.V(__.addV("x").id()) }],
+ g_EXaddVXxX_idX_rejected: [function({g}) { return g.E(__.addV("x").id()) }],
+ g_V_propertyXV_mapXdropX_projectXxX_byXnameXX_rejected: [function({g}) { return g.V().property(__.V().map(__.drop()).project("x").by("name")) }],
+ g_V_hasXname_VXvid1X_valuesXnameXX_passes_verification: [function({g, vid1}) { return g.V().has("name", __.V(vid1).values("name")) }],
+ g_V_hasXage_gtXVXvid1X_valuesXageXXX_passes_verification: [function({g, vid1}) { return g.V().has("age", P.gt(__.V(vid1).values("age"))) }],
+ g_V_VXoutXknowsX_idX_valuesXnameX_passes_verification: [function({g, vid1}) { return g.V(vid1).V(__.out("knows").id()).values("name") }],
g_V_coinX1_0X: [function({g}) { return g.V().coin(1.0) }],
g_V_coinX1X: [function({g}) { return g.V().coin(1) }],
g_V_coinX0X: [function({g}) { return g.V().coin(0.0) }],
diff --git a/gremlin-python/src/main/python/tests/feature/gremlin.py b/gremlin-python/src/main/python/tests/feature/gremlin.py
index c5b2e09b1e..aa4358cfe7 100644
--- a/gremlin-python/src/main/python/tests/feature/gremlin.py
+++ b/gremlin-python/src/main/python/tests/feature/gremlin.py
@@ -348,6 +348,22 @@ world.gremlins = {
'g_injectX7X_anyXeqX7XX': [(lambda g:g.inject(7).any_(P.eq(7)))],
'g_injectXnull_nullX_anyXeqXnullXX': [(lambda g:g.inject([None, None]).any_(P.eq(None)))],
'g_injectX3_threeX_anyXeqX3XX': [(lambda g:g.inject([3, 'three']).any_(P.eq(3)))],
+ 'g_V_hasXname_addVXxX_valuesXnameXX_rejected': [(lambda g:g.V().has('name', __.add_v('x').values('name')))],
+ 'g_V_hasXname_V_drop_constantXxXX_rejected': [(lambda g:g.V().has('name', __.V().drop().constant('x')))],
+ 'g_V_hasXname_V_mapXaddVXxXX_valuesXnameXX_rejected': [(lambda g:g.V().has('name', __.V().map(__.add_v('x')).values('name')))],
+ 'g_V_hasXname_eqXaddVXxX_valuesXnameXXX_rejected': [(lambda g:g.V().has('name', P.eq(__.add_v('x').values('name'))))],
+ 'g_V_hasXname_withinXaddVXxX_valuesXnameXXX_rejected': [(lambda g:g.V().has('name', P.within(__.add_v('x').values('name'))))],
+ 'g_V_hasXage_gtXaddVXxX_valuesXageXXX_rejected': [(lambda g:g.V().has('age', P.gt(__.add_v('x').values('age'))))],
+ 'g_V_valuesXageX_isXaddVXxX_valuesXageXX_rejected': [(lambda g:g.V().values('age').is_(__.add_v('x').values('age')))],
+ 'g_V_valuesXageX_isXgtXaddVXxX_valuesXageXXX_rejected': [(lambda g:g.V().values('age').is_(P.gt(__.add_v('x').values('age'))))],
+ 'g_V_VXaddVXxX_idX_rejected': [(lambda g:g.V().V(__.add_v('x').id_()))],
+ 'g_V_EXaddVXxX_idX_rejected': [(lambda g:g.V().E(__.add_v('x').id_()))],
+ 'g_VXaddVXxX_idX_rejected': [(lambda g:g.V(__.add_v('x').id_()))],
+ 'g_EXaddVXxX_idX_rejected': [(lambda g:g.E(__.add_v('x').id_()))],
+ 'g_V_propertyXV_mapXdropX_projectXxX_byXnameXX_rejected': [(lambda g:g.V().property(__.V().map(__.drop()).project('x').by('name')))],
+ 'g_V_hasXname_VXvid1X_valuesXnameXX_passes_verification': [(lambda g, vid1=None:g.V().has('name', __.V(vid1).values('name')))],
+ 'g_V_hasXage_gtXVXvid1X_valuesXageXXX_passes_verification': [(lambda g, vid1=None:g.V().has('age', P.gt(__.V(vid1).values('age'))))],
+ 'g_V_VXoutXknowsX_idX_valuesXnameX_passes_verification': [(lambda g, vid1=None:g.V(vid1).V(__.out('knows').id_()).values('name'))],
'g_V_coinX1_0X': [(lambda g:g.V().coin(1.0))],
'g_V_coinX1X': [(lambda g:g.V().coin(1))],
'g_V_coinX0X': [(lambda g:g.V().coin(0.0))],
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json
index b19cdfa20f..99148d3a53 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json
@@ -6295,6 +6295,278 @@
}
]
},
+ {
+ "scenario": "g_V_hasXname_addVXxX_valuesXnameXX_rejected",
+ "traversals": [
+ {
+ "original": "g.V().has(\"name\", __.addV(\"x\").values(\"name\"))",
+ "language": "g.V().has(\"name\", __.addV(\"x\").values(\"name\"))",
+ "canonical": "g.V().has(\"name\", __.addV(\"x\").values(\"name\"))",
+ "anonymized": "g.V().has(string0, __.addV(string1).values(string0))",
+ "dotnet": "g.V().Has(\"name\", __.AddV((string) \"x\").Values<object>(\"name\"))",
+ "go": "g.V().Has(\"name\", gremlingo.T__.AddV(\"x\").Values(\"name\"))",
+ "groovy": "g.V().has(\"name\", __.addV(\"x\").values(\"name\"))",
+ "java": "g.V().has(\"name\", __.addV(\"x\").values(\"name\"))",
+ "javascript": "g.V().has(\"name\", __.addV(\"x\").values(\"name\"))",
+ "python": "g.V().has('name', __.add_v('x').values('name'))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_hasXname_V_drop_constantXxXX_rejected",
+ "traversals": [
+ {
+ "original": "g.V().has(\"name\", __.V().drop().constant(\"x\"))",
+ "language": "g.V().has(\"name\", __.V().drop().constant(\"x\"))",
+ "canonical": "g.V().has(\"name\", __.V().drop().constant(\"x\"))",
+ "anonymized": "g.V().has(string0, __.V().drop().constant(string1))",
+ "dotnet": "g.V().Has(\"name\", __.V().Drop().Constant<object>(\"x\"))",
+ "go": "g.V().Has(\"name\", gremlingo.T__.V().Drop().Constant(\"x\"))",
+ "groovy": "g.V().has(\"name\", __.V().drop().constant(\"x\"))",
+ "java": "g.V().has(\"name\", __.V().drop().constant(\"x\"))",
+ "javascript": "g.V().has(\"name\", __.V().drop().constant(\"x\"))",
+ "python": "g.V().has('name', __.V().drop().constant('x'))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_hasXname_V_mapXaddVXxXX_valuesXnameXX_rejected",
+ "traversals": [
+ {
+ "original": "g.V().has(\"name\", __.V().map(__.addV(\"x\")).values(\"name\"))",
+ "language": "g.V().has(\"name\", __.V().map(__.addV(\"x\")).values(\"name\"))",
+ "canonical": "g.V().has(\"name\", __.V().map(__.addV(\"x\")).values(\"name\"))",
+ "anonymized": "g.V().has(string0, __.V().map(__.addV(string1)).values(string0))",
+ "dotnet": "g.V().Has(\"name\", __.V().Map<object>(__.AddV((string) \"x\")).Values<object>(\"name\"))",
+ "go": "g.V().Has(\"name\", gremlingo.T__.V().Map(gremlingo.T__.AddV(\"x\")).Values(\"name\"))",
+ "groovy": "g.V().has(\"name\", __.V().map(__.addV(\"x\")).values(\"name\"))",
+ "java": "g.V().has(\"name\", __.V().map(__.addV(\"x\")).values(\"name\"))",
+ "javascript": "g.V().has(\"name\", __.V().map(__.addV(\"x\")).values(\"name\"))",
+ "python": "g.V().has('name', __.V().map(__.add_v('x')).values('name'))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_hasXname_eqXaddVXxX_valuesXnameXXX_rejected",
+ "traversals": [
+ {
+ "original": "g.V().has(\"name\", P.eq(__.addV(\"x\").values(\"name\")))",
+ "language": "g.V().has(\"name\", P.eq(__.addV(\"x\").values(\"name\")))",
+ "canonical": "g.V().has(\"name\", P.eq(__.addV(\"x\").values(\"name\")))",
+ "anonymized": "g.V().has(string0, P.eq(__.addV(string1).values(string0)))",
+ "dotnet": "g.V().Has(\"name\", P.Eq(__.AddV((string) \"x\").Values<object>(\"name\")))",
+ "go": "g.V().Has(\"name\", gremlingo.P.Eq(gremlingo.T__.AddV(\"x\").Values(\"name\")))",
+ "groovy": "g.V().has(\"name\", P.eq(__.addV(\"x\").values(\"name\")))",
+ "java": "g.V().has(\"name\", P.eq(__.addV(\"x\").values(\"name\")))",
+ "javascript": "g.V().has(\"name\", P.eq(__.addV(\"x\").values(\"name\")))",
+ "python": "g.V().has('name', P.eq(__.add_v('x').values('name')))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_hasXname_withinXaddVXxX_valuesXnameXXX_rejected",
+ "traversals": [
+ {
+ "original": "g.V().has(\"name\", P.within(__.addV(\"x\").values(\"name\")))",
+ "language": "g.V().has(\"name\", P.within(__.addV(\"x\").values(\"name\")))",
+ "canonical": "g.V().has(\"name\", P.within(__.addV(\"x\").values(\"name\")))",
+ "anonymized": "g.V().has(string0, P.within(__.addV(string1).values(string0)))",
+ "dotnet": "g.V().Has(\"name\", P.Within(__.AddV((string) \"x\").Values<object>(\"name\")))",
+ "go": "g.V().Has(\"name\", gremlingo.P.Within(gremlingo.T__.AddV(\"x\").Values(\"name\")))",
+ "groovy": "g.V().has(\"name\", P.within(__.addV(\"x\").values(\"name\")))",
+ "java": "g.V().has(\"name\", P.within(__.addV(\"x\").values(\"name\")))",
+ "javascript": "g.V().has(\"name\", P.within(__.addV(\"x\").values(\"name\")))",
+ "python": "g.V().has('name', P.within(__.add_v('x').values('name')))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_hasXage_gtXaddVXxX_valuesXageXXX_rejected",
+ "traversals": [
+ {
+ "original": "g.V().has(\"age\", P.gt(__.addV(\"x\").values(\"age\")))",
+ "language": "g.V().has(\"age\", P.gt(__.addV(\"x\").values(\"age\")))",
+ "canonical": "g.V().has(\"age\", P.gt(__.addV(\"x\").values(\"age\")))",
+ "anonymized": "g.V().has(string0, P.gt(__.addV(string1).values(string0)))",
+ "dotnet": "g.V().Has(\"age\", P.Gt(__.AddV((string) \"x\").Values<object>(\"age\")))",
+ "go": "g.V().Has(\"age\", gremlingo.P.Gt(gremlingo.T__.AddV(\"x\").Values(\"age\")))",
+ "groovy": "g.V().has(\"age\", P.gt(__.addV(\"x\").values(\"age\")))",
+ "java": "g.V().has(\"age\", P.gt(__.addV(\"x\").values(\"age\")))",
+ "javascript": "g.V().has(\"age\", P.gt(__.addV(\"x\").values(\"age\")))",
+ "python": "g.V().has('age', P.gt(__.add_v('x').values('age')))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_valuesXageX_isXaddVXxX_valuesXageXX_rejected",
+ "traversals": [
+ {
+ "original": "g.V().values(\"age\").is(__.addV(\"x\").values(\"age\"))",
+ "language": "g.V().values(\"age\").is(__.addV(\"x\").values(\"age\"))",
+ "canonical": "g.V().values(\"age\").is(__.addV(\"x\").values(\"age\"))",
+ "anonymized": "g.V().values(string0).is(__.addV(string1).values(string0))",
+ "dotnet": "g.V().Values<object>(\"age\").Is(__.AddV((string) \"x\").Values<object>(\"age\"))",
+ "go": "g.V().Values(\"age\").Is(gremlingo.T__.AddV(\"x\").Values(\"age\"))",
+ "groovy": "g.V().values(\"age\").is(__.addV(\"x\").values(\"age\"))",
+ "java": "g.V().values(\"age\").is(__.addV(\"x\").values(\"age\"))",
+ "javascript": "g.V().values(\"age\").is(__.addV(\"x\").values(\"age\"))",
+ "python": "g.V().values('age').is_(__.add_v('x').values('age'))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_valuesXageX_isXgtXaddVXxX_valuesXageXXX_rejected",
+ "traversals": [
+ {
+ "original": "g.V().values(\"age\").is(P.gt(__.addV(\"x\").values(\"age\")))",
+ "language": "g.V().values(\"age\").is(P.gt(__.addV(\"x\").values(\"age\")))",
+ "canonical": "g.V().values(\"age\").is(P.gt(__.addV(\"x\").values(\"age\")))",
+ "anonymized": "g.V().values(string0).is(P.gt(__.addV(string1).values(string0)))",
+ "dotnet": "g.V().Values<object>(\"age\").Is(P.Gt(__.AddV((string) \"x\").Values<object>(\"age\")))",
+ "go": "g.V().Values(\"age\").Is(gremlingo.P.Gt(gremlingo.T__.AddV(\"x\").Values(\"age\")))",
+ "groovy": "g.V().values(\"age\").is(P.gt(__.addV(\"x\").values(\"age\")))",
+ "java": "g.V().values(\"age\").is(P.gt(__.addV(\"x\").values(\"age\")))",
+ "javascript": "g.V().values(\"age\").is(P.gt(__.addV(\"x\").values(\"age\")))",
+ "python": "g.V().values('age').is_(P.gt(__.add_v('x').values('age')))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_VXaddVXxX_idX_rejected",
+ "traversals": [
+ {
+ "original": "g.V().V(__.addV(\"x\").id())",
+ "language": "g.V().V(__.addV(\"x\").id())",
+ "canonical": "g.V().V(__.addV(\"x\").id())",
+ "anonymized": "g.V().V(__.addV(string0).id())",
+ "dotnet": "g.V().V(__.AddV((string) \"x\").Id())",
+ "go": "g.V().V(gremlingo.T__.AddV(\"x\").Id())",
+ "groovy": "g.V().V(__.addV(\"x\").id())",
+ "java": "g.V().V(__.addV(\"x\").id())",
+ "javascript": "g.V().V(__.addV(\"x\").id())",
+ "python": "g.V().V(__.add_v('x').id_())"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_EXaddVXxX_idX_rejected",
+ "traversals": [
+ {
+ "original": "g.V().E(__.addV(\"x\").id())",
+ "language": "g.V().E(__.addV(\"x\").id())",
+ "canonical": "g.V().E(__.addV(\"x\").id())",
+ "anonymized": "g.V().E(__.addV(string0).id())",
+ "dotnet": "g.V().E(__.AddV((string) \"x\").Id())",
+ "go": "g.V().E(gremlingo.T__.AddV(\"x\").Id())",
+ "groovy": "g.V().E(__.addV(\"x\").id())",
+ "java": "g.V().E(__.addV(\"x\").id())",
+ "javascript": "g.V().E(__.addV(\"x\").id())",
+ "python": "g.V().E(__.add_v('x').id_())"
+ }
+ ]
+ },
+ {
+ "scenario": "g_VXaddVXxX_idX_rejected",
+ "traversals": [
+ {
+ "original": "g.V(__.addV(\"x\").id())",
+ "language": "g.V(__.addV(\"x\").id())",
+ "canonical": "g.V(__.addV(\"x\").id())",
+ "anonymized": "g.V(__.addV(string0).id())",
+ "dotnet": "g.V(__.AddV((string) \"x\").Id())",
+ "go": "g.V(gremlingo.T__.AddV(\"x\").Id())",
+ "groovy": "g.V(__.addV(\"x\").id())",
+ "java": "g.V(__.addV(\"x\").id())",
+ "javascript": "g.V(__.addV(\"x\").id())",
+ "python": "g.V(__.add_v('x').id_())"
+ }
+ ]
+ },
+ {
+ "scenario": "g_EXaddVXxX_idX_rejected",
+ "traversals": [
+ {
+ "original": "g.E(__.addV(\"x\").id())",
+ "language": "g.E(__.addV(\"x\").id())",
+ "canonical": "g.E(__.addV(\"x\").id())",
+ "anonymized": "g.E(__.addV(string0).id())",
+ "dotnet": "g.E(__.AddV((string) \"x\").Id())",
+ "go": "g.E(gremlingo.T__.AddV(\"x\").Id())",
+ "groovy": "g.E(__.addV(\"x\").id())",
+ "java": "g.E(__.addV(\"x\").id())",
+ "javascript": "g.E(__.addV(\"x\").id())",
+ "python": "g.E(__.add_v('x').id_())"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_propertyXV_mapXdropX_projectXxX_byXnameXX_rejected",
+ "traversals": [
+ {
+ "original": "g.V().property(__.V().map(__.drop()).project(\"x\").by(\"name\"))",
+ "language": "g.V().property(__.V().map(__.drop()).project(\"x\").by(\"name\"))",
+ "canonical": "g.V().property(__.V().map(__.drop()).project(\"x\").by(\"name\"))",
+ "anonymized": "g.V().property(__.V().map(__.drop()).project(string0).by(string1))",
+ "dotnet": "g.V().Property((ITraversal) __.V().Map<object>(__.Drop()).Project<object>(\"x\").By(\"name\"))",
+ "go": "g.V().Property(gremlingo.T__.V().Map(gremlingo.T__.Drop()).Project(\"x\").By(\"name\"))",
+ "groovy": "g.V().property(__.V().map(__.drop()).project(\"x\").by(\"name\"))",
+ "java": "g.V().property(__.V().map(__.drop()).project(\"x\").by(\"name\"))",
+ "javascript": "g.V().property(__.V().map(__.drop()).project(\"x\").by(\"name\"))",
+ "python": "g.V().property(__.V().map(__.drop()).project('x').by('name'))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_hasXname_VXvid1X_valuesXnameXX_passes_verification",
+ "traversals": [
+ {
+ "original": "g.V().has(\"name\", __.V(vid1).values(\"name\"))",
+ "language": "g.V().has(\"name\", __.V(vid1).values(\"name\"))",
+ "canonical": "g.V().has(\"name\", __.V(vid1).values(\"name\"))",
+ "anonymized": "g.V().has(string0, __.V(vid1).values(string0))",
+ "dotnet": "g.V().Has(\"name\", __.V(vid1).Values<object>(\"name\"))",
+ "go": "g.V().Has(\"name\", gremlingo.T__.V(vid1).Values(\"name\"))",
+ "groovy": "g.V().has(\"name\", __.V(vid1).values(\"name\"))",
+ "java": "g.V().has(\"name\", __.V(vid1).values(\"name\"))",
+ "javascript": "g.V().has(\"name\", __.V(vid1).values(\"name\"))",
+ "python": "g.V().has('name', __.V(vid1).values('name'))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_hasXage_gtXVXvid1X_valuesXageXXX_passes_verification",
+ "traversals": [
+ {
+ "original": "g.V().has(\"age\", P.gt(__.V(vid1).values(\"age\")))",
+ "language": "g.V().has(\"age\", P.gt(__.V(vid1).values(\"age\")))",
+ "canonical": "g.V().has(\"age\", P.gt(__.V(vid1).values(\"age\")))",
+ "anonymized": "g.V().has(string0, P.gt(__.V(vid1).values(string0)))",
+ "dotnet": "g.V().Has(\"age\", P.Gt(__.V(vid1).Values<object>(\"age\")))",
+ "go": "g.V().Has(\"age\", gremlingo.P.Gt(gremlingo.T__.V(vid1).Values(\"age\")))",
+ "groovy": "g.V().has(\"age\", P.gt(__.V(vid1).values(\"age\")))",
+ "java": "g.V().has(\"age\", P.gt(__.V(vid1).values(\"age\")))",
+ "javascript": "g.V().has(\"age\", P.gt(__.V(vid1).values(\"age\")))",
+ "python": "g.V().has('age', P.gt(__.V(vid1).values('age')))"
+ }
+ ]
+ },
+ {
+ "scenario": "g_V_VXoutXknowsX_idX_valuesXnameX_passes_verification",
+ "traversals": [
+ {
+ "original": "g.V(vid1).V(__.out(\"knows\").id()).values(\"name\")",
+ "language": "g.V(vid1).V(__.out(\"knows\").id()).values(\"name\")",
+ "canonical": "g.V(vid1).V(__.out(\"knows\").id()).values(\"name\")",
+ "anonymized": "g.V(vid1).V(__.out(string0).id()).values(string1)",
+ "dotnet": "g.V(vid1).V(__.Out(\"knows\").Id()).Values<object>(\"name\")",
+ "go": "g.V(vid1).V(gremlingo.T__.Out(\"knows\").Id()).Values(\"name\")",
+ "groovy": "g.V(vid1).V(__.out(\"knows\").id()).values(\"name\")",
+ "java": "g.V(vid1).V(__.out(\"knows\").id()).values(\"name\")",
+ "javascript": "g.V(vid1).V(__.out(\"knows\").id()).values(\"name\")",
+ "python": "g.V(vid1).V(__.out('knows').id_()).values('name')"
+ }
+ ]
+ },
{
"scenario": "g_V_coinX1_0X",
"traversals": [
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/ChildTraversalVerification.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/ChildTraversalVerification.feature
new file mode 100644
index 0000000000..1bd57ef418
--- /dev/null
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/ChildTraversalVerification.feature
@@ -0,0 +1,202 @@
+# 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.
+
+@StepClassFilter @StepHas
+Feature: Child Traversal Verification - mutating steps blocked in filter/lookup contexts
+
+ # ===== FILTER CONTEXT: has() with mutating child traversals =====
+ # All error scenarios use addV()/drop() which ComputerVerificationStrategy also rejects on OLAP
+ # with a different message, so we exclude them from GraphComputer runs.
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_hasXname_addVXxX_valuesXnameXX_rejected
+ Given the modern graph
+ And the traversal of
+ """
+ g.V().has("name", __.addV("x").values("name"))
+ """
+ When iterated to list
+ Then the traversal will raise an error with message containing text of "mutating step"
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_hasXname_V_drop_constantXxXX_rejected
+ Given the modern graph
+ And the traversal of
+ """
+ g.V().has("name", __.V().drop().constant("x"))
+ """
+ When iterated to list
+ Then the traversal will raise an error with message containing text of "mutating step"
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_hasXname_V_mapXaddVXxXX_valuesXnameXX_rejected
+ Given the modern graph
+ And the traversal of
+ """
+ g.V().has("name", __.V().map(__.addV("x")).values("name"))
+ """
+ When iterated to list
+ Then the traversal will raise an error with message containing text of "mutating step"
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_hasXname_eqXaddVXxX_valuesXnameXXX_rejected
+ Given the modern graph
+ And the traversal of
+ """
+ g.V().has("name", P.eq(__.addV("x").values("name")))
+ """
+ When iterated to list
+ Then the traversal will raise an error with message containing text of "mutating step"
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_hasXname_withinXaddVXxX_valuesXnameXXX_rejected
+ Given the modern graph
+ And the traversal of
+ """
+ g.V().has("name", P.within(__.addV("x").values("name")))
+ """
+ When iterated to list
+ Then the traversal will raise an error with message containing text of "mutating step"
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_hasXage_gtXaddVXxX_valuesXageXXX_rejected
+ Given the modern graph
+ And the traversal of
+ """
+ g.V().has("age", P.gt(__.addV("x").values("age")))
+ """
+ When iterated to list
+ Then the traversal will raise an error with message containing text of "mutating step"
+
+ # ===== FILTER CONTEXT: is() with mutating child traversals =====
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_valuesXageX_isXaddVXxX_valuesXageXX_rejected
+ Given the modern graph
+ And the traversal of
+ """
+ g.V().values("age").is(__.addV("x").values("age"))
+ """
+ When iterated to list
+ Then the traversal will raise an error with message containing text of "mutating step"
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_valuesXageX_isXgtXaddVXxX_valuesXageXXX_rejected
+ Given the modern graph
+ And the traversal of
+ """
+ g.V().values("age").is(P.gt(__.addV("x").values("age")))
+ """
+ When iterated to list
+ Then the traversal will raise an error with message containing text of "mutating step"
+
+ # ===== LOOKUP CONTEXT: V()/E() with mutating child traversals =====
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_VXaddVXxX_idX_rejected
+ Given the modern graph
+ And the traversal of
+ """
+ g.V().V(__.addV("x").id())
+ """
+ When iterated to list
+ Then the traversal will raise an error with message containing text of "mutating step"
+
+ @GraphComputerVerificationMidENotSupported
+ Scenario: g_V_EXaddVXxX_idX_rejected
+ Given the modern graph
+ And the traversal of
+ """
+ g.V().E(__.addV("x").id())
+ """
+ When iterated to list
+ Then the traversal will raise an error with message containing text of "mutating step"
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_VXaddVXxX_idX_rejected
+ Given the modern graph
+ And the traversal of
+ """
+ g.V(__.addV("x").id())
+ """
+ When iterated to list
+ Then the traversal will raise an error with message containing text of "mutating step"
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_EXaddVXxX_idX_rejected
+ Given the modern graph
+ And the traversal of
+ """
+ g.E(__.addV("x").id())
+ """
+ When iterated to list
+ Then the traversal will raise an error with message containing text of "mutating step"
+
+ # ===== MUTATION CONTEXT: property(traversal) blocks DropStep but allows other mutations =====
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_propertyXV_mapXdropX_projectXxX_byXnameXX_rejected
+ Given the modern graph
+ And the traversal of
+ """
+ g.V().property(__.V().map(__.drop()).project("x").by("name"))
+ """
+ When iterated to list
+ Then the traversal will raise an error with message containing text of "DropStep"
+
+ # ===== VALID TRAVERSALS: should NOT be rejected =====
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_hasXname_VXvid1X_valuesXnameXX_passes_verification
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V().has("name", __.V(vid1).values("name"))
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | v[marko] |
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_hasXage_gtXVXvid1X_valuesXageXXX_passes_verification
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V().has("age", P.gt(__.V(vid1).values("age")))
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | v[josh] |
+ | v[peter] |
+
+ @GraphComputerVerificationMidVNotSupported
+ Scenario: g_V_VXoutXknowsX_idX_valuesXnameX_passes_verification
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V(vid1).V(__.out("knows").id()).values("name")
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | vadas |
+ | josh |
(tinkerpop) 06/14: Add optimizations into has and P
Posted by xi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
xiazcy pushed a commit to branch steps-taking-traversal-poc
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit d8dd2ae0de67390624b855176b659fcd7edb885f
Author: Yang Xia <xi...@gmail.com>
AuthorDate: Mon May 25 14:40:30 2026 -0700
Add optimizations into has and P
---
.../tinkerpop/gremlin/process/traversal/P.java | 59 +++++++++++++---------
.../process/traversal/step/filter/HasStep.java | 44 +++++++++++-----
.../gremlin/process/traversal/PTraversalTest.java | 56 +++++++++++++-------
.../test/features/filter/HasTraversal.feature | 4 ++
4 files changed, 108 insertions(+), 55 deletions(-)
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java
index dbaa10f7da..29d882fa9b 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java
@@ -24,6 +24,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.BulkSet;
import org.apache.tinkerpop.gremlin.process.traversal.util.AndP;
import org.apache.tinkerpop.gremlin.process.traversal.util.ConnectiveP;
+import org.apache.tinkerpop.gremlin.structure.util.CloseableIterator;
import org.apache.tinkerpop.gremlin.process.traversal.util.OrP;
import java.io.Serializable;
@@ -336,8 +337,6 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
if (this.traversalValue == null) return;
- // Use prepare + iteration directly to avoid ambiguous overload resolution of applyAll
- // when S=Object (Traverser.Admin<Object> matches both the Traverser.Admin<S> and S overloads).
final Traversal.Admin<Object, Object> trav = (Traversal.Admin<Object, Object>) (Traversal.Admin) this.traversalValue;
final Traverser.Admin<Object> split = (Traverser.Admin<Object>) traverser.split();
split.setSideEffects(trav.getSideEffects());
@@ -345,29 +344,35 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
trav.reset();
trav.addStart(split);
- final List<Object> results = new ArrayList<>();
- while (trav.hasNext()) {
- results.add(trav.next());
- }
-
- this.resolvedEmpty = results.isEmpty();
+ this.isCollection = false;
- if (results.isEmpty()) {
- this.literals = Collections.emptyList();
- this.isCollection = false;
- } else if (this.biPredicate instanceof Contains) {
- // Collection predicates (within, without) accept multiple results
- this.literals = (Collection<V>) (Collection<?>) results;
- this.isCollection = true;
- } else {
- // Single-value predicates (Compare, Text, etc.) require exactly one result
- if (results.size() > 1) {
- throw new IllegalArgumentException(
- "Predicate " + this.biPredicate.getPredicateName() +
- " requires exactly one value but traversal produced " + results.size());
+ try {
+ if (this.biPredicate instanceof Contains) {
+ // Collection predicates (within, without) need all results
+ final List<Object> results = new ArrayList<>();
+ while (trav.hasNext()) {
+ results.add(trav.next());
+ }
+ this.resolvedEmpty = results.isEmpty();
+ if (!results.isEmpty()) {
+ this.literals = (Collection<V>) (Collection<?>) results;
+ this.isCollection = true;
+ } else {
+ this.literals = Collections.emptyList();
+ }
+ } else {
+ // Single-value predicates (Compare, Text, etc.) only need the first result.
+ // Stop immediately — consistent with by(traversal) and has(key, traversal).
+ if (!trav.hasNext()) {
+ this.resolvedEmpty = true;
+ this.literals = Collections.emptyList();
+ } else {
+ this.resolvedEmpty = false;
+ this.literals = Collections.singleton((V) trav.next());
+ }
}
- this.literals = Collections.singleton((V) results.get(0));
- this.isCollection = false;
+ } finally {
+ CloseableIterator.closeIterator(trav);
}
}
@@ -387,8 +392,12 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
trav.reset();
trav.addStart(split);
- while (trav.hasNext()) {
- allResults.add(trav.next());
+ try {
+ while (trav.hasNext()) {
+ allResults.add(trav.next());
+ }
+ } finally {
+ CloseableIterator.closeIterator(trav);
}
}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/HasStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/HasStep.java
index 65b7eebc89..fc39da51f3 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/HasStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/HasStep.java
@@ -103,16 +103,25 @@ public class HasStep<S extends Element> extends FilterStep<S> implements HasCont
* Tests all HasContainers against a Property, handling traversal-bearing containers by evaluating
* child traversals against the current traverser.
*/
+ @SuppressWarnings("unchecked")
private boolean testAllWithTraversals(final Traverser.Admin<S> traverser, final Property property) {
for (final HasContainer hc : this.hasContainers) {
if (hc.hasTraversal()) {
- // For properties with traversals, we need to handle the traversal resolution
if (hc.getTraversalValue() != null) {
- final List<Object> results = collectTraversalResults(traverser, hc.getTraversalValue());
- if (results.isEmpty()) return false;
- // Get the property value to test against — takes first result, ignores extras
- final Object propertyValue = getPropertyValueFromProperty(property, hc.getKey());
- if (!P.eq(results.get(0)).test(propertyValue)) return false;
+ final Traversal.Admin<Object, Object> trav = (Traversal.Admin<Object, Object>) (Traversal.Admin) hc.getTraversalValue();
+ final Traverser.Admin<Object> split = (Traverser.Admin<Object>) (Traverser.Admin) traverser.split();
+ split.setSideEffects(trav.getSideEffects());
+ split.setBulk(1L);
+ trav.reset();
+ trav.addStart(split);
+ try {
+ if (!trav.hasNext()) return false;
+ final Object result = trav.next();
+ final Object propertyValue = getPropertyValueFromProperty(property, hc.getKey());
+ if (!P.eq(result).test(propertyValue)) return false;
+ } finally {
+ CloseableIterator.closeIterator(trav);
+ }
} else if (hc.getPredicate() != null && hc.getPredicate().hasTraversal()) {
hc.getPredicate().resolve(traverser);
if (hc.getPredicate().isResolvedEmpty()) return false;
@@ -130,16 +139,27 @@ public class HasStep<S extends Element> extends FilterStep<S> implements HasCont
/**
* Tests a single HasContainer against an Element, resolving traversals if present.
*/
+ @SuppressWarnings("unchecked")
private boolean testHasContainer(final Traverser.Admin<S> traverser, final HasContainer hc, final Element element) {
if (hc.hasTraversal()) {
if (hc.getTraversalValue() != null) {
- // Direct traversal value: evaluate and use P.eq(first result) — takes first, ignores extras
+ // Direct traversal value: evaluate and use P.eq(first result) — takes first, ignores extras.
// Consistent with by(traversal) which also takes the first result silently.
- final List<Object> results = collectTraversalResults(traverser, hc.getTraversalValue());
- if (results.isEmpty()) return false;
- final Object propertyValue = getPropertyValue(element, hc.getKey());
- if (propertyValue == null) return false;
- return P.eq(results.get(0)).test(propertyValue);
+ final Traversal.Admin<Object, Object> trav = (Traversal.Admin<Object, Object>) (Traversal.Admin) hc.getTraversalValue();
+ final Traverser.Admin<Object> split = (Traverser.Admin<Object>) (Traverser.Admin) traverser.split();
+ split.setSideEffects(trav.getSideEffects());
+ split.setBulk(1L);
+ trav.reset();
+ trav.addStart(split);
+ try {
+ if (!trav.hasNext()) return false;
+ final Object result = trav.next();
+ final Object propertyValue = getPropertyValue(element, hc.getKey());
+ if (propertyValue == null) return false;
+ return P.eq(result).test(propertyValue);
+ } finally {
+ CloseableIterator.closeIterator(trav);
+ }
} else if (hc.getPredicate() != null && hc.getPredicate().hasTraversal()) {
// Predicate with embedded traversal: resolve then test normally
hc.getPredicate().resolve(traverser);
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTraversalTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTraversalTest.java
index 3e7af19d8b..40200c8eaa 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTraversalTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTraversalTest.java
@@ -102,40 +102,60 @@ public class PTraversalTest {
// --- Single-value predicates should throw on multiple results ---
- @Test(expected = IllegalArgumentException.class)
- public void shouldRejectMultipleResultsForEq() {
- final P<Object> p = P.eq(__.inject(1, 2).asAdmin());
+ // --- Single-value predicates take first result, ignore extras (consistent with by()) ---
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void shouldTakeFirstResultForEq() {
+ final P<Object> p = P.eq(__.union(__.constant(1), __.constant(2)).asAdmin());
p.resolve(createTraverser("start"));
+ assertThat(p.test(1), is(true));
+ assertThat(p.test(2), is(false));
}
- @Test(expected = IllegalArgumentException.class)
- public void shouldRejectMultipleResultsForNeq() {
- final P<Object> p = P.neq(__.inject(1, 2).asAdmin());
+ @SuppressWarnings("unchecked")
+ @Test
+ public void shouldTakeFirstResultForNeq() {
+ final P<Object> p = P.neq(__.union(__.constant(1), __.constant(2)).asAdmin());
p.resolve(createTraverser("start"));
+ assertThat(p.test(1), is(false));
+ assertThat(p.test(2), is(true));
}
- @Test(expected = IllegalArgumentException.class)
- public void shouldRejectMultipleResultsForGt() {
- final P<Object> p = P.gt(__.inject(10, 20).asAdmin());
+ @SuppressWarnings("unchecked")
+ @Test
+ public void shouldTakeFirstResultForGt() {
+ final P<Object> p = P.gt(__.union(__.constant(10), __.constant(20)).asAdmin());
p.resolve(createTraverser("start"));
+ assertThat(p.test(11), is(true));
+ assertThat(p.test(10), is(false));
}
- @Test(expected = IllegalArgumentException.class)
- public void shouldRejectMultipleResultsForLt() {
- final P<Object> p = P.lt(__.inject(10, 20).asAdmin());
+ @SuppressWarnings("unchecked")
+ @Test
+ public void shouldTakeFirstResultForLt() {
+ final P<Object> p = P.lt(__.union(__.constant(10), __.constant(20)).asAdmin());
p.resolve(createTraverser("start"));
+ assertThat(p.test(9), is(true));
+ assertThat(p.test(10), is(false));
}
- @Test(expected = IllegalArgumentException.class)
- public void shouldRejectMultipleResultsForGte() {
- final P<Object> p = P.gte(__.inject(10, 20).asAdmin());
+ @SuppressWarnings("unchecked")
+ @Test
+ public void shouldTakeFirstResultForGte() {
+ final P<Object> p = P.gte(__.union(__.constant(10), __.constant(20)).asAdmin());
p.resolve(createTraverser("start"));
+ assertThat(p.test(10), is(true));
+ assertThat(p.test(9), is(false));
}
- @Test(expected = IllegalArgumentException.class)
- public void shouldRejectMultipleResultsForLte() {
- final P<Object> p = P.lte(__.inject(10, 20).asAdmin());
+ @SuppressWarnings("unchecked")
+ @Test
+ public void shouldTakeFirstResultForLte() {
+ final P<Object> p = P.lte(__.union(__.constant(10), __.constant(20)).asAdmin());
p.resolve(createTraverser("start"));
+ assertThat(p.test(10), is(true));
+ assertThat(p.test(11), is(false));
}
// --- Collection predicates should accept multiple results ---
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/HasTraversal.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/HasTraversal.feature
index 3f2f924af2..8479eeac33 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/HasTraversal.feature
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/HasTraversal.feature
@@ -32,6 +32,8 @@ Feature: Step - has() with traversal arguments
| v[marko] |
@GraphComputerVerificationMidVNotSupported
+ # has(key, traversal) with multi-result child traversal — takes first result (order-dependent)
+ @InsertionOrderingRequired
Scenario: g_V_hasXname_VXvid1X_outXknowsX_valuesXnameXX
Given the modern graph
And using the parameter vid1 defined as "v[marko].id"
@@ -44,7 +46,9 @@ Feature: Step - has() with traversal arguments
| result |
| v[vadas] |
+ # has(key, traversal) with multi-result child traversal (age) — takes first result (order-dependent)
@GraphComputerVerificationMidVNotSupported
+ @InsertionOrderingRequired
Scenario: g_V_hasXage_VXvid1X_outXknowsX_valuesXageXX
Given the modern graph
And using the parameter vid1 defined as "v[marko].id"
(tinkerpop) 11/14: add hasLabel(Traversal)
Posted by xi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
xiazcy pushed a commit to branch steps-taking-traversal-poc
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit 5c53f98e67b9073a0d2580117e4da853d8262884
Author: Yang Xia <xi...@gmail.com>
AuthorDate: Tue Jun 2 09:21:58 2026 -0700
add hasLabel(Traversal)
---
.../language/grammar/DefaultGremlinBaseVisitor.java | 4 ++++
.../language/grammar/TraversalMethodVisitor.java | 9 +++++++++
.../language/translator/DotNetTranslateVisitor.java | 10 ++++++++++
.../process/traversal/dsl/graph/GraphTraversal.java | 17 +++++++++++++++++
.../gremlin/process/traversal/dsl/graph/__.java | 7 +++++++
.../test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs | 1 +
gremlin-go/driver/cucumber/gremlin.go | 1 +
gremlin-js/gremlin-javascript/test/cucumber/gremlin.js | 1 +
gremlin-language/src/main/antlr4/Gremlin.g4 | 1 +
gremlin-python/src/main/python/tests/feature/gremlin.py | 1 +
10 files changed, 52 insertions(+)
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/DefaultGremlinBaseVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/DefaultGremlinBaseVisitor.java
index 96cd5ef97a..4fdf7c0866 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/DefaultGremlinBaseVisitor.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/DefaultGremlinBaseVisitor.java
@@ -487,6 +487,10 @@ public class DefaultGremlinBaseVisitor<T> extends AbstractParseTreeVisitor<T> im
* {@inheritDoc}
*/
@Override public T visitTraversalMethod_hasLabel_P(final GremlinParser.TraversalMethod_hasLabel_PContext ctx) { notImplemented(ctx); return null; }
+ /**
+ * {@inheritDoc}
+ */
+ @Override public T visitTraversalMethod_hasLabel_Traversal(final GremlinParser.TraversalMethod_hasLabel_TraversalContext ctx) { notImplemented(ctx); return null; }
/**
* {@inheritDoc}
*/
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitor.java
index 1c99745f60..518196daef 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitor.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitor.java
@@ -771,6 +771,15 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal>
return graphTraversal.hasLabel(antlr.traversalPredicateVisitor.visitTraversalPredicate(ctx.traversalPredicate()));
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public GraphTraversal visitTraversalMethod_hasLabel_Traversal(final GremlinParser.TraversalMethod_hasLabel_TraversalContext ctx) {
+ final Traversal.Admin<?, ?> traversal = (Traversal.Admin<?, ?>) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal());
+ return graphTraversal.hasLabel((Traversal<?, ?>) traversal);
+ }
+
/**
* {@inheritDoc}
*/
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/DotNetTranslateVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/DotNetTranslateVisitor.java
index 7ce385c925..540f650039 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/DotNetTranslateVisitor.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/DotNetTranslateVisitor.java
@@ -745,6 +745,16 @@ public class DotNetTranslateVisitor extends AbstractTranslateVisitor {
return null;
}
+ @Override
+ public Void visitTraversalMethod_hasLabel_Traversal(final GremlinParser.TraversalMethod_hasLabel_TraversalContext ctx) {
+ final String step = ctx.getChild(0).getText();
+ sb.append(convertToPascalCase(step));
+ sb.append("(");
+ visit(ctx.nestedTraversal());
+ sb.append(")");
+ return null;
+ }
+
@Override
public Void visitTraversalMethod_hasLabel_String_String(final GremlinParser.TraversalMethod_hasLabel_String_StringContext ctx) {
// if there is only one argument then cast to string otherwise it's ambiguous with hasLabel(P)
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
index 8364cb8332..552dec3be8 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
@@ -2894,6 +2894,23 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
}
}
+ /**
+ * Filters vertices, edges and vertex properties based on their label using a child traversal
+ * whose results are resolved at runtime against the current traverser.
+ *
+ * @param traversal the child traversal whose results are used as the label filter value
+ * @return the traversal with an appended {@link HasStep}
+ * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#has-step" target="_blank">Reference Documentation - Has Step</a>
+ * @since 4.0.0
+ */
+ public default GraphTraversal<S, E> hasLabel(final Traversal<?, ?> traversal) {
+ if (null == traversal) return hasLabel((String) null);
+ ChildTraversalValidator.validateFilterContext(traversal.asAdmin());
+ this.asAdmin().getGremlinLang().addStep(Symbols.hasLabel, traversal);
+ final HasContainer hasContainer = new HasContainer(T.label.getAccessor(), traversal.asAdmin());
+ return this.asAdmin().addStep(new HasStep(this.asAdmin(), hasContainer));
+ }
+
/**
* Filters vertices, edges and vertex properties based on their label.
*
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java
index 3dc2ed0651..46eddc4e2f 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java
@@ -1212,6 +1212,13 @@ public class __ {
return __.<A>start().hasLabel(predicate);
}
+ /**
+ * @see GraphTraversal#hasLabel(Traversal)
+ */
+ public static <A> GraphTraversal<A, A> hasLabel(final Traversal<?, ?> traversal) {
+ return __.<A>start().hasLabel(traversal);
+ }
+
/**
* @see GraphTraversal#hasId(Object, Object...)
*/
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
index e54133e1f0..c99098cfce 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
@@ -386,6 +386,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
{"g_VXaddVXxX_idX_rejected", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(__.AddV((string) "x").Id())}},
{"g_EXaddVXxX_idX_rejected", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E(__.AddV((string) "x").Id())}},
{"g_V_propertyXV_mapXdropX_projectXxX_byXnameXX_rejected", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Property((ITraversal) __.V().Map<object>(__.Drop()).Project<object>("x").By("name"))}},
+ {"g_V_propertyXaddVXtempX_projectXkX_byXnameXX_rejected", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Property((ITraversal) __.AddV((string) "temp").Project<object>("k").By("name"))}},
{"g_V_hasXname_VXvid1X_valuesXnameXX_passes_verification", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name", __.V(p["vid1"]).Values<object>("name"))}},
{"g_V_hasXage_gtXVXvid1X_valuesXageXXX_passes_verification", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("age", P.Gt(__.V(p["vid1"]).Values<object>("age")))}},
{"g_V_VXoutXknowsX_idX_valuesXnameX_passes_verification", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).V(__.Out("knows").Id()).Values<object>("name")}},
diff --git a/gremlin-go/driver/cucumber/gremlin.go b/gremlin-go/driver/cucumber/gremlin.go
index 9003f7b3f8..93905479c5 100644
--- a/gremlin-go/driver/cucumber/gremlin.go
+++ b/gremlin-go/driver/cucumber/gremlin.go
@@ -356,6 +356,7 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[
"g_VXaddVXxX_idX_rejected": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(gremlingo.T__.AddV("x").Id())}},
"g_EXaddVXxX_idX_rejected": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E(gremlingo.T__.AddV("x").Id())}},
"g_V_propertyXV_mapXdropX_projectXxX_byXnameXX_rejected": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Property(gremlingo.T__.V().Map(gremlingo.T__.Drop()).Project("x").By("name"))}},
+ "g_V_propertyXaddVXtempX_projectXkX_byXnameXX_rejected": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Property(gremlingo.T__.AddV("temp").Project("k").By("name"))}},
"g_V_hasXname_VXvid1X_valuesXnameXX_passes_verification": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.T__.V(p["vid1"]).Values("name"))}},
"g_V_hasXage_gtXVXvid1X_valuesXageXXX_passes_verification": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("age", gremlingo.P.Gt(gremlingo.T__.V(p["vid1"]).Values("age")))}},
"g_V_VXoutXknowsX_idX_valuesXnameX_passes_verification": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).V(gremlingo.T__.Out("knows").Id()).Values("name")}},
diff --git a/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js b/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js
index 1d705754b8..cec6e2d7fc 100644
--- a/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js
+++ b/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js
@@ -387,6 +387,7 @@ const gremlins = {
g_VXaddVXxX_idX_rejected: [function({g}) { return g.V(__.addV("x").id()) }],
g_EXaddVXxX_idX_rejected: [function({g}) { return g.E(__.addV("x").id()) }],
g_V_propertyXV_mapXdropX_projectXxX_byXnameXX_rejected: [function({g}) { return g.V().property(__.V().map(__.drop()).project("x").by("name")) }],
+ g_V_propertyXaddVXtempX_projectXkX_byXnameXX_rejected: [function({g}) { return g.V().property(__.addV("temp").project("k").by("name")) }],
g_V_hasXname_VXvid1X_valuesXnameXX_passes_verification: [function({g, vid1}) { return g.V().has("name", __.V(vid1).values("name")) }],
g_V_hasXage_gtXVXvid1X_valuesXageXXX_passes_verification: [function({g, vid1}) { return g.V().has("age", P.gt(__.V(vid1).values("age"))) }],
g_V_VXoutXknowsX_idX_valuesXnameX_passes_verification: [function({g, vid1}) { return g.V(vid1).V(__.out("knows").id()).values("name") }],
diff --git a/gremlin-language/src/main/antlr4/Gremlin.g4 b/gremlin-language/src/main/antlr4/Gremlin.g4
index 822cb59481..17dfbaec11 100644
--- a/gremlin-language/src/main/antlr4/Gremlin.g4
+++ b/gremlin-language/src/main/antlr4/Gremlin.g4
@@ -573,6 +573,7 @@ traversalMethod_hasKey
traversalMethod_hasLabel
: K_HASLABEL LPAREN traversalPredicate RPAREN #traversalMethod_hasLabel_P
| K_HASLABEL LPAREN stringNullableArgument (COMMA stringNullableArgumentVarargs)? RPAREN #traversalMethod_hasLabel_String_String
+ | K_HASLABEL LPAREN nestedTraversal RPAREN #traversalMethod_hasLabel_Traversal
;
traversalMethod_hasNot
diff --git a/gremlin-python/src/main/python/tests/feature/gremlin.py b/gremlin-python/src/main/python/tests/feature/gremlin.py
index 5928aaedc4..a3262c119c 100644
--- a/gremlin-python/src/main/python/tests/feature/gremlin.py
+++ b/gremlin-python/src/main/python/tests/feature/gremlin.py
@@ -361,6 +361,7 @@ world.gremlins = {
'g_VXaddVXxX_idX_rejected': [(lambda g:g.V(__.add_v('x').id_()))],
'g_EXaddVXxX_idX_rejected': [(lambda g:g.E(__.add_v('x').id_()))],
'g_V_propertyXV_mapXdropX_projectXxX_byXnameXX_rejected': [(lambda g:g.V().property(__.V().map(__.drop()).project('x').by('name')))],
+ 'g_V_propertyXaddVXtempX_projectXkX_byXnameXX_rejected': [(lambda g:g.V().property(__.add_v('temp').project('k').by('name')))],
'g_V_hasXname_VXvid1X_valuesXnameXX_passes_verification': [(lambda g, vid1=None:g.V().has('name', __.V(vid1).values('name')))],
'g_V_hasXage_gtXVXvid1X_valuesXageXXX_passes_verification': [(lambda g, vid1=None:g.V().has('age', P.gt(__.V(vid1).values('age'))))],
'g_V_VXoutXknowsX_idX_valuesXnameX_passes_verification': [(lambda g, vid1=None:g.V(vid1).V(__.out('knows').id_()).values('name'))],