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:45 UTC
(tinkerpop) 01/14: Add traversal-accepting arguments to has(), V(), E(), property(), is(), and predicates.
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));
+ }
+
+}