This is an automated email from the ASF dual-hosted git repository. spmallette pushed a commit to branch gvalue in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit 1eec10961d99e68f49c2393ac36e6a15507008d2 Author: Stephen Mallette <[email protected]> AuthorDate: Wed Aug 7 15:06:28 2024 -0400 wip --- .../grammar/DefaultGremlinBaseVisitor.java | 12 +-- .../language/grammar/TraversalMethodVisitor.java | 100 ++++++++++-------- .../grammar/TraversalSourceSpawnMethodVisitor.java | 15 ++- .../translator/DotNetTranslateVisitor.java | 23 ++-- .../language/translator/TranslateVisitor.java | 5 - .../gremlin/process/traversal/Operator.java | 10 +- .../traversal/dsl/graph/GraphTraversal.java | 117 ++++++++++++++++++++- .../traversal/dsl/graph/GraphTraversalSource.java | 32 +++++- .../gremlin/process/traversal/step/GValue.java | 9 +- .../process/traversal/step/map/AddEdgeStep.java | 9 +- .../process/traversal/step/map/CallStep.java | 36 +++++-- .../process/traversal/step/map/ConstantStep.java | 2 +- .../process/traversal/step/map/DifferenceStep.java | 16 ++- .../process/traversal/step/map/DisjunctStep.java | 12 ++- .../process/traversal/step/map/ProductStep.java | 15 ++- .../traversal/step/map/TraversalMergeStep.java | 3 +- .../traversal/step/sideEffect/InjectStep.java | 2 +- .../strategy/decoration/SideEffectStrategy.java | 7 +- gremlin-language/src/main/antlr4/Gremlin.g4 | 7 +- .../tinkerpop/gremlin/features/StepDefinition.java | 25 ++--- 20 files changed, 333 insertions(+), 124 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 3bfb22d17b..f32e40e44b 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 @@ -414,11 +414,11 @@ public class DefaultGremlinBaseVisitor<T> extends AbstractParseTreeVisitor<T> im /** * {@inheritDoc} */ - @Override public T visitTraversalMethod_from_Traversal(final GremlinParser.TraversalMethod_from_TraversalContext ctx) { notImplemented(ctx); return null; } + @Override public T visitTraversalMethod_from_Vertex(final GremlinParser.TraversalMethod_from_VertexContext ctx) { notImplemented(ctx); return null; } /** * {@inheritDoc} */ - @Override public T visitTraversalMethod_from_Vertex(final GremlinParser.TraversalMethod_from_VertexContext ctx) { notImplemented(ctx); return null; } + @Override public T visitTraversalMethod_from_Traversal(final GremlinParser.TraversalMethod_from_TraversalContext ctx) { notImplemented(ctx); return null; } /** * {@inheritDoc} */ @@ -854,11 +854,11 @@ public class DefaultGremlinBaseVisitor<T> extends AbstractParseTreeVisitor<T> im /** * {@inheritDoc} */ - @Override public T visitTraversalMethod_to_Traversal(final GremlinParser.TraversalMethod_to_TraversalContext ctx) { notImplemented(ctx); return null; } + @Override public T visitTraversalMethod_to_Vertex(final GremlinParser.TraversalMethod_to_VertexContext ctx) { notImplemented(ctx); return null; } /** * {@inheritDoc} */ - @Override public T visitTraversalMethod_to_Vertex(final GremlinParser.TraversalMethod_to_VertexContext ctx) { notImplemented(ctx); return null; } + @Override public T visitTraversalMethod_to_Traversal(final GremlinParser.TraversalMethod_to_TraversalContext ctx) { notImplemented(ctx); return null; } /** * {@inheritDoc} */ @@ -1395,10 +1395,6 @@ public class DefaultGremlinBaseVisitor<T> extends AbstractParseTreeVisitor<T> im * {@inheritDoc} */ @Override public T visitTraversalMethod_option_Merge_Map(final GremlinParser.TraversalMethod_option_Merge_MapContext ctx) { notImplemented(ctx); return null; } - /** - * {@inheritDoc} - */ - @Override public T visitTraversalMethod_option_Merge_Traversal(final GremlinParser.TraversalMethod_option_Merge_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 fe500e6210..daf72820d4 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 @@ -25,14 +25,12 @@ 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.GType; import org.apache.tinkerpop.gremlin.process.traversal.step.GValue; +import org.apache.tinkerpop.gremlin.structure.Vertex; import org.apache.tinkerpop.gremlin.structure.VertexProperty.Cardinality; -import java.util.Collection; import java.util.Map; import java.util.function.BiFunction; -import static org.apache.tinkerpop.gremlin.process.traversal.SackFunctions.Barrier.normSack; - /** * Specific case of TraversalRootVisitor where all TraversalMethods returns * a GraphTraversal object. @@ -535,7 +533,11 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal> */ @Override public GraphTraversal visitTraversalMethod_difference_Object(final GremlinParser.TraversalMethod_difference_ObjectContext ctx) { - return graphTraversal.difference(antlr.argumentVisitor.visitGenericLiteralArgument(ctx.genericLiteralArgument())); + final Object literalOrVar = antlr.argumentVisitor.visitGenericLiteralArgument(ctx.genericLiteralArgument()); + if (literalOrVar instanceof GValue && ((GValue) literalOrVar).getType().isCollection()) + return graphTraversal.difference((GValue<Object>) literalOrVar); + else + return graphTraversal.difference(literalOrVar); } /** @@ -543,7 +545,11 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal> */ @Override public GraphTraversal visitTraversalMethod_disjunct_Object(final GremlinParser.TraversalMethod_disjunct_ObjectContext ctx) { - return graphTraversal.disjunct(antlr.argumentVisitor.visitGenericLiteralArgument(ctx.genericLiteralArgument())); + final Object literalOrVar = antlr.argumentVisitor.visitGenericLiteralArgument(ctx.genericLiteralArgument()); + if (literalOrVar instanceof GValue && ((GValue) literalOrVar).getType().isCollection()) + return graphTraversal.disjunct((GValue<Object>) literalOrVar); + else + return graphTraversal.disjunct(literalOrVar); } /** @@ -640,8 +646,22 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal> * {@inheritDoc} */ @Override - public GraphTraversal visitTraversalMethod_from_String(final GremlinParser.TraversalMethod_from_StringContext ctx) { - return graphTraversal.from(antlr.argumentVisitor.parseString(ctx.stringArgument())); + public Traversal visitTraversalMethod_from_String(final GremlinParser.TraversalMethod_from_StringContext ctx) { + return graphTraversal.from(antlr.genericVisitor.parseString(ctx.stringLiteral())); + } + + /** + * {@inheritDoc} + */ + @Override + public Traversal visitTraversalMethod_from_Vertex(final GremlinParser.TraversalMethod_from_VertexContext ctx) { + final Object literalOrVar = antlr.argumentVisitor.visitStructureVertexArgument(ctx.structureVertexArgument()); + if (literalOrVar instanceof Vertex) + return graphTraversal.from((Vertex) literalOrVar); + else if (literalOrVar instanceof GValue && ((GValue) literalOrVar).getType() == GType.VERTEX) + return graphTraversal.from((GValue<Vertex>) literalOrVar); + else + throw new IllegalArgumentException("from argument must be a vertex"); } /** @@ -1162,15 +1182,6 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal> return graphTraversal.option(antlr.argumentVisitor.parseMerge(ctx.traversalMergeArgument()), (Map) literalOrVar); } - /** - * {@inheritDoc} - */ - @Override - public GraphTraversal visitTraversalMethod_option_Merge_Traversal(final GremlinParser.TraversalMethod_option_Merge_TraversalContext ctx) { - return this.graphTraversal.option(antlr.argumentVisitor.parseMerge(ctx.traversalMergeArgument()), - antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal())); - } - /** * {@inheritDoc} */ @@ -1298,7 +1309,11 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal> */ @Override public GraphTraversal visitTraversalMethod_product_Object(final GremlinParser.TraversalMethod_product_ObjectContext ctx) { - return graphTraversal.product(antlr.argumentVisitor.visitGenericLiteralArgument(ctx.genericLiteralArgument())); + final Object literalOrVar = antlr.argumentVisitor.visitGenericLiteralArgument(ctx.genericLiteralArgument()); + if (literalOrVar instanceof GValue && ((GValue) literalOrVar).getType().isCollection()) + return graphTraversal.product((GValue<Object>) literalOrVar); + else + return graphTraversal.product(literalOrVar); } /** @@ -1641,7 +1656,7 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal> */ @Override public GraphTraversal visitTraversalMethod_to_Direction_String(final GremlinParser.TraversalMethod_to_Direction_StringContext ctx) { - return graphTraversal.to(antlr.argumentVisitor.parseDirection(ctx.traversalDirectionArgument()), + return graphTraversal.to(TraversalEnumParser.parseTraversalDirectionFromContext(ctx.traversalDirection()), antlr.genericVisitor.parseStringVarargs(ctx.stringLiteralVarargs())); } @@ -1649,8 +1664,22 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal> * {@inheritDoc} */ @Override - public GraphTraversal visitTraversalMethod_to_String(final GremlinParser.TraversalMethod_to_StringContext ctx) { - return graphTraversal.to(antlr.argumentVisitor.parseString(ctx.stringArgument())); + public Traversal visitTraversalMethod_to_String(final GremlinParser.TraversalMethod_to_StringContext ctx) { + return graphTraversal.to(antlr.genericVisitor.parseString(ctx.stringLiteral())); + } + + /** + * {@inheritDoc} + */ + @Override + public Traversal visitTraversalMethod_to_Vertex(final GremlinParser.TraversalMethod_to_VertexContext ctx) { + final Object literalOrVar = antlr.argumentVisitor.visitStructureVertexArgument(ctx.structureVertexArgument()); + if (literalOrVar instanceof Vertex) + return graphTraversal.to((Vertex) literalOrVar); + else if (literalOrVar instanceof GValue && ((GValue) literalOrVar).getType() == GType.VERTEX) + return graphTraversal.to((GValue<Vertex>) literalOrVar); + else + throw new IllegalArgumentException("from argument must be a vertex"); } /** @@ -1789,22 +1818,6 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal> antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal())); } - /** - * {@inheritDoc} - */ - @Override - public Traversal visitTraversalMethod_from_Vertex(final GremlinParser.TraversalMethod_from_VertexContext ctx) { - return graphTraversal.from(antlr.argumentVisitor.parseVertex(ctx.structureVertexArgument())); - } - - /** - * {@inheritDoc} - */ - @Override - public Traversal visitTraversalMethod_to_Vertex(final GremlinParser.TraversalMethod_to_VertexContext ctx) { - return graphTraversal.to(antlr.argumentVisitor.parseVertex(ctx.structureVertexArgument())); - } - /** * {@inheritDoc} */ @@ -1826,8 +1839,11 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal> */ @Override public Traversal visitTraversalMethod_call_string_map(final GremlinParser.TraversalMethod_call_string_mapContext ctx) { - return graphTraversal.call(antlr.argumentVisitor.parseString(ctx.stringArgument()), - antlr.argumentVisitor.parseMap(ctx.genericLiteralMapArgument())); + final Object literalOrVar = antlr.argumentVisitor.visitGenericLiteralMapArgument(ctx.genericLiteralMapArgument()); + if (literalOrVar instanceof GValue && ((GValue) literalOrVar).getType() == GType.MAP) + return graphTraversal.call(antlr.argumentVisitor.parseString(ctx.stringArgument()), (GValue<Map>) literalOrVar); + else + return graphTraversal.call(antlr.argumentVisitor.parseString(ctx.stringArgument()), (Map) literalOrVar); } /** @@ -1844,9 +1860,11 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal> */ @Override public Traversal visitTraversalMethod_call_string_map_traversal(final GremlinParser.TraversalMethod_call_string_map_traversalContext ctx) { - return graphTraversal.call(antlr.argumentVisitor.parseString(ctx.stringArgument()), - antlr.argumentVisitor.parseMap(ctx.genericLiteralMapArgument()), - antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal())); + final Object literalOrVar = antlr.argumentVisitor.visitGenericLiteralMapArgument(ctx.genericLiteralMapArgument()); + if (literalOrVar instanceof GValue && ((GValue) literalOrVar).getType() == GType.MAP) + return graphTraversal.call(antlr.argumentVisitor.parseString(ctx.stringArgument()), (GValue<Map>) literalOrVar, antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal())); + else + return graphTraversal.call(antlr.argumentVisitor.parseString(ctx.stringArgument()), (Map) literalOrVar, antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal())); } /** 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 8e5ba3ded2..bedf28d487 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 @@ -177,8 +177,11 @@ public class TraversalSourceSpawnMethodVisitor extends DefaultGremlinBaseVisitor */ @Override public GraphTraversal visitTraversalSourceSpawnMethod_call_string_map(final GremlinParser.TraversalSourceSpawnMethod_call_string_mapContext ctx) { - return this.traversalSource.call(antlr.argumentVisitor.parseString(ctx.stringArgument()), - antlr.argumentVisitor.parseMap(ctx.genericLiteralMapArgument())); + final Object literalOrVar = antlr.argumentVisitor.visitGenericLiteralMapArgument(ctx.genericLiteralMapArgument()); + if (literalOrVar instanceof GValue && ((GValue) literalOrVar).getType() == GType.MAP) + return this.traversalSource.asAdmin().call(antlr.argumentVisitor.parseString(ctx.stringArgument()), (GValue<Map>) literalOrVar); + else + return this.traversalSource.call(antlr.argumentVisitor.parseString(ctx.stringArgument()), (Map) literalOrVar); } /** @@ -195,9 +198,11 @@ public class TraversalSourceSpawnMethodVisitor extends DefaultGremlinBaseVisitor */ @Override public GraphTraversal visitTraversalSourceSpawnMethod_call_string_map_traversal(final GremlinParser.TraversalSourceSpawnMethod_call_string_map_traversalContext ctx) { - return this.traversalSource.call(antlr.argumentVisitor.parseString(ctx.stringArgument()), - antlr.argumentVisitor.parseMap(ctx.genericLiteralMapArgument()), - anonymousVisitor.visitNestedTraversal(ctx.nestedTraversal())); + final Object literalOrVar = antlr.argumentVisitor.visitGenericLiteralMapArgument(ctx.genericLiteralMapArgument()); + if (literalOrVar instanceof GValue && ((GValue) literalOrVar).getType() == GType.MAP) + return this.traversalSource.asAdmin().call(antlr.argumentVisitor.parseString(ctx.stringArgument()), (GValue<Map>) literalOrVar, anonymousVisitor.visitNestedTraversal(ctx.nestedTraversal())); + else + return this.traversalSource.call(antlr.argumentVisitor.parseString(ctx.stringArgument()), (Map) literalOrVar, anonymousVisitor.visitNestedTraversal(ctx.nestedTraversal())); } /** diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/DotNetTranslateVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/DotNetTranslateVisitor.java index 2701819624..f4607ae087 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/DotNetTranslateVisitor.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/DotNetTranslateVisitor.java @@ -872,16 +872,19 @@ public class DotNetTranslateVisitor extends AbstractTranslateVisitor { } @Override - public Void visitTraversalMethod_option_Merge_Traversal(final GremlinParser.TraversalMethod_option_Merge_TraversalContext ctx) { - // call is ambiguous without an explicit cast - visit(ctx.getChild(0)); - sb.append("("); - visit(ctx.traversalMergeArgument()); - sb.append(", "); - sb.append("(ITraversal) "); - visit(ctx.nestedTraversal()); - sb.append(")"); - return null; + public Void visitTraversalMethod_option_Object_Traversal(final GremlinParser.TraversalMethod_option_Object_TraversalContext ctx) { + if (ctx.genericLiteralArgument().genericLiteral().traversalMerge() != null) { + visit(ctx.getChild(0)); + sb.append("("); + visit(ctx.genericLiteralArgument()); + sb.append(", "); + sb.append("(ITraversal) "); + visit(ctx.nestedTraversal()); + sb.append(")"); + return null; + } else { + return super.visitTraversalMethod_option_Object_Traversal(ctx); + } } @Override diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/TranslateVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/TranslateVisitor.java index 00a8523b45..553ae00be7 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/TranslateVisitor.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/TranslateVisitor.java @@ -902,11 +902,6 @@ public class TranslateVisitor extends AbstractParseTreeVisitor<Void> implements return visitChildren(ctx); } - @Override - public Void visitTraversalMethod_option_Merge_Traversal(final GremlinParser.TraversalMethod_option_Merge_TraversalContext ctx) { - return visitChildren(ctx); - } - @Override public Void visitTraversalMethod_option_Object_Traversal(final GremlinParser.TraversalMethod_option_Object_TraversalContext ctx) { return visitChildren(ctx); diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Operator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Operator.java index 5bb2c85b3a..2e2a2ee91d 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Operator.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Operator.java @@ -186,9 +186,13 @@ public enum Operator implements BinaryOperator<Object> { if (a instanceof Map && b instanceof Map) ((Map<?,?>) a).putAll((Map) b); - else if (a instanceof Collection && a instanceof Collection) - ((Collection<?>) a).addAll((Collection) b); - else + else if (a instanceof Collection && a instanceof Collection) { + try { + ((Collection<?>) a).addAll((Collection) b); + } catch (UnsupportedOperationException uoe) { + uoe.printStackTrace(); + } + } else throw new IllegalArgumentException(String.format("Objects must be both of Map or Collection: a=%s b=%s", a.getClass().getSimpleName(), b.getClass().getSimpleName())); return a; 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 7967688a87..0a392fc334 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 @@ -550,6 +550,30 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> { return this.asAdmin().addStep(new ConjoinStep<>(this.asAdmin(), delimiter)); } + /** + * Calculates the difference between the list traverser and list argument. + * + * @return the traversal with an appended {@link DifferenceStep}. + * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#difference-step" target="_blank">Reference Documentation - Difference Step</a> + * @since 3.7.1 + */ + public default GraphTraversal<S, Set<?>> difference(final GValue<Object> values) { + this.asAdmin().getBytecode().addStep(GraphTraversal.Symbols.difference, values); + return this.asAdmin().addStep(new DifferenceStep<>(this.asAdmin(), values)); + } + + /** + * Calculates the disjunction between the list traverser and list argument. + * + * @return the traversal with an appended {@link DisjunctStep}. + * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#disjunct-step" target="_blank">Reference Documentation - Disjunct Step</a> + * @since 3.7.3 + */ + public default GraphTraversal<S, Set<?>> disjunct(final GValue<Object> values) { + this.asAdmin().getBytecode().addStep(GraphTraversal.Symbols.disjunct, values); + return this.asAdmin().addStep(new DisjunctStep<>(this.asAdmin(), values)); + } + /** * Calculates the intersection between the list traverser and list argument. * @@ -567,13 +591,98 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> { * * @return the traversal with an appended {@link TraversalMergeStep}. * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#merge-step" target="_blank">Reference Documentation - Merge Step</a> - * @since 3.7.1 + * @since 3.7.3 */ public default <E2> GraphTraversal<S, E2> merge(final GValue<Object> values) { this.asAdmin().getBytecode().addStep(GraphTraversal.Symbols.merge, values); return this.asAdmin().addStep(new TraversalMergeStep<>(this.asAdmin(), values)); } + /** + * Calculates the cartesian product between the list traverser and list argument. + * + * @return the traversal with an appended {@link ProductStep}. + * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#product-step" target="_blank">Reference Documentation - Product Step</a> + * @since 3.7.3 + */ + public default GraphTraversal<S, List<List<?>>> product(final GValue<Object> values) { + this.asAdmin().getBytecode().addStep(GraphTraversal.Symbols.product, values); + return this.asAdmin().addStep(new ProductStep<>(this.asAdmin(), values)); + } + + /** + * When used as a modifier to {@link #addE(String)} this method specifies the traversal to use for selecting the + * incoming vertex of the newly added {@link Edge}. + * + * @param toVertex the vertex for selecting the incoming vertex + * @return the traversal with the modified {@link AddEdgeStep} + * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#addedge-step" target="_blank">Reference Documentation - From Step</a> + * @since 4.0.0 + */ + public default GraphTraversal<S, E> to(final GValue<Vertex> toVertex) { + final Step<?,?> prev = this.asAdmin().getEndStep(); + if (!(prev instanceof FromToModulating)) + throw new IllegalArgumentException(String.format( + "The to() step cannot follow %s", prev.getClass().getSimpleName())); + + this.asAdmin().getBytecode().addStep(GraphTraversal.Symbols.to, toVertex); + ((FromToModulating) prev).addTo(__.constant(toVertex).asAdmin()); + return this; + } + + /** + * When used as a modifier to {@link #addE(String)} this method specifies the traversal to use for selecting the + * outgoing vertex of the newly added {@link Edge}. + * + * @param fromVertex the vertex for selecting the outgoing vertex + * @return the traversal with the modified {@link AddEdgeStep} + * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#addedge-step" target="_blank">Reference Documentation - From Step</a> + * @since 4.0.0 + */ + public default GraphTraversal<S, E> from(final GValue<Vertex> fromVertex) { + final Step<?,?> prev = this.asAdmin().getEndStep(); + if (!(prev instanceof FromToModulating)) + throw new IllegalArgumentException(String.format( + "The from() step cannot follow %s", prev.getClass().getSimpleName())); + + this.asAdmin().getBytecode().addStep(GraphTraversal.Symbols.from, fromVertex); + ((FromToModulating) prev).addFrom(__.constant(fromVertex).asAdmin()); + return this; + } + + /** + * Perform the specified service call with the specified static parameters. + * + * @param service the name of the service call + * @param params static parameter map (no nested traversals) + * @return the traversal with an appended {@link CallStep}. + * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#call-step" target="_blank">Reference Documentation - Call Step</a> + * @since 4.0.0 + */ + default <E> GraphTraversal<S, E> call(final String service, final GValue<Map> params) { + this.asAdmin().getBytecode().addStep(GraphTraversal.Symbols.call, service, params); + final CallStep<S,E> call = new CallStep<>(this.asAdmin(), false, service, params); + return this.asAdmin().addStep(call); + } + /** + * Perform the specified service call with both static and dynamic parameters produced by the specified child + * traversal. These parameters will be merged at execution time per the provider implementation. Reference + * implementation merges dynamic into static (dynamic will overwrite static). + * + * @param service the name of the service call + * @param params static parameter map (no nested traversals) + * @param childTraversal a traversal that will produce a Map of parameters for the service call when invoked. + * @return the traversal with an appended {@link CallStep}. + * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#call-step" target="_blank">Reference Documentation - Call Step</a> + * @since 4.0.0 + */ + default <E> GraphTraversal<S, E> call(final String service, final GValue<Map> params, final Traversal<?, Map<?,?>> childTraversal) { + this.asAdmin().getBytecode().addStep(GraphTraversal.Symbols.call, service, params, childTraversal); + final CallStep<S,E> step = null == childTraversal ? new CallStep(this.asAdmin(), false, service, params) : + new CallStep(this.asAdmin(), false, service, params, childTraversal.asAdmin()); + return this.asAdmin().addStep(step); + } + @Override public default <E2> GraphTraversal.Admin<S, E2> addStep(final Step<?, E2> step) { return (GraphTraversal.Admin<S, E2>) Traversal.Admin.super.addStep((Step) step); @@ -2725,8 +2834,7 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> { public default GraphTraversal<S, E> hasId(final Object id, final Object... otherIds) { if (id instanceof P) { return this.hasId((P) id); - } - else { + } else { this.asAdmin().getBytecode().addStep(Symbols.hasId, id, otherIds); //using ArrayList given P.within() turns all arguments into lists @@ -2737,8 +2845,9 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> { // as ids are unrolled when it's in array, they should also be unrolled when it's a list. // this also aligns with behavior of hasId() when it's pushed down to g.V() (TINKERPOP-2863) ids.addAll((Collection<?>) id); - } else + } else { ids.add(id); + } // unrolling ids from lists works cleaner with Collection too, as otherwise they will need to // be turned into array first 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 0c0670a7ca..be9ec2d44e 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 @@ -638,6 +638,36 @@ public class GraphTraversalSource implements TraversalSource { */ public class Admin { + /** + * Spawns a {@link GraphTraversal} starting with values produced by the specified service call with the specified + * static parameters. + * + * @param service the name of the service call + * @param params static parameter map (no nested traversals) + * @since 4.0.0 + */ + public <S> GraphTraversal<S, S> call(final String service, final GValue<Map> params) { + final GraphTraversalSource clone = GraphTraversalSource.this.clone(); + clone.bytecode.addStep(GraphTraversal.Symbols.call, service, params); + final GraphTraversal.Admin<S, S> traversal = new DefaultGraphTraversal<>(clone); + return traversal.addStep(new CallStep<>(traversal, true, service, params)); + } + + /** + * Spawns a {@link GraphTraversal} starting with values produced by the specified service call with the specified + * static parameters. + * + * @param service the name of the service call + * @param params static parameter map (no nested traversals) + * @since 4.0.0 + */ + public <S> GraphTraversal<S, S> call(final String service, final GValue<Map> params, final Traversal<S, Map> childTraversal) { + final GraphTraversalSource clone = GraphTraversalSource.this.clone(); + clone.bytecode.addStep(GraphTraversal.Symbols.call, service, params); + final GraphTraversal.Admin<S, S> traversal = new DefaultGraphTraversal<>(clone); + return traversal.addStep(new CallStep<>(traversal, true, service, params, childTraversal.asAdmin())); + } + /** * Spawns a {@link GraphTraversal} by doing a merge (i.e. upsert) style operation for an {@link Vertex} using a * {@code Map} as an argument. The {@code Map} represents search criteria and will match each of the supplied @@ -645,7 +675,7 @@ public class GraphTraversalSource implements TraversalSource { * made it will use that search criteria to create the new {@link Vertex}. * * @param searchCreate This {@code Map} can have a key of {@link T} or a {@code String}. - * @since 3.6.0 + * @since 4.0.0 */ public GraphTraversal<Vertex, Vertex> mergeV(final GValue<Map<Object, Object>> searchCreate) { final GraphTraversalSource clone = GraphTraversalSource.this.clone(); diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/GValue.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/GValue.java index e05a9e91f4..41caaea1a2 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/GValue.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/GValue.java @@ -79,6 +79,13 @@ public class GValue<V> implements Cloneable, Serializable { return this.type; } + /** + * Determines if the value held is of a {@code null} value. + */ + public boolean isNull() { + return this.value == null; + } + /** * Gets the value. */ @@ -96,7 +103,7 @@ public class GValue<V> implements Cloneable, Serializable { public boolean equals(final Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; - GValue<?> gValue = (GValue<?>) o; + final GValue<?> gValue = (GValue<?>) o; return Objects.equals(name, gValue.name) && type == gValue.type && Objects.equals(value, gValue.value); } diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStep.java index 9dfa4ce754..82c7f3893b 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStep.java @@ -21,6 +21,7 @@ package org.apache.tinkerpop.gremlin.process.traversal.step.map; import org.apache.tinkerpop.gremlin.process.traversal.Traversal; import org.apache.tinkerpop.gremlin.process.traversal.Traverser; import org.apache.tinkerpop.gremlin.process.traversal.step.FromToModulating; +import org.apache.tinkerpop.gremlin.process.traversal.step.GType; import org.apache.tinkerpop.gremlin.process.traversal.step.GValue; import org.apache.tinkerpop.gremlin.process.traversal.step.Scoping; import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent; @@ -113,7 +114,7 @@ public class AddEdgeStep<S> extends ScalarMapStep<S, Edge> edgeLabel, e.getMessage())); } - if (!(theTo instanceof Vertex)) + if (!(theTo instanceof Vertex) && (theTo instanceof GValue && ((GValue) theTo).getType() != GType.VERTEX)) throw new IllegalStateException(String.format( "The value given to addE(%s).to() must resolve to a Vertex but %s was specified instead", edgeLabel, null == theTo ? "null" : theTo.getClass().getSimpleName())); @@ -127,13 +128,13 @@ public class AddEdgeStep<S> extends ScalarMapStep<S, Edge> edgeLabel, e.getMessage())); } - if (!(theFrom instanceof Vertex)) + if (!(theFrom instanceof Vertex) && (theFrom instanceof GValue && ((GValue) theTo).getType() != GType.VERTEX)) throw new IllegalStateException(String.format( "The value given to addE(%s).to() must resolve to a Vertex but %s was specified instead", edgeLabel, null == theFrom ? "null" : theFrom.getClass().getSimpleName())); - Vertex toVertex = (Vertex) theTo; - Vertex fromVertex = (Vertex) theFrom; + Vertex toVertex = theTo instanceof Vertex ? (Vertex) theTo : ((GValue<Vertex>) theTo).get(); + Vertex fromVertex = theFrom instanceof Vertex ? (Vertex) theFrom : ((GValue<Vertex>) theFrom).get(); if (toVertex instanceof Attachable) toVertex = ((Attachable<Vertex>) toVertex) diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/CallStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/CallStep.java index 2435be373c..3dd99d1703 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/CallStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/CallStep.java @@ -22,6 +22,7 @@ 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.Configuring; +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.Parameters; @@ -62,7 +63,7 @@ public final class CallStep<S, E> extends AbstractStep<S, E> implements Traversa private ServiceCallContext ctx; private String serviceName; private Service<S, E> service; - private Map staticParams; + private GValue<Map> staticParams; private Traversal.Admin<S,Map> mapTraversal; private Parameters parameters; @@ -74,20 +75,29 @@ public final class CallStep<S, E> extends AbstractStep<S, E> implements Traversa } public CallStep(final Traversal.Admin traversal, final boolean isStart, final String service) { - this(traversal, isStart, service, null); + this(traversal, isStart, service, (Map) null); } public CallStep(final Traversal.Admin traversal, final boolean isStart, final String service, final Map staticParams) { + this(traversal, isStart, service, GValue.ofMap(staticParams)); + } + + public CallStep(final Traversal.Admin traversal, final boolean isStart, final String service, final GValue<Map> staticParams) { this(traversal, isStart, service, staticParams, null); } public CallStep(final Traversal.Admin traversal, final boolean isStart, final String service, final Map staticParams, final Traversal.Admin<S, Map> mapTraversal) { + this(traversal, isStart, service, GValue.ofMap(staticParams), mapTraversal); + } + + public CallStep(final Traversal.Admin traversal, final boolean isStart, final String service, final GValue<Map> staticParams, + final Traversal.Admin<S, Map> mapTraversal) { super(traversal); this.isStart = isStart; this.serviceName = service; - this.staticParams = staticParams == null ? new LinkedHashMap() : staticParams; + this.staticParams = staticParams == null || staticParams.isNull() ? GValue.ofMap(staticParams.getName(), new LinkedHashMap()) : staticParams; this.mapTraversal = mapTraversal == null ? null : integrateChild(mapTraversal); this.parameters = new Parameters(); this.ctx = new ServiceCallContext(traversal, this); @@ -95,13 +105,17 @@ public final class CallStep<S, E> extends AbstractStep<S, E> implements Traversa protected Service<S, E> service() { // throws exception for unrecognized service - return service != null ? service : (service = getServiceRegistry().get(serviceName, isStart, staticParams)); + return service != null ? service : (service = getServiceRegistry().get(serviceName, isStart, staticParams.get())); } public String getServiceName() { return serviceName; } + public GValue<Map> getStaticParams() { + return staticParams; + } + @Override protected Traverser.Admin<E> processNextStart() { if (isStart && first) { @@ -199,7 +213,7 @@ public final class CallStep<S, E> extends AbstractStep<S, E> implements Traversa public Map getMergedParams() { if (mapTraversal == null && parameters.isEmpty()) { // static params only - return Collections.unmodifiableMap(this.staticParams); + return Collections.unmodifiableMap(this.staticParams.get()); } return getMergedParams(new DummyTraverser(this.traversal.getTraverserGenerator())); @@ -208,11 +222,11 @@ public final class CallStep<S, E> extends AbstractStep<S, E> implements Traversa protected Map getMergedParams(final Traverser.Admin<S> traverser) { if (mapTraversal == null && parameters.isEmpty()) { // static params only - return Collections.unmodifiableMap(this.staticParams); + return Collections.unmodifiableMap(this.staticParams.get()); } // merge dynamic with static params - final Map params = new LinkedHashMap(this.staticParams); + final Map params = new LinkedHashMap(this.staticParams.get()); if (mapTraversal != null) params.putAll(TraversalUtil.apply(traverser, mapTraversal)); final Object[] kvs = this.parameters.getKeyValues(traverser); for (int i = 0; i < kvs.length; i += 2) { @@ -225,7 +239,7 @@ public final class CallStep<S, E> extends AbstractStep<S, E> implements Traversa protected Map getMergedParams(final TraverserSet<S> traverserSet) { if (mapTraversal == null && parameters.isEmpty()) { // static params only - return Collections.unmodifiableMap(this.staticParams); + return Collections.unmodifiableMap(this.staticParams.get()); } /* @@ -302,7 +316,7 @@ public final class CallStep<S, E> extends AbstractStep<S, E> implements Traversa public String toString() { final ArrayList args = new ArrayList(); args.add(serviceName); - if (!staticParams.isEmpty()) + if (!staticParams.get().isEmpty()) args.add(staticParams); if (mapTraversal != null) args.add(mapTraversal); @@ -314,8 +328,8 @@ public final class CallStep<S, E> extends AbstractStep<S, E> implements Traversa @Override public int hashCode() { int hashCode = super.hashCode() ^ Objects.hashCode(this.serviceName); - if (!staticParams.isEmpty()) - hashCode ^= staticParams.hashCode(); + if (!staticParams.get().isEmpty()) + hashCode ^= staticParams.get().hashCode(); if (mapTraversal != null) hashCode ^= mapTraversal.hashCode(); if (!parameters.isEmpty()) diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConstantStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConstantStep.java index 245a443e5a..2145f7e966 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConstantStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConstantStep.java @@ -33,7 +33,7 @@ public class ConstantStep<S, E> extends ScalarMapStep<S, E> { private final GValue<E> constant; public ConstantStep(final Traversal.Admin traversal, final E constant) { - this(traversal, GValue.of(constant)); + this(traversal, constant instanceof GValue ? (GValue) constant : GValue.of(constant)); } public ConstantStep(final Traversal.Admin traversal, final GValue<E> constant) { diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DifferenceStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DifferenceStep.java index 1317f931c4..87f44f8639 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DifferenceStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DifferenceStep.java @@ -20,6 +20,7 @@ package org.apache.tinkerpop.gremlin.process.traversal.step.map; 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.traverser.TraverserRequirement; import org.apache.tinkerpop.gremlin.process.traversal.util.ListFunction; @@ -36,24 +37,33 @@ import java.util.Set; */ public final class DifferenceStep<S, E> extends ScalarMapStep<S, Set<?>> implements TraversalParent, ListFunction { private Traversal.Admin<S, E> valueTraversal; - private Object parameterItems; + private GValue<Object> parameterItems; + public DifferenceStep(final Traversal.Admin traversal, final Object values) { super(traversal); if (values instanceof Traversal) { valueTraversal = integrateChild(((Traversal<S, E>) values).asAdmin()); } else { - parameterItems = values; + parameterItems = values instanceof GValue ? (GValue<Object>) values : GValue.of(values); } } + public Traversal.Admin<S,E> getValueTraversal() { + return this.valueTraversal; + } + + public GValue<Object> getParameterItems() { + return parameterItems; + } + @Override public String getStepName() { return "difference"; } @Override protected Set<?> map(Traverser.Admin<S> traverser) { final Collection setA = convertTraverserToCollection(traverser); - final Collection setB = (null != valueTraversal) ? convertTraversalToCollection(traverser, valueTraversal) : convertArgumentToCollection(parameterItems); + final Collection setB = (null != valueTraversal) ? convertTraversalToCollection(traverser, valueTraversal) : convertArgumentToCollection(parameterItems.get()); final Set differenceSet = new HashSet(); for (Object element : setA) { diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DisjunctStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DisjunctStep.java index 60eebf0457..fc890dd2a2 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DisjunctStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DisjunctStep.java @@ -20,6 +20,7 @@ package org.apache.tinkerpop.gremlin.process.traversal.step.map; 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.traverser.TraverserRequirement; import org.apache.tinkerpop.gremlin.process.traversal.util.ListFunction; @@ -35,14 +36,15 @@ import java.util.Set; */ public final class DisjunctStep<S, E> extends ScalarMapStep<S, Set<?>> implements TraversalParent, ListFunction { private Traversal.Admin<S, E> valueTraversal; - private Object parameterItems; + private GValue<Object> parameterItems; + public DisjunctStep(final Traversal.Admin traversal, final Object values) { super(traversal); if (values instanceof Traversal) { valueTraversal = integrateChild(((Traversal<S, E>) values).asAdmin()); } else { - parameterItems = values; + parameterItems = values instanceof GValue ? (GValue<Object>) values : GValue.of(values); } } @@ -50,8 +52,8 @@ public final class DisjunctStep<S, E> extends ScalarMapStep<S, Set<?>> implement return this.valueTraversal; } - public Object getParameterItems() { - return this.parameterItems; + public GValue<Object> getParameterItems() { + return parameterItems; } @Override @@ -60,7 +62,7 @@ public final class DisjunctStep<S, E> extends ScalarMapStep<S, Set<?>> implement @Override protected Set<?> map(Traverser.Admin<S> traverser) { final Set setA = convertTraverserToSet(traverser); - final Set setB = (null != valueTraversal) ? convertTraversalToSet(traverser, this.valueTraversal) : convertArgumentToSet(parameterItems); + final Set setB = (null != valueTraversal) ? convertTraversalToSet(traverser, this.valueTraversal) : convertArgumentToSet(parameterItems.get()); final Set disjunctSet = new HashSet(); if (setA.size() == 0) { diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProductStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProductStep.java index b14c02ba92..4842a313bb 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProductStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProductStep.java @@ -20,6 +20,7 @@ package org.apache.tinkerpop.gremlin.process.traversal.step.map; 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.traverser.TraverserRequirement; import org.apache.tinkerpop.gremlin.process.traversal.util.ListFunction; @@ -36,7 +37,7 @@ import java.util.Set; */ public final class ProductStep<S, E> extends ScalarMapStep<S, List<List<?>>> implements TraversalParent, ListFunction { private Traversal.Admin<S, E> valueTraversal; - private Object parameterItems; + private GValue<Object> parameterItems; public ProductStep(final Traversal.Admin traversal, final Object values) { super(traversal); @@ -44,17 +45,25 @@ public final class ProductStep<S, E> extends ScalarMapStep<S, List<List<?>>> imp if (values instanceof Traversal) { valueTraversal = integrateChild(((Traversal<S, E>) values).asAdmin()); } else { - parameterItems = values; + parameterItems = values instanceof GValue ? (GValue<Object>) values : GValue.of(values); } } + public Traversal.Admin<S,E> getValueTraversal() { + return this.valueTraversal; + } + + public GValue<Object> getParameterItems() { + return parameterItems; + } + @Override public String getStepName() { return "product"; } @Override protected List<List<?>> map(Traverser.Admin<S> traverser) { final Collection listA = convertTraverserToCollection(traverser); - final Collection listB = (null != valueTraversal) ? convertTraversalToCollection(traverser, valueTraversal) : convertArgumentToCollection(parameterItems); + final Collection listB = (null != valueTraversal) ? convertTraversalToCollection(traverser, valueTraversal) : convertArgumentToCollection(parameterItems.get()); final List elements = new ArrayList(); for (Object elementInA : listA) { diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TraversalMergeStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TraversalMergeStep.java index 74d5c185de..eb82dbf381 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TraversalMergeStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TraversalMergeStep.java @@ -85,9 +85,10 @@ public final class TraversalMergeStep<S, E> extends ScalarMapStep<S, E> implemen } else { final Collection listA = convertTraverserToCollection(traverser); - if (parameterItems.get() instanceof Map) { + if (parameterItems != null && parameterItems.get() instanceof Map) { throw new IllegalArgumentException(getStepName() + " step type mismatch: expected argument to be Iterable but got Map"); } + final Collection listB = (null != valueTraversal) ? convertTraversalToCollection(traverser, valueTraversal) diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/InjectStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/InjectStep.java index ab57c05ce5..cc3a970f93 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/InjectStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/InjectStep.java @@ -39,7 +39,7 @@ public final class InjectStep<S> extends StartStep<S> { @Override public InjectStep<S> clone() { final InjectStep<S> clone = (InjectStep<S>) super.clone(); - clone.start = new ArrayIterator<>(clone.injections); + clone.start = new ArrayIterator<>(resolveToValues(clone.injections)); return clone; } diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SideEffectStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SideEffectStrategy.java index ce794b8b6a..9b309dba3f 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SideEffectStrategy.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SideEffectStrategy.java @@ -22,6 +22,7 @@ package org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration; import org.apache.tinkerpop.gremlin.process.traversal.Traversal; import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies; import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy; +import org.apache.tinkerpop.gremlin.process.traversal.step.GValue; import org.apache.tinkerpop.gremlin.process.traversal.step.util.EmptyStep; import org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy; import org.apache.tinkerpop.gremlin.util.function.ConstantSupplier; @@ -60,7 +61,11 @@ public final class SideEffectStrategy extends AbstractTraversalStrategy<Traversa strategy = cloneStrategy; traversalStrategies.addStrategies(strategy); } - strategy.sideEffects.add(new Triplet<>(key, value instanceof Supplier ? (Supplier) value : new ConstantSupplier<>(value), reducer)); + + // don't want the GValue to leak beyond strategy application or else the Supplier will start producing it + // during execution + final ConstantSupplier initialValue = value instanceof GValue ? new ConstantSupplier<>(((GValue) value).get()) : new ConstantSupplier<>(value); + strategy.sideEffects.add(new Triplet<>(key, value instanceof Supplier ? (Supplier) value : initialValue, reducer)); } public boolean contains(final String sideEffectKey) { diff --git a/gremlin-language/src/main/antlr4/Gremlin.g4 b/gremlin-language/src/main/antlr4/Gremlin.g4 index 57bfcca445..5775c27cbb 100644 --- a/gremlin-language/src/main/antlr4/Gremlin.g4 +++ b/gremlin-language/src/main/antlr4/Gremlin.g4 @@ -487,7 +487,7 @@ traversalMethod_fold ; traversalMethod_from - : 'from' LPAREN stringArgument RPAREN #traversalMethod_from_String + : 'from' LPAREN stringLiteral RPAREN #traversalMethod_from_String | 'from' LPAREN structureVertexArgument RPAREN #traversalMethod_from_Vertex | 'from' LPAREN nestedTraversal RPAREN #traversalMethod_from_Traversal ; @@ -644,7 +644,6 @@ traversalMethod_option : 'option' LPAREN traversalPredicate COMMA nestedTraversal RPAREN #traversalMethod_option_Predicate_Traversal | 'option' LPAREN traversalMergeArgument COMMA genericLiteralMapNullableArgument RPAREN #traversalMethod_option_Merge_Map | 'option' LPAREN traversalMergeArgument COMMA genericLiteralMapNullableArgument COMMA traversalCardinality RPAREN #traversalMethod_option_Merge_Map_Cardinality - | 'option' LPAREN traversalMergeArgument COMMA nestedTraversal RPAREN #traversalMethod_option_Merge_Traversal | 'option' LPAREN genericLiteralArgument COMMA nestedTraversal RPAREN #traversalMethod_option_Object_Traversal | 'option' LPAREN nestedTraversal RPAREN #traversalMethod_option_Traversal ; @@ -808,8 +807,8 @@ traversalMethod_times ; traversalMethod_to - : 'to' LPAREN traversalDirectionArgument (COMMA stringLiteralVarargs)? RPAREN #traversalMethod_to_Direction_String - | 'to' LPAREN stringArgument RPAREN #traversalMethod_to_String + : 'to' LPAREN traversalDirection (COMMA stringLiteralVarargs)? RPAREN #traversalMethod_to_Direction_String + | 'to' LPAREN stringLiteral RPAREN #traversalMethod_to_String | 'to' LPAREN structureVertexArgument RPAREN #traversalMethod_to_Vertex | 'to' LPAREN nestedTraversal RPAREN #traversalMethod_to_Traversal ; diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/StepDefinition.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/StepDefinition.java index 380313e29a..e31b3ff2d4 100644 --- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/StepDefinition.java +++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/StepDefinition.java @@ -75,6 +75,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; @@ -183,13 +184,13 @@ public final class StepDefinition { } })); - add(Pair.with(Pattern.compile("l\\[\\]"), s -> Collections.emptyList())); + add(Pair.with(Pattern.compile("l\\[\\]"), s -> new ArrayList<>())); add(Pair.with(Pattern.compile("l\\[(.*)\\]"), s -> { final String[] items = s.split(","); return Stream.of(items).map(String::trim).map(x -> convertToObject(x)).collect(Collectors.toList()); })); - add(Pair.with(Pattern.compile("s\\[\\]"), s -> Collections.emptySet())); + add(Pair.with(Pattern.compile("s\\[\\]"), s -> new HashSet<>())); add(Pair.with(Pattern.compile("s\\[(.*)\\]"), s -> { final String[] items = s.split(","); return Stream.of(items).map(String::trim).map(x -> convertToObject(x)).collect(Collectors.toSet()); @@ -235,7 +236,7 @@ public final class StepDefinition { add(Pair.with(Pattern.compile("e\\[(.+)\\]"), s -> getEdge(g, s))); add(Pair.with(Pattern.compile("t\\[(.*)\\]"), T::valueOf)); - add(Pair.with(Pattern.compile("D\\[(.*)\\]"), Direction::valueOf)); + add(Pair.with(Pattern.compile("D\\[(.*)\\]"), StepDefinition::getDirection)); add(Pair.with(Pattern.compile("M\\[(.*)\\]"), Merge::valueOf)); add(Pair.with(Pattern.compile("c\\[(.*)\\]"), s -> { @@ -382,17 +383,11 @@ public final class StepDefinition { } @Then("the graph should return {int} for count of {string}") - public void theGraphShouldReturnForCountOf(final Integer count, final String gremlin) { + public void theGraphShouldReturnForCountOf(final Integer count, final String rawGremlin) { assertThatNoErrorWasThrown(); - assertEquals(count.longValue(), ((GraphTraversal) parseGremlin(applyParameters(gremlin))).count().next()); - } - - @Then("debug the graph should return {int} for count of {string}") - public void debugTheGraphShouldReturnForCountOf(final Integer count, final String gremlin) { - assertThatNoErrorWasThrown(); - - assertEquals(count.longValue(), ((GraphTraversal) parseGremlin(applyParameters(gremlin))).count().next()); + final String gremlin = world.useParametersLiterally() ? applyParameters(rawGremlin) : rawGremlin; + assertEquals(count.longValue(), ((GraphTraversal) parseGremlin(gremlin)).count().next()); } @Then("the result should be empty") @@ -604,6 +599,12 @@ public final class StepDefinition { return docString.replace(relPath, escapeJava(absPath)); } + private static Direction getDirection(final String direction) { + if (direction.equals("from")) return Direction.OUT; + if (direction.equals("to")) return Direction.IN; + return Direction.valueOf(direction); + } + /** * TinkerPop version of Hamcrest's {code containsInAnyOrder} that can use our custom assertions for {@link Path}. */
