You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by sp...@apache.org on 2024/11/20 14:42:38 UTC
(tinkerpop) 01/01: TINKERPOP-2959 Allow parameters to work for primitives
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 0f64df12648600b2cd9b5b6fde9ef15b6a8e85f4
Author: Stephen Mallette <st...@amazon.com>
AuthorDate: Fri Jul 12 10:48:20 2024 -0400
TINKERPOP-2959 Allow parameters to work for primitives
---
.../gremlin/jsr223/GremlinLangScriptEngine.java | 17 +-
.../gremlin/jsr223/VariableResolverCustomizer.java | 40 ++
.../gremlin/jsr223/VariableResolverPlugin.java | 95 +++
.../grammar/DefaultGremlinBaseVisitor.java | 16 +-
.../language/grammar/GenericLiteralVisitor.java | 14 +
.../language/grammar/TraversalMethodVisitor.java | 191 ++++--
.../grammar/TraversalSourceSpawnMethodVisitor.java | 29 +-
.../gremlin/language/grammar/VariableResolver.java | 37 +-
.../translator/DotNetTranslateVisitor.java | 62 +-
.../translator/GroovyTranslateVisitor.java | 31 +-
.../language/translator/TranslateVisitor.java | 6 +-
.../tinkerpop/gremlin/process/traversal/P.java | 14 +-
.../gremlin/process/traversal/SackFunctions.java | 5 +-
.../traversal/dsl/graph/GraphTraversal.java | 547 ++++++++++++++++--
.../traversal/dsl/graph/GraphTraversalSource.java | 61 ++
.../gremlin/process/traversal/dsl/graph/__.java | 177 ++++++
.../traversal/lambda/ConstantTraversal.java | 15 +-
.../gremlin/process/traversal/step/GType.java | 103 ++++
.../gremlin/process/traversal/step/GValue.java | 443 ++++++++++++++
.../process/traversal/step/filter/CoinStep.java | 24 +-
.../process/traversal/step/map/AddEdgeStep.java | 15 +-
.../process/traversal/step/map/AddVertexStep.java | 5 +
.../process/traversal/step/map/CallStep.java | 36 +-
.../process/traversal/step/map/CombineStep.java | 15 +-
.../process/traversal/step/map/ConjoinStep.java | 19 +-
.../process/traversal/step/map/ConstantStep.java | 18 +-
.../process/traversal/step/map/DifferenceStep.java | 20 +-
.../process/traversal/step/map/DisjunctStep.java | 14 +-
.../process/traversal/step/map/GraphStep.java | 87 ++-
.../process/traversal/step/map/IntersectStep.java | 15 +-
.../process/traversal/step/map/MergeEdgeStep.java | 5 +
.../traversal/step/map/MergeElementStep.java | 14 +-
.../process/traversal/step/map/MergeStep.java | 23 +-
.../traversal/step/map/MergeVertexStep.java | 5 +
.../process/traversal/step/map/ProductStep.java | 19 +-
.../process/traversal/step/map/VertexStep.java | 27 +-
.../traversal/step/sideEffect/InjectStep.java | 23 +-
.../process/traversal/step/util/AbstractStep.java | 2 +-
.../process/traversal/step/util/HasContainer.java | 6 +-
.../process/traversal/step/util/Parameters.java | 21 +-
.../strategy/decoration/ElementIdStrategy.java | 7 +-
.../strategy/decoration/SideEffectStrategy.java | 7 +-
.../strategy/decoration/SubgraphStrategy.java | 2 +-
.../optimization/AdjacentToIncidentStrategy.java | 2 +-
.../optimization/IncidentToAdjacentStrategy.java | 2 +-
.../optimization/InlineFilterStrategy.java | 19 +-
.../process/traversal/util/ListFunction.java | 16 +-
.../gremlin/structure/VertexProperty.java | 3 -
.../gremlin/structure/io/gryo/GryoVersion.java | 12 +-
.../tinkerpop/gremlin/util/CollectionUtil.java | 44 +-
.../gremlin/jsr223/VariableResolverPluginTest.java | 117 ++++
.../language/grammar/ArgumentVisitorTest.java | 92 ++-
.../language/grammar/GremlinQueryParserTest.java | 8 +-
.../language/translator/GremlinTranslatorTest.java | 58 +-
.../gremlin/process/traversal/step/GTypeTest.java | 77 +++
.../gremlin/process/traversal/step/GValueTest.java | 641 +++++++++++++++++++++
.../traversal/step/map/ConjoinStepTest.java | 2 +-
.../traversal/step/util/ParametersTest.java | 11 +
.../tinkerpop/gremlin/util/CollectionUtilTest.java | 110 ++++
.../Gherkin/CommonSteps.cs | 7 -
.../Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs | 61 +-
gremlin-go/driver/cucumber/cucumberSteps_test.go | 15 +-
gremlin-go/driver/cucumber/gremlin.go | 15 +-
.../test/cucumber/feature-steps.js | 4 -
.../gremlin-javascript/test/cucumber/gremlin.js | 54 +-
gremlin-language/src/main/antlr4/Gremlin.g4 | 4 +-
.../src/main/python/radish/feature_steps.py | 11 -
gremlin-python/src/main/python/radish/gremlin.py | 54 +-
.../tinkerpop/gremlin/features/StepDefinition.java | 55 +-
.../apache/tinkerpop/gremlin/features/World.java | 9 +
.../gremlin/test/features/filter/Has.feature | 24 +
.../gremlin/test/features/filter/HasId.feature | 13 +-
.../gremlin/test/features/filter/HasLabel.feature | 28 +
.../gremlin/test/features/map/Conjoin.feature | 14 +-
.../gremlin/test/features/map/Edge.feature | 261 ++++++++-
.../gremlin/test/features/map/Vertex.feature | 248 +-------
.../traversal/step/sideEffect/Neo4jGraphStep.java | 4 +-
.../process/traversal/strategy/SparqlStrategy.java | 1 -
.../traversal/step/sideEffect/TinkerGraphStep.java | 14 +-
.../tinkerpop/gremlin/tinkergraph/TinkerWorld.java | 5 +
.../tinkergraph/structure/TinkerGraphPlayTest.java | 33 +-
81 files changed, 3773 insertions(+), 707 deletions(-)
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/GremlinLangScriptEngine.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/GremlinLangScriptEngine.java
index 440c27ad56..5528b280b1 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/GremlinLangScriptEngine.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/GremlinLangScriptEngine.java
@@ -31,7 +31,11 @@ import javax.script.ScriptException;
import javax.script.SimpleBindings;
import java.io.IOException;
import java.io.Reader;
+import java.util.Arrays;
+import java.util.List;
import java.util.Map;
+import java.util.Optional;
+import java.util.function.Function;
/**
* A {@link GremlinScriptEngine} implementation that evaluates Gremlin scripts using {@code gremlin-language}. As it
@@ -50,6 +54,8 @@ import java.util.Map;
public class GremlinLangScriptEngine extends AbstractScriptEngine implements GremlinScriptEngine {
private volatile GremlinScriptEngineFactory factory;
+ private final Function<Map<String, Object>, VariableResolver> variableResolverMaker;
+
/**
* Creates a new instance using no {@link Customizer}.
*/
@@ -58,6 +64,15 @@ public class GremlinLangScriptEngine extends AbstractScriptEngine implements Gre
}
public GremlinLangScriptEngine(final Customizer... customizers) {
+ final List<Customizer> listOfCustomizers = Arrays.asList(customizers);
+
+ // this ScriptEngine really only supports the VariableResolverCustomizer to configure the VariableResolver
+ // and can't configure it more than once. first one wins
+ final Optional<Customizer> opt = listOfCustomizers.stream().filter(c -> c instanceof VariableResolverCustomizer).findFirst();
+ variableResolverMaker = opt.isPresent() ?
+ ((VariableResolverCustomizer) opt.get()).getVariableResolverMaker() :
+ VariableResolver.DirectVariableResolver::new;
+
}
@Override
@@ -84,7 +99,7 @@ public class GremlinLangScriptEngine extends AbstractScriptEngine implements Gre
final Map<String, Object> m = context.getBindings(ScriptContext.ENGINE_SCOPE);
final GremlinAntlrToJava antlr = new GremlinAntlrToJava((GraphTraversalSource) o,
- new VariableResolver.DefaultVariableResolver(m));
+ variableResolverMaker.apply(m));
try {
return GremlinQueryParser.parse(script, antlr);
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/VariableResolverCustomizer.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/VariableResolverCustomizer.java
new file mode 100644
index 0000000000..1be1f3d448
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/VariableResolverCustomizer.java
@@ -0,0 +1,40 @@
+/*
+ * 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.jsr223;
+
+import org.apache.tinkerpop.gremlin.language.grammar.VariableResolver;
+
+import java.util.Map;
+import java.util.function.Function;
+
+/**
+ * Supplies a {@link VariableResolver} implementation to the {@link GremlinLangScriptEngine}. This {@link Customizer}
+ * is not relevant to any other {@link GremlinScriptEngine} implementation.
+ */
+public class VariableResolverCustomizer implements Customizer {
+ private final Function<Map<String,Object>, VariableResolver> variableResolverMaker;
+
+ public VariableResolverCustomizer(final Function<Map<String, Object>, VariableResolver> variableResolverMaker) {
+ this.variableResolverMaker = variableResolverMaker;
+ }
+
+ public Function<Map<String, Object>, VariableResolver> getVariableResolverMaker() {
+ return variableResolverMaker;
+ }
+}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/VariableResolverPlugin.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/VariableResolverPlugin.java
new file mode 100644
index 0000000000..587f9666a1
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/VariableResolverPlugin.java
@@ -0,0 +1,95 @@
+/*
+ * 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.jsr223;
+
+import org.apache.tinkerpop.gremlin.language.grammar.VariableResolver;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Function;
+
+/**
+ * A plugin that allows for the configuration of a {@link VariableResolver} implementation to be used by the
+ * {@link GremlinLangScriptEngine}. By default, it will use the {@link VariableResolver.DirectVariableResolver} which
+ * directly resolves variable name to a value from the binding in the script engine context. This is the most common
+ * usage relevant for most users and providers. Other options are reserved for more advanced use cases.
+ */
+public class VariableResolverPlugin extends AbstractGremlinPlugin {
+ private static final String NAME = "tinkerpop.variableResolver";
+
+ public static final Map<String, Function<Map<String, Object>, VariableResolver>> VARIABLE_RESOLVERS =
+ new HashMap<String, Function<Map<String, Object>, VariableResolver>>() {{
+ put(VariableResolver.DirectVariableResolver.class.getSimpleName(), VariableResolver.DirectVariableResolver::new);
+ put(VariableResolver.DefaultVariableResolver.class.getSimpleName(), VariableResolver.DefaultVariableResolver::new);
+ put(VariableResolver.NoVariableResolver.class.getSimpleName(), m -> VariableResolver.NoVariableResolver.instance());
+ put(VariableResolver.NullVariableResolver.class.getSimpleName(), m -> VariableResolver.NullVariableResolver.instance());
+ }};
+
+ private VariableResolverPlugin(final VariableResolverPlugin.Builder builder) {
+ super(NAME, new VariableResolverCustomizer(builder.variableResolverMaker));
+ }
+
+ /**
+ * Builds a set of static bindings.
+ */
+ public static VariableResolverPlugin.Builder build() {
+ return new VariableResolverPlugin.Builder();
+ }
+
+ public static final class Builder {
+
+ Function<Map<String,Object>, VariableResolver> variableResolverMaker = VariableResolver.DirectVariableResolver::new;
+
+ private Builder() {}
+
+ /**
+ * Sets the type of {@link VariableResolver} to use by specifying a simple class name associated with the
+ * inner classes in that interface or a fully qualified class name. The assumption is that implementations
+ * will allow a constructor that takes a {@code Map} which contains the bindings from the script engine context.
+ * Implementations are can then decide how to resolve variables in the script based on that {@code Map} or some
+ * other mechanism.
+ */
+ public VariableResolverPlugin.Builder resolver(final String resolverName) {
+ if (VARIABLE_RESOLVERS.containsKey(resolverName)) {
+ this.variableResolverMaker = VARIABLE_RESOLVERS.get(resolverName);
+ } else {
+ try {
+ // Assuming resolverName is a fully qualified class name if it's not in the simple name map
+ final Class<?> clazz = Class.forName(resolverName);
+ if (VariableResolver.class.isAssignableFrom(clazz)) {
+ this.variableResolverMaker = map -> {
+ try {
+ return (VariableResolver) clazz.getConstructor(Map.class).newInstance(map);
+ } catch (Exception e) {
+ throw new RuntimeException("Error instantiating VariableResolver", e);
+ }
+ };
+ }
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException("VariableResolver class not found: " + resolverName, e);
+ }
+ }
+ return this;
+ }
+
+ public VariableResolverPlugin create() {
+ return new VariableResolverPlugin(this);
+ }
+ }
+}
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 2cade8cac7..c7a255cd34 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}
*/
@@ -631,6 +631,10 @@ public class DefaultGremlinBaseVisitor<T> extends AbstractParseTreeVisitor<T> im
* {@inheritDoc}
*/
@Override public T visitTraversalMethod_option_Traversal(final GremlinParser.TraversalMethod_option_TraversalContext 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}
*/
@@ -854,11 +858,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 +1399,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/GenericLiteralVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GenericLiteralVisitor.java
index ced6c832d1..fb124ec910 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GenericLiteralVisitor.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GenericLiteralVisitor.java
@@ -658,4 +658,18 @@ public class GenericLiteralVisitor extends DefaultGremlinBaseVisitor<Object> {
else
return StringEscapeUtils.unescapeJava(stripQuotes(ctx.getText()));
}
+
+ @Override
+ public Object[] visitStringLiteralVarargs(final GremlinParser.StringLiteralVarargsContext ctx) {
+ if (ctx == null) {
+ return new Object[0];
+ }
+ return ctx.children
+ .stream()
+ .filter(Objects::nonNull)
+ .filter(p -> p instanceof GremlinParser.StringNullableArgumentContext)
+ .map(p -> (GremlinParser.StringNullableArgumentContext) p)
+ .map(antlr.argumentVisitor::visitStringNullableArgument)
+ .toArray(Object[]::new);
+ }
}
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 c4437d9f75..1d107e6a88 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
@@ -27,16 +27,18 @@ 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.GType;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.apache.tinkerpop.gremlin.structure.Column;
import org.apache.tinkerpop.gremlin.structure.Direction;
import org.apache.tinkerpop.gremlin.structure.T;
import org.apache.tinkerpop.gremlin.structure.VertexProperty.Cardinality;
+import java.util.Arrays;
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.
@@ -45,11 +47,11 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal>
/**
* This object is used to append the traversal methods.
*/
- private final GraphTraversal graphTraversal;
+ private final GraphTraversal.Admin graphTraversal;
public TraversalMethodVisitor(final GremlinAntlrToJava antlr, final GraphTraversal graphTraversal) {
super(antlr, graphTraversal);
- this.graphTraversal = graphTraversal;
+ this.graphTraversal = graphTraversal.asAdmin();
}
/**
@@ -97,7 +99,11 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal>
*/
@Override
public GraphTraversal visitTraversalMethod_mergeV_Map(final GremlinParser.TraversalMethod_mergeV_MapContext ctx) {
- return this.graphTraversal.mergeV(antlr.argumentVisitor.parseMap(ctx.genericLiteralMapNullableArgument()));
+ final Object literalOrVar = antlr.argumentVisitor.visitGenericLiteralMapNullableArgument(ctx.genericLiteralMapNullableArgument());
+ if (GValue.valueInstanceOf(literalOrVar, GType.MAP))
+ return graphTraversal.mergeV((GValue<Map<Object, Object>>) literalOrVar);
+ else
+ return graphTraversal.mergeV((Map) literalOrVar);
}
/**
@@ -129,7 +135,11 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal>
*/
@Override
public GraphTraversal visitTraversalMethod_mergeE_Map(final GremlinParser.TraversalMethod_mergeE_MapContext ctx) {
- return this.graphTraversal.mergeE(antlr.argumentVisitor.parseMap(ctx.genericLiteralMapNullableArgument()));
+ final Object literalOrVar = antlr.argumentVisitor.visitGenericLiteralMapNullableArgument(ctx.genericLiteralMapNullableArgument());
+ if (GValue.valueInstanceOf(literalOrVar, GType.MAP))
+ return graphTraversal.mergeE((GValue<Map<Object, Object>>) literalOrVar);
+ else
+ return graphTraversal.mergeE((Map) literalOrVar);
}
/**
@@ -440,7 +450,11 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal>
*/
@Override
public GraphTraversal visitTraversalMethod_combine_Object(final GremlinParser.TraversalMethod_combine_ObjectContext ctx) {
- return graphTraversal.combine(antlr.argumentVisitor.visitGenericLiteralArgument(ctx.genericLiteralArgument()));
+ final Object literalOrVar = antlr.argumentVisitor.visitGenericLiteralArgument(ctx.genericLiteralArgument());
+ if (literalOrVar instanceof GValue && ((GValue) literalOrVar).getType().isCollection())
+ return graphTraversal.combine((GValue<Object>) literalOrVar);
+ else
+ return graphTraversal.combine(literalOrVar);
}
/**
@@ -448,7 +462,12 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal>
*/
@Override
public GraphTraversal visitTraversalMethod_coin(final GremlinParser.TraversalMethod_coinContext ctx) {
- return graphTraversal.coin(((Number) antlr.argumentVisitor.visitFloatArgument(ctx.floatArgument())).doubleValue());
+ final Object literalOrVar = antlr.argumentVisitor.visitFloatArgument(ctx.floatArgument());
+ if (GValue.valueInstanceOfNumeric(literalOrVar))
+ return graphTraversal.coin((GValue<Double>) literalOrVar);
+ else
+ return graphTraversal.coin(((Number) literalOrVar).doubleValue());
+
}
/**
@@ -456,7 +475,13 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal>
*/
@Override
public GraphTraversal visitTraversalMethod_conjoin_String(final GremlinParser.TraversalMethod_conjoin_StringContext ctx) {
- return graphTraversal.conjoin(antlr.argumentVisitor.parseString(ctx.stringArgument()));
+ final Object literalOrVar = antlr.argumentVisitor.visitStringArgument(ctx.stringArgument());
+ if (literalOrVar instanceof String)
+ return graphTraversal.conjoin((String) literalOrVar);
+ else if (literalOrVar instanceof GValue && ((GValue) literalOrVar).getType() == GType.STRING)
+ return graphTraversal.conjoin((GValue<String>) literalOrVar);
+ else
+ throw new IllegalArgumentException("conjoin argument must be a string");
}
/**
@@ -514,7 +539,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);
}
/**
@@ -522,7 +551,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);
}
/**
@@ -619,8 +652,20 @@ 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 (GValue.valueInstanceOf(literalOrVar, GType.VERTEX))
+ return graphTraversal.from((GValue<Vertex>) literalOrVar);
+ else
+ return graphTraversal.from((Vertex) literalOrVar);
}
/**
@@ -715,10 +760,30 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal>
@Override
public GraphTraversal visitTraversalMethod_hasLabel_String_String(final GremlinParser.TraversalMethod_hasLabel_String_StringContext ctx) {
if (ctx.getChildCount() == 4) {
- return graphTraversal.hasLabel(antlr.argumentVisitor.parseString(ctx.stringNullableArgument()));
+ final Object literalOrVar = antlr.argumentVisitor.visitStringNullableArgument(ctx.stringNullableArgument());
+ if (GValue.valueInstanceOf(literalOrVar, GType.STRING))
+ return graphTraversal.hasLabel((GValue) literalOrVar);
+ else
+ return graphTraversal.hasLabel((String) literalOrVar);
} else {
- return graphTraversal.hasLabel(antlr.argumentVisitor.parseString(ctx.stringNullableArgument()),
- antlr.genericVisitor.parseStringVarargs(ctx.stringLiteralVarargs()));
+ Object literalOrVar = antlr.argumentVisitor.visitStringNullableArgument(ctx.stringNullableArgument());
+ Object[] literalOrVars = antlr.genericVisitor.visitStringLiteralVarargs(ctx.stringLiteralVarargs());
+
+ // if any are GValue then they all need to be GValue to call hasLabel
+ if (literalOrVar instanceof GValue || Arrays.stream(literalOrVars).anyMatch(lov -> lov instanceof GValue)) {
+ literalOrVar = GValue.of(literalOrVar);
+ literalOrVars = GValue.ensureGValues(literalOrVars);
+ }
+
+ // since we normalized above to gvalue or literal we can just test the first arg for gvalue-ness
+ if (GValue.valueInstanceOf(literalOrVar, GType.STRING)) {
+ final GValue[] gvalueLiteralOrVars = literalOrVars == null ? null : Arrays.stream(literalOrVars).map(o -> (GValue) o).toArray(GValue[]::new);
+ return graphTraversal.hasLabel((GValue) literalOrVar, (GValue[]) gvalueLiteralOrVars);
+ } else {
+ // convert object array to string array
+ final String[] stringLiteralOrVars = literalOrVars == null ? null : Arrays.stream(literalOrVars).map(o -> (String) o).toArray(String[]::new);
+ return graphTraversal.hasLabel((String) literalOrVar, stringLiteralOrVars);
+ }
}
}
@@ -778,9 +843,16 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal>
*/
@Override
public GraphTraversal visitTraversalMethod_has_String_String_Object(final GremlinParser.TraversalMethod_has_String_String_ObjectContext ctx) {
- return graphTraversal.has(antlr.argumentVisitor.parseString(ctx.stringNullableArgument(0)),
- antlr.argumentVisitor.parseString(ctx.stringNullableArgument(1)),
- antlr.argumentVisitor.visitGenericLiteralArgument(ctx.genericLiteralArgument()));
+ final Object literalOrVar = antlr.argumentVisitor.visitStringNullableArgument(ctx.stringNullableArgument(0));
+ if (GValue.valueInstanceOf(literalOrVar, GType.STRING)) {
+ return graphTraversal.has((GValue) literalOrVar,
+ antlr.argumentVisitor.parseString(ctx.stringNullableArgument(1)),
+ antlr.argumentVisitor.visitGenericLiteralArgument(ctx.genericLiteralArgument()));
+ } else {
+ return graphTraversal.has((String) literalOrVar,
+ antlr.argumentVisitor.parseString(ctx.stringNullableArgument(1)),
+ antlr.argumentVisitor.visitGenericLiteralArgument(ctx.genericLiteralArgument()));
+ }
}
/**
@@ -866,7 +938,11 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal>
*/
@Override
public GraphTraversal visitTraversalMethod_intersect_Object(final GremlinParser.TraversalMethod_intersect_ObjectContext ctx) {
- return graphTraversal.intersect(antlr.argumentVisitor.visitGenericLiteralArgument(ctx.genericLiteralArgument()));
+ final Object literalOrVar = antlr.argumentVisitor.visitGenericLiteralArgument(ctx.genericLiteralArgument());
+ if (literalOrVar instanceof GValue && ((GValue) literalOrVar).getType().isCollection())
+ return graphTraversal.intersect((GValue<Object>) literalOrVar);
+ else
+ return graphTraversal.intersect(literalOrVar);
}
/**
@@ -1066,7 +1142,11 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal>
*/
@Override
public GraphTraversal visitTraversalMethod_merge_Object(final GremlinParser.TraversalMethod_merge_ObjectContext ctx) {
- return graphTraversal.merge(antlr.argumentVisitor.visitGenericLiteralArgument(ctx.genericLiteralArgument()));
+ final Object literalOrVar = antlr.argumentVisitor.visitGenericLiteralArgument(ctx.genericLiteralArgument());
+ if (literalOrVar instanceof GValue && ((GValue) literalOrVar).getType().isCollection())
+ return graphTraversal.merge((GValue<Object>) literalOrVar);
+ else
+ return graphTraversal.merge(literalOrVar);
}
/**
@@ -1106,8 +1186,11 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal>
*/
@Override
public GraphTraversal visitTraversalMethod_option_Object_Traversal(final GremlinParser.TraversalMethod_option_Object_TraversalContext ctx) {
- return graphTraversal.option(antlr.argumentVisitor.visitGenericLiteralArgument(ctx.genericLiteralArgument()),
- antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal()));
+ final Object literalOrVar = antlr.argumentVisitor.visitGenericLiteralArgument(ctx.genericLiteralArgument());
+ if (literalOrVar instanceof GValue)
+ return graphTraversal.option((GValue) literalOrVar, antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal()));
+ else
+ return graphTraversal.option(literalOrVar, antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal()));
}
/**
@@ -1123,8 +1206,11 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal>
*/
@Override
public GraphTraversal visitTraversalMethod_option_Merge_Map(final GremlinParser.TraversalMethod_option_Merge_MapContext ctx) {
- return graphTraversal.option(TraversalEnumParser.parseTraversalEnumFromContext(Merge.class, ctx.traversalMerge()),
- (Map) antlr.argumentVisitor.visitGenericLiteralMapNullableArgument(ctx.genericLiteralMapNullableArgument()));
+ final Object literalOrVar = antlr.argumentVisitor.visitGenericLiteralMapNullableArgument(ctx.genericLiteralMapNullableArgument());
+ if (GValue.valueInstanceOf(literalOrVar, GType.MAP))
+ return graphTraversal.option(TraversalEnumParser.parseTraversalEnumFromContext(Merge.class, ctx.traversalMerge()), (GValue<Map>) literalOrVar);
+ else
+ return graphTraversal.option(TraversalEnumParser.parseTraversalEnumFromContext(Merge.class, ctx.traversalMerge()), (Map) literalOrVar);
}
/**
@@ -1263,7 +1349,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);
}
/**
@@ -1607,7 +1697,7 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal>
*/
@Override
public GraphTraversal visitTraversalMethod_to_Direction_String(final GremlinParser.TraversalMethod_to_Direction_StringContext ctx) {
- return graphTraversal.to(TraversalEnumParser.parseTraversalEnumFromContext(Direction.class, ctx.traversalDirection()),
+ return graphTraversal.to(TraversalEnumParser.parseTraversalDirectionFromContext(ctx.traversalDirection()),
antlr.genericVisitor.parseStringVarargs(ctx.stringLiteralVarargs()));
}
@@ -1615,8 +1705,20 @@ 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 (GValue.valueInstanceOf(literalOrVar, GType.VERTEX))
+ return graphTraversal.to((GValue<Vertex>) literalOrVar);
+ else
+ return graphTraversal.to((Vertex) literalOrVar);
}
/**
@@ -1755,22 +1857,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}
*/
@@ -1792,8 +1878,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 (GValue.valueInstanceOf(literalOrVar, GType.MAP))
+ return graphTraversal.call(antlr.argumentVisitor.parseString(ctx.stringArgument()), (GValue<Map>) literalOrVar);
+ else
+ return graphTraversal.call(antlr.argumentVisitor.parseString(ctx.stringArgument()), (Map) literalOrVar);
}
/**
@@ -1810,9 +1899,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 (GValue.valueInstanceOf(literalOrVar, 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 2227635f80..02fb654451 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
@@ -21,6 +21,8 @@ package org.apache.tinkerpop.gremlin.language.grammar;
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.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GType;
import java.util.Map;
@@ -119,7 +121,11 @@ public class TraversalSourceSpawnMethodVisitor extends DefaultGremlinBaseVisitor
*/
@Override
public GraphTraversal visitTraversalSourceSpawnMethod_mergeV_Map(final GremlinParser.TraversalSourceSpawnMethod_mergeV_MapContext ctx) {
- return this.traversalSource.mergeV(antlr.argumentVisitor.parseMap(ctx.genericLiteralMapNullableArgument()));
+ final Object literalOrVar = antlr.argumentVisitor.visitGenericLiteralMapNullableArgument(ctx.genericLiteralMapNullableArgument());
+ if (GValue.valueInstanceOf(literalOrVar, GType.MAP))
+ return this.traversalSource.mergeV((GValue) literalOrVar);
+ else
+ return this.traversalSource.mergeV((Map) literalOrVar);
}
/**
@@ -143,7 +149,11 @@ public class TraversalSourceSpawnMethodVisitor extends DefaultGremlinBaseVisitor
*/
@Override
public GraphTraversal visitTraversalSourceSpawnMethod_mergeE_Map(final GremlinParser.TraversalSourceSpawnMethod_mergeE_MapContext ctx) {
- return this.traversalSource.mergeE(antlr.argumentVisitor.parseMap(ctx.genericLiteralMapNullableArgument()));
+ final Object literalOrVar = antlr.argumentVisitor.visitGenericLiteralMapNullableArgument(ctx.genericLiteralMapNullableArgument());
+ if (GValue.valueInstanceOf(literalOrVar, GType.MAP))
+ return this.traversalSource.mergeE((GValue) literalOrVar);
+ else
+ return this.traversalSource.mergeE((Map) literalOrVar);
}
/**
@@ -167,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 (GValue.valueInstanceOf(literalOrVar, GType.MAP))
+ return this.traversalSource.call(antlr.argumentVisitor.parseString(ctx.stringArgument()), (GValue<Map>) literalOrVar);
+ else
+ return this.traversalSource.call(antlr.argumentVisitor.parseString(ctx.stringArgument()), (Map) literalOrVar);
}
/**
@@ -185,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 (GValue.valueInstanceOf(literalOrVar, GType.MAP))
+ return this.traversalSource.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/grammar/VariableResolver.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/VariableResolver.java
index a97bd4b646..e017808faf 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/VariableResolver.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/VariableResolver.java
@@ -18,24 +18,25 @@
*/
package org.apache.tinkerpop.gremlin.language.grammar;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
import java.util.Map;
import java.util.function.BiFunction;
/**
* Resolves parameters in Gremlin to objects.
*/
-public interface VariableResolver extends BiFunction<String, GremlinParser.VariableContext, Object> {
+public interface VariableResolver<T> extends BiFunction<String, GremlinParser.VariableContext, T> {
/**
* This function resolves a variable name and the given parsers context to an object.
*/
@Override
- Object apply(final String varName, final GremlinParser.VariableContext variableContext);
+ T apply(final String varName, final GremlinParser.VariableContext variableContext);
/**
* This {@link VariableResolver} implementation throws exceptions for all variable names.
*/
- class NoVariableResolver implements VariableResolver {
+ class NoVariableResolver implements VariableResolver<Object> {
private static NoVariableResolver instance = new NoVariableResolver();
public static VariableResolver instance() {
@@ -48,12 +49,35 @@ public interface VariableResolver extends BiFunction<String, GremlinParser.Varia
}
}
+ /**
+ * Allows for a provided variable set in the form of a {@code Map}, where the keys are variable names and the
+ * values are the parameter values to be injected into the traversal in their place. The value is provided to a
+ * {@link GValue} object along with the variable name for further reference.
+ */
+ class DefaultVariableResolver implements VariableResolver<GValue<?>> {
+
+ private final Map<String, Object> variables;
+
+ public DefaultVariableResolver(final Map<String, Object> variables) {
+ this.variables = variables;
+ }
+
+ @Override
+ public GValue<?> apply(final String s, final GremlinParser.VariableContext variableContext) {
+ if (!variables.containsKey(s)) {
+ throw new VariableResolverException(String.format("No variable found for %s", s));
+ }
+
+ return GValue.of(s, variables.get(s));
+ }
+ }
+
/**
* This {@link VariableResolver} simply provides a {@code null} value for all variable names. It's typical use
* is for when you really don't intend to execute the traversal and just want to get an instance of one when
* bindings are being used as with {@link NoOpTerminalVisitor}.
*/
- class NullVariableResolver implements VariableResolver {
+ class NullVariableResolver implements VariableResolver<Object> {
private static NullVariableResolver instance = new NullVariableResolver();
public static VariableResolver instance() {
@@ -70,11 +94,11 @@ public interface VariableResolver extends BiFunction<String, GremlinParser.Varia
* Allows for a provided variable set in the form of a {@code Map}, where the keys are variable names and the
* values are the parameter values to be injected into the traversal in their place.
*/
- class DefaultVariableResolver implements VariableResolver {
+ class DirectVariableResolver implements VariableResolver<Object> {
private final Map<String, Object> variables;
- public DefaultVariableResolver(final Map<String, Object> variables) {
+ public DirectVariableResolver(final Map<String, Object> variables) {
this.variables = variables;
}
@@ -87,4 +111,5 @@ public interface VariableResolver extends BiFunction<String, GremlinParser.Varia
return variables.get(s);
}
}
+
}
\ No newline at end of file
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 21c4d20ea4..60ce2f8e30 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
@@ -739,10 +739,36 @@ public class DotNetTranslateVisitor extends AbstractTranslateVisitor {
sb.append(")");
return null;
} else {
- return super.visitTraversalMethod_hasLabel_String_String(ctx);
+ final String step = ctx.getChild(0).getText();
+ sb.append(convertToPascalCase(step));
+ sb.append("(");
+ tryAppendCastToString(ctx.stringNullableArgument());
+ visit(ctx.stringNullableArgument());
+
+ // more arguments to come
+ if (!ctx.stringLiteralVarargs().isEmpty()) sb.append(", ");
+ visit(ctx.stringLiteralVarargs());
+
+ sb.append(")");
+ return null;
}
}
+ @Override
+ public Void visitStringLiteralVarargs(final GremlinParser.StringLiteralVarargsContext ctx) {
+ for (int ix = 0; ix < ctx.getChildCount(); ix++) {
+ final ParseTree pt = ctx.getChild(ix);
+ if (pt instanceof GremlinParser.StringNullableArgumentContext) {
+ GremlinParser.StringNullableArgumentContext sna = (GremlinParser.StringNullableArgumentContext) pt;
+ tryAppendCastToString(sna);
+ visit(sna);
+ } else {
+ visit(pt);
+ }
+ };
+ return null;
+ }
+
@Override
public Void visitTraversalMethod_index(final GremlinParser.TraversalMethod_indexContext ctx) {
return handleGenerics(ctx);
@@ -870,9 +896,24 @@ public class DotNetTranslateVisitor extends AbstractTranslateVisitor {
return null;
}
+ @Override
+ public Void visitTraversalMethod_option_Object_Traversal(final GremlinParser.TraversalMethod_option_Object_TraversalContext ctx) {
+ if (ctx.genericLiteralArgument().genericLiteral() != null && 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
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.traversalMerge());
@@ -923,6 +964,17 @@ public class DotNetTranslateVisitor extends AbstractTranslateVisitor {
}
}
+ @Override
+ public Void visitTraversalMethod_conjoin_String(final GremlinParser.TraversalMethod_conjoin_StringContext ctx) {
+ final String step = ctx.getChild(0).getText();
+ sb.append(convertToPascalCase(step));
+ sb.append("(");
+ tryAppendCastToString(ctx.stringArgument());
+ visit(ctx.stringArgument());
+ sb.append(")");
+ return null;
+ }
+
@Override
public Void visitTraversalMethod_propertyMap(final GremlinParser.TraversalMethod_propertyMapContext ctx) {
return handleGenerics(ctx);
@@ -1138,6 +1190,12 @@ public class DotNetTranslateVisitor extends AbstractTranslateVisitor {
}
}
+ private void tryAppendCastToString(final GremlinParser.StringArgumentContext ctx) {
+ if (ctx.variable() != null || ctx.stringLiteral() != null) {
+ sb.append("(string) ");
+ }
+ }
+
private void tryAppendCastToString(final GremlinParser.StringNullableArgumentContext ctx) {
if (ctx.variable() != null || ctx.stringNullableLiteral().NullLiteral() != null) {
sb.append("(string) ");
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/GroovyTranslateVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/GroovyTranslateVisitor.java
index 3c87b6249a..20a6b6434e 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/GroovyTranslateVisitor.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/GroovyTranslateVisitor.java
@@ -186,8 +186,35 @@ public class GroovyTranslateVisitor extends TranslateVisitor {
return handleInject(ctx);
}
- /*
- * very special handling for inject with second `null` argument like g.inject(1, null)
+ @Override
+ public Void visitTraversalMethod_hasLabel_String_String(final GremlinParser.TraversalMethod_hasLabel_String_StringContext ctx) {
+ // special handling for resolving ambiguous invocations of the hasLabel() step. coerces to the string form
+ if (ctx.getChildCount() > 4 && ctx.getChild(2).getText().equals("null")) {
+ final GremlinParser.StringLiteralVarargsContext varArgs = (GremlinParser.StringLiteralVarargsContext) ctx.getChild(4);
+ sb.append(ctx.getChild(0).getText());
+ sb.append("((String) null, ");
+
+ for (int i = 0; i < varArgs.getChildCount(); i += 2) {
+ if (varArgs.getChild(i).getText().equals("null")) {
+ sb.append("(String) null");
+ } else {
+ visit(varArgs.getChild(i));
+ }
+
+ if (i < varArgs.getChildCount() - 1) {
+ sb.append(", ");
+ }
+ }
+
+ sb.append(")");
+ return null;
+ }
+
+ return visitChildren(ctx);
+ }
+
+ /**
+ * Special handling for inject with second `null` argument like g.inject(1, null)
* inject() ends up being ambiguous with groovy's jdk extension of inject(Object initialValue, Closure closure)
*/
private Void handleInject(final ParserRuleContext ctx) {
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 2712262678..beb6040091 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
@@ -903,17 +903,17 @@ public class TranslateVisitor extends AbstractParseTreeVisitor<Void> implements
}
@Override
- public Void visitTraversalMethod_option_Merge_Traversal(final GremlinParser.TraversalMethod_option_Merge_TraversalContext ctx) {
+ public Void visitTraversalMethod_option_Object_Traversal(final GremlinParser.TraversalMethod_option_Object_TraversalContext ctx) {
return visitChildren(ctx);
}
@Override
- public Void visitTraversalMethod_option_Object_Traversal(final GremlinParser.TraversalMethod_option_Object_TraversalContext ctx) {
+ public Void visitTraversalMethod_option_Traversal(final GremlinParser.TraversalMethod_option_TraversalContext ctx) {
return visitChildren(ctx);
}
@Override
- public Void visitTraversalMethod_option_Traversal(final GremlinParser.TraversalMethod_option_TraversalContext ctx) {
+ public Void visitTraversalMethod_option_Merge_Traversal(final GremlinParser.TraversalMethod_option_Merge_TraversalContext ctx) {
return visitChildren(ctx);
}
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 917a13891d..a878bbb839 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
@@ -18,13 +18,16 @@
*/
package org.apache.tinkerpop.gremlin.process.traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
import org.apache.tinkerpop.gremlin.process.traversal.util.AndP;
import org.apache.tinkerpop.gremlin.process.traversal.util.OrP;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
+import java.util.List;
import java.util.function.Predicate;
+import java.util.stream.Collectors;
/**
* Predefined {@code Predicate} values that can be used to define filters to {@code has()} and {@code where()}.
@@ -74,7 +77,16 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
@Override
public boolean test(final V testValue) {
- return this.biPredicate.test(testValue, this.value);
+ if (this.value instanceof GValue) {
+ return this.biPredicate.test(testValue, ((GValue<V>) this.value).get());
+ } else {
+ // this might be a bunch of GValue that need to be resolved. zomg
+ if (this.value instanceof List) {
+ return this.biPredicate.test(testValue, (V) ((List) this.value).stream().map(GValue::valueOf).collect(Collectors.toList()));
+ } else {
+ return this.biPredicate.test(testValue, this.value);
+ }
+ }
}
@Override
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/SackFunctions.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/SackFunctions.java
index 4752bf0b32..3985efe699 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/SackFunctions.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/SackFunctions.java
@@ -19,6 +19,7 @@
package org.apache.tinkerpop.gremlin.process.traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
import org.apache.tinkerpop.gremlin.process.traversal.traverser.util.TraverserSet;
import java.util.function.Consumer;
@@ -42,10 +43,10 @@ public final class SackFunctions {
public void accept(final TraverserSet<Object> traverserSet) {
Number total = 0.0;
for (final Traverser.Admin<Object> traverser : traverserSet) {
- total = add(total, mul(traverser.sack(), traverser.bulk()));
+ total = add(total, mul(GValue.numberOf(traverser.sack()), traverser.bulk()));
}
for (final Traverser.Admin<Object> traverser : traverserSet) {
- traverser.sack(div(mul(traverser.sack(), traverser.bulk()), total));
+ traverser.sack(div(mul(GValue.numberOf(traverser.sack()), traverser.bulk()), total));
}
}
}
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 9d5b500376..ab5af2445b 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
@@ -25,6 +25,7 @@ import org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.PageRank
import org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.PeerPressureVertexProgramStep;
import org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.ProgramVertexProgramStep;
import org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.ShortestPathVertexProgramStep;
+import org.apache.tinkerpop.gremlin.process.traversal.Contains;
import org.apache.tinkerpop.gremlin.process.traversal.DT;
import org.apache.tinkerpop.gremlin.process.traversal.Failure;
import org.apache.tinkerpop.gremlin.process.traversal.Merge;
@@ -47,6 +48,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.lambda.TrueTraversal;
import org.apache.tinkerpop.gremlin.process.traversal.step.ByModulating;
import org.apache.tinkerpop.gremlin.process.traversal.step.Configuring;
import org.apache.tinkerpop.gremlin.process.traversal.step.FromToModulating;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
import org.apache.tinkerpop.gremlin.process.traversal.step.Mutating;
import org.apache.tinkerpop.gremlin.process.traversal.step.ReadWriting;
import org.apache.tinkerpop.gremlin.process.traversal.step.TimesModulating;
@@ -203,8 +205,10 @@ import org.apache.tinkerpop.gremlin.structure.PropertyType;
import org.apache.tinkerpop.gremlin.structure.T;
import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+import org.apache.tinkerpop.gremlin.util.CollectionUtil;
import org.apache.tinkerpop.gremlin.util.function.ConstantSupplier;
+import java.lang.reflect.Array;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.Arrays;
@@ -230,6 +234,11 @@ import static org.apache.tinkerpop.gremlin.structure.VertexProperty.Cardinality.
*/
public interface GraphTraversal<S, E> extends Traversal<S, E> {
+ /**
+ * Exposes administrative methods that are either internal to TinkerPop or for users with advanced needs. This
+ * separation helps keep the Gremlin API more concise. Any {@code GraphTraversal} can get an instance of its
+ * administrative form by way of {@link GraphTraversal#asAdmin()}.
+ */
public interface Admin<S, E> extends Traversal.Admin<S, E>, GraphTraversal<S, E> {
@Override
@@ -356,6 +365,18 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
return this.asAdmin().addStep(new ConstantStep<E, E2>(this.asAdmin(), e));
}
+ /**
+ * Map any object to a fixed <code>E</code> value. For internal use for parameterization features.
+ *
+ * @return the traversal with an appended {@link ConstantStep}.
+ * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#constant-step" target="_blank">Reference Documentation - Constant Step</a>
+ * @since 4.0.0
+ */
+ public default <E2> GraphTraversal<S, E2> constant(final GValue<E2> e) {
+ this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.constant, e);
+ return this.asAdmin().addStep(new ConstantStep<E, E2>(this.asAdmin(), e));
+ }
+
/**
* A {@code V} step is usually used to start a traversal but it may also be used mid-traversal.
*
@@ -400,6 +421,22 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), Vertex.class, direction, edgeLabels));
}
+ /**
+ * Map the {@link Vertex} to its adjacent vertices given a direction and edge labels. The arguments for the
+ * labels must be either a {@code String} or a {@link GValue<String>}. For internal use for parameterization.
+ *
+ * @param direction the direction to traverse from the current vertex
+ * @param edgeLabels the edge labels to traverse
+ * @return the traversal with an appended {@link VertexStep}.
+ * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#vertex-steps" target="_blank">Reference Documentation - Vertex Step</a>
+ * @since 4.0.0
+ */
+ public default GraphTraversal<S, Vertex> to(final Direction direction, final GValue<String> edgeLabel, final GValue<String>... edgeLabels) {
+ this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.to, direction, edgeLabel, edgeLabels);
+ final GValue<String>[] labels = CollectionUtil.addFirst(edgeLabels, edgeLabel, GValue.class);
+ return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), Vertex.class, direction, labels));
+ }
+
/**
* Map the {@link Vertex} to its outgoing adjacent vertices given the edge labels.
*
@@ -413,6 +450,21 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), Vertex.class, Direction.OUT, edgeLabels));
}
+ /**
+ * Map the {@link Vertex} to its outgoing adjacent vertices given the edge labels. The arguments for the
+ * labels must be either a {@code String} or a {@link GValue<String>}. For internal use for parameterization.
+ *
+ * @param edgeLabels the edge labels to traverse
+ * @return the traversal with an appended {@link VertexStep}.
+ * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#vertex-steps" target="_blank">Reference Documentation - Vertex Step</a>
+ * @since 3.7.3
+ */
+ public default GraphTraversal<S, Vertex> out(final GValue<String> label, final GValue<String>... edgeLabels) {
+ final GValue<String>[] labels = CollectionUtil.addFirst(edgeLabels, label, GValue.class);
+ this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.out, label, edgeLabels);
+ return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), Vertex.class, Direction.OUT, labels));
+ }
+
/**
* Map the {@link Vertex} to its incoming adjacent vertices given the edge labels.
*
@@ -426,6 +478,21 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), Vertex.class, Direction.IN, edgeLabels));
}
+ /**
+ * Map the {@link Vertex} to its incoming adjacent vertices given the edge labels. The arguments for the
+ * labels must be either a {@code String} or a {@link GValue<String>}. For internal use for parameterization.
+ *
+ * @param edgeLabels the edge labels to traverse
+ * @return the traversal with an appended {@link VertexStep}.
+ * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#vertex-steps" target="_blank">Reference Documentation - Vertex Step</a>
+ * @since 4.0.0
+ */
+ public default GraphTraversal<S, Vertex> in(final GValue<String> label, final GValue<String>... edgeLabels) {
+ final GValue<String>[] labels = CollectionUtil.addFirst(edgeLabels, label, GValue.class);
+ this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.in, label, edgeLabels);
+ return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), Vertex.class, Direction.IN, labels));
+ }
+
/**
* Map the {@link Vertex} to its adjacent vertices given the edge labels.
*
@@ -439,6 +506,21 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), Vertex.class, Direction.BOTH, edgeLabels));
}
+ /**
+ * Map the {@link Vertex} to its adjacent vertices given the edge labels. The arguments for the labels must be
+ * either a {@code String} or a {@link GValue<String>}. For internal use for parameterization.
+ *
+ * @param edgeLabels the edge labels to traverse
+ * @return the traversal with an appended {@link VertexStep}.
+ * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#vertex-steps" target="_blank">Reference Documentation - Vertex Step</a>
+ * @since 4.0.0
+ */
+ public default GraphTraversal<S, Vertex> both(final GValue<String> label, final GValue<String>... edgeLabels) {
+ final GValue<String>[] labels = CollectionUtil.addFirst(edgeLabels, label, GValue.class);
+ this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.both, label, edgeLabels);
+ return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), Vertex.class, Direction.BOTH, labels));
+ }
+
/**
* Map the {@link Vertex} to its incident edges given the direction and edge labels.
*
@@ -453,6 +535,23 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), Edge.class, direction, edgeLabels));
}
+
+ /**
+ * Map the {@link Vertex} to its incident edges given the direction and edge labels. The arguments for the
+ * labels must be either a {@code String} or a {@link GValue<String>}. For internal use for parameterization.
+ *
+ * @param direction the direction to traverse from the current vertex
+ * @param edgeLabels the edge labels to traverse
+ * @return the traversal with an appended {@link VertexStep}.
+ * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#vertex-steps" target="_blank">Reference Documentation - Vertex Step</a>
+ * @since 4.0.0
+ */
+ public default GraphTraversal<S, Edge> toE(final Direction direction, final GValue<String> edgeLabel, final GValue<String>... edgeLabels) {
+ this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.toE, direction, edgeLabel, edgeLabels);
+ final GValue<String>[] labels = CollectionUtil.addFirst(edgeLabels, edgeLabel, GValue.class);
+ return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), Edge.class, direction, labels));
+ }
+
/**
* Map the {@link Vertex} to its outgoing incident edges given the edge labels.
*
@@ -466,6 +565,21 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), Edge.class, Direction.OUT, edgeLabels));
}
+ /**
+ * Map the {@link Vertex} to its outgoing incident edges given the edge labels. The arguments for the labels
+ * must be either a {@code String} or a {@link GValue<String>}. For internal use for parameterization.
+ *
+ * @param edgeLabels the edge labels to traverse
+ * @return the traversal with an appended {@link VertexStep}.
+ * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#vertex-steps" target="_blank">Reference Documentation - Vertex Step</a>
+ * @since 4.0.0
+ */
+ public default GraphTraversal<S, Edge> outE(final GValue<String> label, final GValue<String>... edgeLabels) {
+ final GValue<String>[] labels = CollectionUtil.addFirst(edgeLabels, label, GValue.class);
+ this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.outE, label, edgeLabels);
+ return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), Edge.class, Direction.OUT, labels));
+ }
+
/**
* Map the {@link Vertex} to its incoming incident edges given the edge labels.
*
@@ -479,6 +593,22 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), Edge.class, Direction.IN, edgeLabels));
}
+ /**
+ * Map the {@link Vertex} to its incoming incident edges given the edge labels. The arguments for the labels
+ * must be either a {@code String} or a {@link GValue<String>}. For internal use for parameterization.
+ *
+ * @param edgeLabels the edge labels to traverse
+ * @return the traversal with an appended {@link VertexStep}.
+ * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#vertex-steps" target="_blank">Reference Documentation - Vertex Step</a>
+ * @since 4.0.0
+ */
+ public default GraphTraversal<S, Edge> inE(final GValue<String> label, final GValue<String>... edgeLabels) {
+ final GValue<String>[] labels = CollectionUtil.addFirst(edgeLabels, label, GValue.class);
+ this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.inE, label, edgeLabels);
+ return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), Edge.class, Direction.IN, labels));
+ }
+
+
/**
* Map the {@link Vertex} to its incident edges given the edge labels.
*
@@ -492,6 +622,21 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), Edge.class, Direction.BOTH, edgeLabels));
}
+ /**
+ * Map the {@link Vertex} to its incident edges given the edge labels. The arguments for the labels must be
+ * either a {@code String} or a {@link GValue<String>}. For internal use for parameterization.
+ *
+ * @param edgeLabels the edge labels to traverse
+ * @return the traversal with an appended {@link VertexStep}.
+ * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#vertex-steps" target="_blank">Reference Documentation - Vertex Step</a>
+ * @since 4.0.0
+ */
+ public default GraphTraversal<S, Edge> bothE(final GValue<String> label, final GValue<String>... edgeLabels) {
+ final GValue<String>[] labels = CollectionUtil.addFirst(edgeLabels, label, GValue.class);
+ this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.bothE, label, edgeLabels);
+ return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), Edge.class, Direction.BOTH, labels));
+ }
+
/**
* Map the {@link Edge} to its incident vertices given the direction.
*
@@ -1121,6 +1266,20 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
return this.asAdmin().addStep(new AddVertexStep<>(this.asAdmin(), vertexLabelTraversal.asAdmin()));
}
+ /**
+ * Adds a {@link Vertex}.
+ *
+ * @param vertexLabel the label of the {@link Vertex} to add
+ * @return the traversal with the {@link AddVertexStep} added
+ * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#addvertex-step" target="_blank">Reference Documentation - AddVertex Step</a>
+ * @since 4.0.0
+ */
+ public default GraphTraversal<S, Vertex> addV(final GValue<String> vertexLabel) {
+ if (null == vertexLabel || null == vertexLabel.get()) throw new IllegalArgumentException("vertexLabel cannot be null");
+ this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.addV, vertexLabel);
+ return this.asAdmin().addStep(new AddVertexStep<>(this.asAdmin(), vertexLabel));
+ }
+
/**
* Adds a {@link Vertex} with a default vertex label.
*
@@ -1179,6 +1338,21 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
return this.asAdmin().addStep(step);
}
+ /**
+ * Performs 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 key/value pairs where the keys
+ * may be {@code String} property values or a value of {@link T}. If a match is not 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 4.0.0
+ */
+ public default GraphTraversal<S, Vertex> mergeV(final GValue<Map<Object, Object>> searchCreate) {
+ this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.mergeV, searchCreate);
+ final MergeVertexStep<S> step = new MergeVertexStep(this.asAdmin(), false, null == searchCreate ? GValue.ofMap(null) : searchCreate);
+ return this.asAdmin().addStep(step);
+ }
+
/**
* Spawns a {@link GraphTraversal} by doing a merge (i.e. upsert) style operation for an {@link Edge} using an
* incoming {@code Map} as an argument.
@@ -1220,6 +1394,20 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
return this.asAdmin().addStep(step);
}
+ /**
+ * Spawns a {@link GraphTraversal} by doing a merge (i.e. upsert) style operation for an {@link Edge} using a
+ * {@code Map} as an argument.
+ *
+ * @param searchCreate This {@code Map} can have a key of {@link T} {@link Direction} or a {@code String}.
+ * @since 4.0.0
+ */
+ public default GraphTraversal<S, Edge> mergeE(final GValue<Map<Object, Object>> searchCreate) {
+ // get a construction time exception if the Map is bad
+ this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.mergeE, searchCreate);
+ final MergeEdgeStep<S> step = new MergeEdgeStep(this.asAdmin(), false, null == searchCreate ? GValue.ofMap(null) : searchCreate);
+ return this.asAdmin().addStep(step);
+ }
+
/**
* Adds an {@link Edge} with the specified edge label.
*
@@ -1246,21 +1434,35 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
}
/**
- * Provide {@code to()}-modulation to respective steps.
+ * Adds an {@link Edge} with the specified edge label.
*
- * @param toStepLabel the step label to modulate to.
- * @return the traversal with the modified {@link FromToModulating} step.
- * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#to-step" target="_blank">Reference Documentation - To Step</a>
+ * @param edgeLabel the label of the newly added edge
+ * @return the traversal with the {@link AddEdgeStep} added
+ * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#addedge-step" target="_blank">Reference Documentation - AddEdge Step</a>
+ * @since 4.0.0
+ */
+ public default GraphTraversal<S, Edge> addE(final GValue<String> edgeLabel) {
+ this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.addE, edgeLabel);
+ return this.asAdmin().addStep(new AddEdgeStep<>(this.asAdmin(), edgeLabel));
+ }
+
+ /**
+ * 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 traversal 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 3.1.0-incubating
*/
- public default GraphTraversal<S, E> to(final String toStepLabel) {
+ public default GraphTraversal<S, E> from(final Traversal<?, Vertex> fromVertex) {
final Step<?,?> prev = this.asAdmin().getEndStep();
if (!(prev instanceof FromToModulating))
throw new IllegalArgumentException(String.format(
- "The to() step cannot follow %s", prev.getClass().getSimpleName()));
+ "The from() step cannot follow %s", prev.getClass().getSimpleName()));
- this.asAdmin().getGremlinLang().addStep(Symbols.to, toStepLabel);
- ((FromToModulating) prev).addTo(toStepLabel);
+ this.asAdmin().getGremlinLang().addStep(Symbols.from, fromVertex);
+ ((FromToModulating) prev).addFrom(fromVertex.asAdmin());
return this;
}
@@ -1285,21 +1487,21 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
/**
* 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}.
+ * outgoing vertex of the newly added {@link Edge}.
*
- * @param toVertex the traversal for selecting the incoming vertex
+ * @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 3.1.0-incubating
+ * @since 4.0.0
*/
- public default GraphTraversal<S, E> to(final Traversal<?, Vertex> toVertex) {
+ 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 to() step cannot follow %s", prev.getClass().getSimpleName()));
+ "The from() step cannot follow %s", prev.getClass().getSimpleName()));
- this.asAdmin().getGremlinLang().addStep(Symbols.to, toVertex);
- ((FromToModulating) prev).addTo(toVertex.asAdmin());
+ this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.from, fromVertex);
+ ((FromToModulating) prev).addFrom(__.constant(fromVertex).asAdmin());
return this;
}
@@ -1307,19 +1509,38 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
* 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 traversal for selecting the outgoing vertex
+ * @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 3.1.0-incubating
+ * @since 3.3.0
*/
- public default GraphTraversal<S, E> from(final Traversal<?, Vertex> fromVertex) {
+ public default GraphTraversal<S, E> from(final 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().getGremlinLang().addStep(Symbols.from, fromVertex);
- ((FromToModulating) prev).addFrom(fromVertex.asAdmin());
+ ((FromToModulating) prev).addFrom(__.constant(fromVertex).asAdmin());
+ return this;
+ }
+
+ /**
+ * Provide {@code to()}-modulation to respective steps.
+ *
+ * @param toStepLabel the step label to modulate to.
+ * @return the traversal with the modified {@link FromToModulating} step.
+ * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#to-step" target="_blank">Reference Documentation - To Step</a>
+ * @since 3.1.0-incubating
+ */
+ public default GraphTraversal<S, E> to(final String toStepLabel) {
+ 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().getGremlinLang().addStep(Symbols.to, toStepLabel);
+ ((FromToModulating) prev).addTo(toStepLabel);
return this;
}
@@ -1330,36 +1551,56 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
* @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 3.3.0
+ * @since 4.0.0
*/
- public default GraphTraversal<S, E> to(final Vertex toVertex) {
+ 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().getGremlinLang().addStep(Symbols.to, toVertex);
+ this.asAdmin().getGremlinLang().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}.
+ * incoming vertex of the newly added {@link Edge}.
*
- * @param fromVertex the vertex for selecting the outgoing vertex
+ * @param toVertex the traversal 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 3.1.0-incubating
+ */
+ public default GraphTraversal<S, E> to(final Traversal<?, 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().getGremlinLang().addStep(Symbols.to, toVertex);
+ ((FromToModulating) prev).addTo(toVertex.asAdmin());
+ return this;
+ }
+
+ /**
+ * 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 3.3.0
*/
- public default GraphTraversal<S, E> from(final Vertex fromVertex) {
+ public default GraphTraversal<S, E> to(final Vertex toVertex) {
final Step<?,?> prev = this.asAdmin().getEndStep();
if (!(prev instanceof FromToModulating))
throw new IllegalArgumentException(String.format(
- "The from() step cannot follow %s", prev.getClass().getSimpleName()));
+ "The to() step cannot follow %s", prev.getClass().getSimpleName()));
- this.asAdmin().getGremlinLang().addStep(Symbols.from, fromVertex);
- ((FromToModulating) prev).addFrom(__.constant(fromVertex).asAdmin());
+ this.asAdmin().getGremlinLang().addStep(Symbols.to, toVertex);
+ ((FromToModulating) prev).addTo(__.constant(toVertex).asAdmin());
return this;
}
@@ -1416,6 +1657,21 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
return this.asAdmin().addStep(call);
}
+ /**
+ * 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().getGremlinLang().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 dynamic parameters produced by the specified child traversal.
*
@@ -1451,6 +1707,25 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
return this.asAdmin().addStep(step);
}
+ /**
+ * 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().getGremlinLang().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);
+ }
+
/**
* Concatenate values of an arbitrary number of string traversals to the incoming traverser.
*
@@ -1900,6 +2175,18 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
return this.asAdmin().addStep(new DifferenceStep<>(this.asAdmin(), values));
}
+ /**
+ * 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 4.0.0
+ */
+ public default GraphTraversal<S, Set<?>> difference(final GValue<Object> values) {
+ this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.difference, values);
+ return this.asAdmin().addStep(new DifferenceStep<>(this.asAdmin(), values));
+ }
+
/**
* Calculates the disjunction between the list traverser and list argument.
*
@@ -1912,6 +2199,18 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
return this.asAdmin().addStep(new DisjunctStep<>(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 4.0.0
+ */
+ public default GraphTraversal<S, Set<?>> disjunct(final GValue<Object> values) {
+ this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.disjunct, values);
+ return this.asAdmin().addStep(new DisjunctStep<>(this.asAdmin(), values));
+ }
+
/**
* Calculates the intersection between the list traverser and list argument.
*
@@ -1924,6 +2223,18 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
return this.asAdmin().addStep(new IntersectStep<>(this.asAdmin(), values));
}
+ /**
+ * Calculates the intersection between the list traverser and list argument.
+ *
+ * @return the traversal with an appended {@link IntersectStep}.
+ * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#intersect-step" target="_blank">Reference Documentation - Intersect Step</a>
+ * @since 4.0.0
+ */
+ public default GraphTraversal<S, Set<?>> intersect(final GValue<Object> values) {
+ this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.intersect, values);
+ return this.asAdmin().addStep(new IntersectStep<>(this.asAdmin(), values));
+ }
+
/**
* Joins together the elements of the incoming list traverser together with the provided delimiter.
*
@@ -1936,6 +2247,18 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
return this.asAdmin().addStep(new ConjoinStep<>(this.asAdmin(), delimiter));
}
+ /**
+ * Joins together the elements of the incoming list traverser together with the provided delimiter.
+ *
+ * @return the traversal with an appended {@link ConjoinStep}.
+ * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#conjoin-step" target="_blank">Reference Documentation - Conjoin Step</a>
+ * @since 4.0.0
+ */
+ public default GraphTraversal<S, String> conjoin(final GValue<String> delimiter) {
+ this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.conjoin, delimiter);
+ return this.asAdmin().addStep(new ConjoinStep<>(this.asAdmin(), delimiter));
+ }
+
/**
* Merges the list traverser and list argument. Also known as union.
*
@@ -1948,6 +2271,18 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
return this.asAdmin().addStep(new MergeStep<>(this.asAdmin(), values));
}
+ /**
+ * Merges the list traverser and list argument. Also known as union.
+ *
+ * @return the traversal with an appended {@link MergeStep}.
+ * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#merge-step" target="_blank">Reference Documentation - Merge Step</a>
+ * @since 4.0.0
+ */
+ public default <E2> GraphTraversal<S, E2> merge(final GValue<Object> values) {
+ this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.merge, values);
+ return this.asAdmin().addStep(new MergeStep<>(this.asAdmin(), values));
+ }
+
/**
* Combines the list traverser and list argument. Also known as concatenation or append.
*
@@ -1960,6 +2295,18 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
return this.asAdmin().addStep(new CombineStep<>(this.asAdmin(), values));
}
+ /**
+ * Combines the list traverser and list argument. Also known as concatenation or append.
+ *
+ * @return the traversal with an appended {@link CombineStep}.
+ * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#combine-step" target="_blank">Reference Documentation - Combine Step</a>
+ * @since 4.0.0
+ */
+ public default GraphTraversal<S, List<?>> combine(final GValue<Object> values) {
+ this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.combine, values);
+ return this.asAdmin().addStep(new CombineStep<>(this.asAdmin(), values));
+ }
+
/**
* Calculates the cartesian product between the list traverser and list argument.
*
@@ -1972,6 +2319,18 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
return this.asAdmin().addStep(new ProductStep<>(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 4.0.0
+ */
+ public default GraphTraversal<S, List<List<?>>> product(final GValue<Object> values) {
+ this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.product, values);
+ return this.asAdmin().addStep(new ProductStep<>(this.asAdmin(), values));
+ }
+
///////////////////// FILTER STEPS /////////////////////
/**
@@ -2310,6 +2669,22 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
return this.asAdmin().addStep(new TraversalFilterStep(this.asAdmin(), __.values(propertyKey)));
}
+ /**
+ * Filters vertices, edges and vertex properties based on their properties.
+ *
+ * @param label the label of the {@link Element}
+ * @param propertyKey the key of the property to filter on
+ * @param value the value to compare the accessor value to for equality
+ * @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 GValue<String> label, final String propertyKey, final Object value) {
+ this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.has, label.get(), propertyKey, value);
+ TraversalHelper.addHasContainer(this.asAdmin(), new HasContainer(T.label.getAccessor(), P.eq(label)));
+ return TraversalHelper.addHasContainer(this.asAdmin(), new HasContainer(propertyKey, value instanceof P ? (P) value : P.eq(value)));
+ }
+
/**
* Filters vertices, edges and vertex properties based on the non-existence of properties.
*
@@ -2337,11 +2712,7 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
// groovy evaluation seems to do strange things with varargs given hasLabel(null, null). odd someone would
// do this but the failure is ugly if not handled.
- final int otherLabelsLength = null == otherLabels ? 0 : otherLabels.length;
- final String[] labels = new String[otherLabelsLength + 1];
- labels[0] = label;
- if (otherLabelsLength > 0)
- System.arraycopy(otherLabels, 0, labels, 1, otherLabelsLength);
+ final String[] labels = CollectionUtil.addFirst(otherLabels, label, String.class);
return TraversalHelper.addHasContainer(this.asAdmin(), new HasContainer(T.label.getAccessor(), labels.length == 1 ? P.eq(labels[0]) : P.within(labels)));
}
@@ -2364,6 +2735,24 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
}
}
+ /**
+ * Filters vertices, edges and vertex properties based on their label.
+ *
+ * @param label the label of the {@link Element}
+ * @param otherLabels additional labels of the {@link Element}
+ * @return the traversal with an appended {@link HasStep}
+ * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#has-step" target="_blank">Reference Documentation - Has Step</a>
+ * @since 4.0.0
+ */
+ public default GraphTraversal<S, E> hasLabel(final GValue<String> label, final GValue<String>... otherLabels) {
+ this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.hasLabel, label, otherLabels);
+
+ // groovy evaluation seems to do strange things with varargs given hasLabel(null, null). odd someone would
+ // do this but the failure is ugly if not handled.
+ final Object[] labels = CollectionUtil.addFirst(otherLabels, label, GValue.class);
+ return TraversalHelper.addHasContainer(this.asAdmin(), new HasContainer(T.label.getAccessor(), labels.length == 1 ? P.eq(labels[0]) : P.within(labels)));
+ }
+
/**
* Filters vertices, edges and vertex properties based on their identifier.
*
@@ -2376,10 +2765,15 @@ 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().getGremlinLang().addStep(Symbols.hasId, id, otherIds);
+ // the logic for dealing with hasId([]) is sketchy historically, just trying to maintain what we were
+ // originally testing prior to GValue.
+ if (id instanceof GValue && ((GValue) id).getType().isCollection()) {
+ return TraversalHelper.addHasContainer(this.asAdmin(), new HasContainer(T.id.getAccessor(), new P(Contains.within, id)));
+ }
+
//using ArrayList given P.within() turns all arguments into lists
final List<Object> ids = new ArrayList<>();
if (id instanceof Object[]) {
@@ -2388,8 +2782,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
@@ -2575,6 +2970,19 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
return this.asAdmin().addStep(new CoinStep<>(this.asAdmin(), probability));
}
+ /**
+ * Filter the <code>E</code> object given a biased coin toss. For internal use for parameterization features.
+ *
+ * @param probability the probability that the object will pass through the filter
+ * @return the traversal with an appended {@link CoinStep}.
+ * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#coin-step" target="_blank">Reference Documentation - Coin Step</a>
+ * @since 4.0.0
+ */
+ public default GraphTraversal<S, E> coin(final GValue<Double> probability) {
+ this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.coin, probability);
+ return this.asAdmin().addStep(new CoinStep<>(this.asAdmin(), probability));
+ }
+
/**
* Filter the objects in the traversal by the number of them to pass through the stream. Those before the value
* of {@code low} do not pass through and those that exceed the value of {@code high} will end the iteration.
@@ -3970,6 +4378,73 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
return this;
}
+ /**
+ * This is a step modulator to a {@link TraversalOptionParent} like {@code choose()} or {@code mergeV()} where the
+ * provided argument associated to the {@code token} is applied according to the semantics of the step. Please see
+ * the documentation of such steps to understand the usage context.
+ *
+ * @param token the token that would trigger this option which may be a {@link Pick}, {@link Merge},
+ * a {@link Traversal}, {@link Predicate}, or object depending on the step being modulated.
+ * @param traversalOption the option as a traversal
+ * @return the traversal with the modulated step
+ * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#choose-step" target="_blank">Reference Documentation - Choose Step</a>
+ * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#mergev-step" target="_blank">Reference Documentation - MergeV Step</a>
+ * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#mergee-step" target="_blank">Reference Documentation - MergeE Step</a>
+ * @since 3.0.0-incubating
+ */
+ public default <M, E2> GraphTraversal<S, E> option(final GValue<M> token, final Traversal<?, E2> traversalOption) {
+ this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.option, token, traversalOption);
+
+ // handle null similar to how option() with Map handles it, otherwise we get a NPE if this one gets used
+ final Traversal.Admin<E,E2> t = null == traversalOption ?
+ new ConstantTraversal<>(null) : (Traversal.Admin<E, E2>) traversalOption.asAdmin();
+ ((TraversalOptionParent<M, E, E2>) this.asAdmin().getEndStep()).addChildOption(token.get(), t);
+ return this;
+ }
+
+ /**
+ * This is a step modulator to a {@link TraversalOptionParent} like {@code choose()} or {@code mergeV()} where the
+ * provided argument associated to the {@code token} is applied according to the semantics of the step. Please see
+ * the documentation of such steps to understand the usage context.
+ *
+ * @param m Provides a {@code Map} as the option which is the same as doing {@code constant(m)}.
+ * @return the traversal with the modulated step
+ * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#mergev-step" target="_blank">Reference Documentation - MergeV Step</a>
+ * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#mergee-step" target="_blank">Reference Documentation - MergeE Step</a>
+ * @since 3.7.3
+ */
+ public default <M, E2> GraphTraversal<S, E> option(final M token, final GValue<Map<Object, Object>> m) {
+ this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.option, token, m);
+ ((TraversalOptionParent<M, E, E2>) this.asAdmin().getEndStep()).addChildOption(token, (Traversal.Admin<E, E2>) new ConstantTraversal<>(m).asAdmin());
+ return this;
+ }
+
+ /**
+ * This is a step modulator to a {@link TraversalOptionParent} like {@code choose()} or {@code mergeV()} where the
+ * provided argument associated to the {@code token} is applied according to the semantics of the step. Please see
+ * the documentation of such steps to understand the usage context.
+ *
+ * @param m Provides a {@code Map} as the option which is the same as doing {@code constant(m)}.
+ * @return the traversal with the modulated step
+ * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#mergev-step" target="_blank">Reference Documentation - MergeV Step</a>
+ * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#mergee-step" target="_blank">Reference Documentation - MergeE Step</a>
+ * @since 3.7.3
+ */
+ public default <M, E2> GraphTraversal<S, E> option(final Merge merge, final GValue<Map<Object, Object>> m, final VertexProperty.Cardinality cardinality) {
+ this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.option, merge, m, cardinality);
+
+ final Map<Object, Object> map = m.get();
+
+ // do explicit cardinality for every single pair in the map
+ for (Object k : map.keySet()) {
+ final Object o = map.get(k);
+ if (!(o instanceof CardinalityValueTraversal))
+ map.put(k, new CardinalityValueTraversal(cardinality, o));
+ }
+ ((TraversalOptionParent<M, E, E2>) this.asAdmin().getEndStep()).addChildOption((M) merge, (Traversal.Admin<E, E2>) new ConstantTraversal<>(m).asAdmin());
+ return this;
+ }
+
////
///////////////////// IO 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 a28089247f..63e49e243f 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
@@ -27,6 +27,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource;
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.branch.UnionStep;
import org.apache.tinkerpop.gremlin.process.traversal.step.map.AddEdgeStartStep;
import org.apache.tinkerpop.gremlin.process.traversal.step.map.AddVertexStartStep;
@@ -406,6 +407,22 @@ public class GraphTraversalSource implements TraversalSource {
return traversal.addStep(step);
}
+ /**
+ * 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
+ * key/value pairs where the keys may be {@code String} property values or a value of {@link T}. If a match is not
+ * 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 4.0.0
+ */
+ public GraphTraversal<Vertex, Vertex> mergeV(final GValue<Map<Object, Object>> searchCreate) {
+ final GraphTraversalSource clone = GraphTraversalSource.this.clone();
+ clone.gremlinLang.addStep(GraphTraversal.Symbols.mergeV, searchCreate);
+ final GraphTraversal.Admin<Vertex, Vertex> traversal = new DefaultGraphTraversal<>(clone);
+ return traversal.addStep(new MergeVertexStep(traversal, true, searchCreate));
+ }
+
/**
* Spawns a {@link GraphTraversal} by doing a merge (i.e. upsert) style operation for an {@link Edge} using a
* {@code Map} as an argument.
@@ -438,6 +455,20 @@ public class GraphTraversalSource implements TraversalSource {
return traversal.addStep(step);
}
+ /**
+ * Spawns a {@link GraphTraversal} by doing a merge (i.e. upsert) style operation for an {@link Edge} using a
+ * {@code Map} as an argument.
+ *
+ * @param searchCreate This {@code Map} can have a key of {@link T} {@link Direction} or a {@code String}.
+ * @since 4.0.0
+ */
+ public GraphTraversal<Edge, Edge> mergeE(final GValue<Map<?, Object>> searchCreate) {
+ final GraphTraversalSource clone = GraphTraversalSource.this.clone();
+ clone.gremlinLang.addStep(GraphTraversal.Symbols.mergeE, searchCreate);
+ final GraphTraversal.Admin<Edge, Edge> traversal = new DefaultGraphTraversal<>(clone);
+ return traversal.addStep(new MergeEdgeStep(traversal, true, searchCreate));
+ }
+
/**
* Spawns a {@link GraphTraversal} starting it with arbitrary values.
*/
@@ -557,6 +588,36 @@ public class GraphTraversalSource implements TraversalSource {
return traversal.addStep(step);
}
+ /**
+ * 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.gremlinLang.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.gremlinLang.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()));
+ }
+
/**
* Merges the results of an arbitrary number of traversals.
*
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 57776db82e..59fdf5f605 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
@@ -25,6 +25,8 @@ import org.apache.tinkerpop.gremlin.process.traversal.Pop;
import org.apache.tinkerpop.gremlin.process.traversal.Scope;
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.map.FormatStep;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
import org.apache.tinkerpop.gremlin.process.traversal.traverser.util.TraverserSet;
import org.apache.tinkerpop.gremlin.structure.Column;
@@ -110,6 +112,13 @@ public class __ {
return __.<A>start().constant(a);
}
+ /**
+ * @see GraphTraversal#constant(GValue)
+ */
+ public static <A> GraphTraversal<A, A> constant(final GValue<A> a) {
+ return __.<A>start().constant(a);
+ }
+
/**
* @see GraphTraversal#label()
*/
@@ -145,6 +154,13 @@ public class __ {
return __.<Vertex>start().to(direction, edgeLabels);
}
+ /**
+ * @see GraphTraversal#to(Direction, GValue, GValue...)
+ */
+ public static GraphTraversal<Vertex, Vertex> to(final Direction direction, final GValue<String> edgeLabel, final GValue<String>... edgeLabels) {
+ return __.<Vertex>start().to(direction, edgeLabel, edgeLabels);
+ }
+
/**
* @see GraphTraversal#out(String...)
*/
@@ -152,6 +168,13 @@ public class __ {
return __.<Vertex>start().out(edgeLabels);
}
+ /**
+ * @see GraphTraversal#out(GValue, GValue...)
+ */
+ public static GraphTraversal<Vertex, Vertex> out(final GValue<String> edgeLabel, final GValue<String>... edgeLabels) {
+ return __.<Vertex>start().out(edgeLabel, edgeLabels);
+ }
+
/**
* @see GraphTraversal#in(String...)
*/
@@ -159,6 +182,13 @@ public class __ {
return __.<Vertex>start().in(edgeLabels);
}
+ /**
+ * @see GraphTraversal#in(String...)
+ */
+ public static GraphTraversal<Vertex, Vertex> in(final GValue<String> edgeLabel, final GValue<String>... edgeLabels) {
+ return __.<Vertex>start().in(edgeLabel, edgeLabels);
+ }
+
/**
* @see GraphTraversal#both(String...)
*/
@@ -166,6 +196,13 @@ public class __ {
return __.<Vertex>start().both(edgeLabels);
}
+ /**
+ * @see GraphTraversal#both(GValue, GValue...)
+ */
+ public static GraphTraversal<Vertex, Vertex> both(final GValue<String> edgeLabel, final GValue<String>... edgeLabels) {
+ return __.<Vertex>start().both(edgeLabel, edgeLabels);
+ }
+
/**
* @see GraphTraversal#toE(Direction, String...)
*/
@@ -173,6 +210,13 @@ public class __ {
return __.<Vertex>start().toE(direction, edgeLabels);
}
+ /**
+ * @see GraphTraversal#toE(Direction, GValue, GValue...)
+ */
+ public static GraphTraversal<Vertex, Edge> toE(final Direction direction, final GValue<String> edgeLabel, final GValue<String>... edgeLabels) {
+ return __.<Vertex>start().toE(direction, edgeLabel, edgeLabels);
+ }
+
/**
* @see GraphTraversal#outE(String...)
*/
@@ -180,6 +224,13 @@ public class __ {
return __.<Vertex>start().outE(edgeLabels);
}
+ /**
+ * @see GraphTraversal#outE(GValue, GValue...)
+ */
+ public static GraphTraversal<Vertex, Edge> outE(final GValue<String> edgeLabel, final GValue<String>... edgeLabels) {
+ return __.<Vertex>start().outE(edgeLabel, edgeLabels);
+ }
+
/**
* @see GraphTraversal#inE(String...)
*/
@@ -187,6 +238,13 @@ public class __ {
return __.<Vertex>start().inE(edgeLabels);
}
+ /**
+ * @see GraphTraversal#inE(GValue, GValue...)
+ */
+ public static GraphTraversal<Vertex, Edge> inE(final GValue<String> edgeLabel, final GValue<String>... edgeLabels) {
+ return __.<Vertex>start().inE(edgeLabel, edgeLabels);
+ }
+
/**
* @see GraphTraversal#bothE(String...)
*/
@@ -194,6 +252,13 @@ public class __ {
return __.<Vertex>start().bothE(edgeLabels);
}
+ /**
+ * @see GraphTraversal#bothE(GValue, GValue...)
+ */
+ public static GraphTraversal<Vertex, Edge> bothE(final GValue<String> edgeLabel, final GValue<String>... edgeLabels) {
+ return __.<Vertex>start().bothE(edgeLabel, edgeLabels);
+ }
+
/**
* @see GraphTraversal#toV(Direction)
*/
@@ -512,6 +577,13 @@ public class __ {
return __.<A>start().addV(vertexLabel);
}
+ /**
+ * @see GraphTraversal#addV(GValue)
+ */
+ public static <A> GraphTraversal<A, Vertex> addV(final GValue<String> vertexLabel) {
+ return __.<A>start().addV(vertexLabel);
+ }
+
/**
* @see GraphTraversal#addV(org.apache.tinkerpop.gremlin.process.traversal.Traversal)
*/
@@ -540,6 +612,13 @@ public class __ {
return __.<A>start().mergeV(searchCreate);
}
+ /**
+ * @see GraphTraversal#mergeV(GValue)
+ */
+ public static <A> GraphTraversal<A, Vertex> mergeV(final GValue<Map<Object, Object>> searchCreate) {
+ return __.<A>start().mergeV(searchCreate);
+ }
+
/**
* @see GraphTraversal#mergeV(Traversal)
*/
@@ -554,6 +633,13 @@ public class __ {
return __.<A>start().addE(edgeLabel);
}
+ /**
+ * @see GraphTraversal#addE(GValue)
+ */
+ public static <A> GraphTraversal<A, Edge> addE(final GValue<String> edgeLabel) {
+ return __.<A>start().addE(edgeLabel);
+ }
+
/**
* @see GraphTraversal#addE(Traversal)
*/
@@ -575,6 +661,13 @@ public class __ {
return __.<A>start().mergeE(searchCreate);
}
+ /**
+ * @see GraphTraversal#mergeE(GValue)
+ */
+ public static <A> GraphTraversal<A, Edge> mergeE(final GValue<Map<Object, Object>> searchCreate) {
+ return __.<A>start().mergeE(searchCreate);
+ }
+
/**
* @see GraphTraversal#mergeE(Traversal)
*/
@@ -806,6 +899,13 @@ public class __ {
return __.<A>start().difference(values);
}
+ /**
+ * @see GraphTraversal#difference(GValue)
+ */
+ public static <A> GraphTraversal<A, Set<?>> difference(final GValue<Object> values) {
+ return __.<A>start().difference(values);
+ }
+
/**
* @see GraphTraversal#disjunct(Object)
*/
@@ -813,6 +913,13 @@ public class __ {
return __.<A>start().disjunct(values);
}
+ /**
+ * @see GraphTraversal#disjunct(GValue)
+ */
+ public static <A> GraphTraversal<A, Set<?>> disjunct(final GValue<Object> values) {
+ return __.<A>start().disjunct(values);
+ }
+
/**
* @see GraphTraversal#intersect(Object)
*/
@@ -820,6 +927,13 @@ public class __ {
return __.<A>start().intersect(values);
}
+ /**
+ * @see GraphTraversal#intersect(GValue)
+ */
+ public static <A> GraphTraversal<A, Set<?>> intersect(final GValue<Object> values) {
+ return __.<A>start().intersect(values);
+ }
+
/**
* @see GraphTraversal#conjoin(String)
*/
@@ -827,6 +941,13 @@ public class __ {
return __.<A>start().conjoin(values);
}
+ /**
+ * @see GraphTraversal#conjoin(GValue)
+ */
+ public static <A> GraphTraversal<A, String> conjoin(final GValue<String> values) {
+ return __.<A>start().conjoin(values);
+ }
+
/**
* @see GraphTraversal#merge(Object)
*/
@@ -834,6 +955,13 @@ public class __ {
return __.<A>start().merge(values);
}
+ /**
+ * @see GraphTraversal#merge(GValue)
+ */
+ public static <A, B> GraphTraversal<A, B> merge(final GValue<Object> values) {
+ return __.<A>start().merge(values);
+ }
+
/**
* @see GraphTraversal#combine(Object)
*/
@@ -841,6 +969,13 @@ public class __ {
return __.<A>start().combine(values);
}
+ /**
+ * @see GraphTraversal#combine(GValue)
+ */
+ public static <A> GraphTraversal<A, List<?>> combine(final GValue<Object> values) {
+ return __.<A>start().combine(values);
+ }
+
/**
* @see GraphTraversal#product(Object)
*/
@@ -848,6 +983,13 @@ public class __ {
return __.<A>start().product(values);
}
+ /**
+ * @see GraphTraversal#product(GValue)
+ */
+ public static <A> GraphTraversal<A, List<List<?>>> product(final GValue<Object> values) {
+ return __.<A>start().product(values);
+ }
+
///////////////////// FILTER STEPS /////////////////////
/**
@@ -934,6 +1076,13 @@ public class __ {
return __.<A>start().has(label, propertyKey, value);
}
+ /**
+ * @see GraphTraversal#has(GValue, String, Object)
+ */
+ public static <A> GraphTraversal<A, A> has(final GValue<String> label, final String propertyKey, final Object value) {
+ return __.<A>start().has(label, propertyKey, value);
+ }
+
/**
* @see GraphTraversal#has(String, String, P)
*/
@@ -976,6 +1125,13 @@ public class __ {
return __.<A>start().hasLabel(label, otherLabels);
}
+ /**
+ * @see GraphTraversal#hasLabel(GValue, GValue...)
+ */
+ public static <A> GraphTraversal<A, A> hasLabel(final GValue<String> label, GValue<String>... otherLabels) {
+ return __.<A>start().hasLabel(label, otherLabels);
+ }
+
/**
* @see GraphTraversal#hasLabel(P)
*/
@@ -1074,6 +1230,13 @@ public class __ {
return __.<A>start().coin(probability);
}
+ /**
+ * @see GraphTraversal#coin(GValue)
+ */
+ public static <A> GraphTraversal<A, A> coin(final GValue<Double> probability) {
+ return __.<A>start().coin(probability);
+ }
+
/**
* @see GraphTraversal#range(long, long)
*/
@@ -1517,6 +1680,13 @@ public class __ {
return __.<A>start().call(service, params);
}
+ /**
+ * @see GraphTraversal#call(String, GValue)
+ */
+ public static <A, B> GraphTraversal<A, B> call(final String service, final GValue<Map> params) {
+ return __.<A>start().call(service, params);
+ }
+
/**
* @see GraphTraversal#call(String, Traversal)
*/
@@ -1530,4 +1700,11 @@ public class __ {
public static <A, B> GraphTraversal<A, B> call(final String service, final Map params, final Traversal<?, Map<?,?>> childTraversal) {
return __.<A>start().call(service, params, childTraversal);
}
+
+ /**
+ * @see GraphTraversal#call(String, GValue, Traversal)
+ */
+ public static <A, B> GraphTraversal<A, B> call(final String service, final GValue<Map> params, final Traversal<?, Map<?,?>> childTraversal) {
+ return __.<A>start().call(service, params, childTraversal);
+ }
}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/ConstantTraversal.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/ConstantTraversal.java
index b22d88e66c..3bac69ce48 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/ConstantTraversal.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/ConstantTraversal.java
@@ -19,6 +19,7 @@
package org.apache.tinkerpop.gremlin.process.traversal.lambda;
import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
import java.util.Objects;
@@ -29,15 +30,23 @@ import java.util.Objects;
*/
public final class ConstantTraversal<S, E> extends AbstractLambdaTraversal<S, E> {
- private final E end;
+ private final GValue<E> end;
public ConstantTraversal(final E end) {
- this.end = end;
+ this.end = null == end ? GValue.of(null) : GValue.of(end);
+ }
+
+ public ConstantTraversal(final GValue<E> end) {
+ this.end = null == end ? GValue.of(null) : end;
}
@Override
public E next() {
- return this.end;
+ return this.end.get();
+ }
+
+ public GValue<E> getEnd() {
+ return end;
}
@Override
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/GType.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/GType.java
new file mode 100644
index 0000000000..4c8777d290
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/GType.java
@@ -0,0 +1,103 @@
+/*
+ * 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.Path;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Property;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * An enum that describes types that are used in the Gremlin language.
+ */
+public enum GType {
+ BIG_DECIMAL(BigDecimal.class),
+ BIG_INTEGER(BigInteger.class),
+ BOOLEAN(Boolean.class),
+ DOUBLE(Double.class),
+ EDGE(Edge.class),
+ INTEGER(Integer.class),
+ LIST(List.class),
+ LONG(Long.class),
+ MAP(Map.class),
+ PATH(Path.class),
+ PROPERTY(Property.class),
+ SET(Set.class),
+ STRING(String.class),
+ UNKNOWN(null),
+ VERTEX(Vertex.class);
+
+ private Class<?> javaType;
+
+ GType(final Class<?> javaType) {
+ this.javaType = javaType;
+ }
+
+ public Class<?> getJavaType() {
+ return this.javaType;
+ }
+
+ /**
+ * Returns {@code true} if the type is a number.
+ */
+ public boolean isNumeric() {
+ return this == INTEGER || this == DOUBLE || this == LONG || this == BIG_INTEGER || this == BIG_DECIMAL;
+ }
+
+ /**
+ * Returns {@code true} if the type is a collection.v
+ */
+ public boolean isCollection() {
+ return this == LIST || this == SET;
+ }
+
+ /**
+ * Returns {@code true} if the type is an element.
+ */
+ public boolean isElement() {
+ return this == VERTEX || this == EDGE;
+ }
+
+ /**
+ * Convert an object to a matching {@link GType} and if not matched return {@link GType#UNKNOWN}.
+ */
+ public static GType getType(final Object object) {
+ if (object instanceof String) return STRING;
+ else if (object instanceof Integer) return INTEGER;
+ else if (object instanceof Boolean) return BOOLEAN;
+ else if (object instanceof Double) return DOUBLE;
+ else if (object instanceof Long) return LONG;
+ else if (object instanceof Map) return MAP;
+ else if (object instanceof List) return LIST;
+ else if (object instanceof Set) return SET;
+ else if (object instanceof Vertex) return VERTEX;
+ else if (object instanceof Edge) return EDGE;
+ else if (object instanceof Path) return PATH;
+ else if (object instanceof Property) return PROPERTY;
+ else if (object instanceof BigInteger) return BIG_INTEGER;
+ else if (object instanceof BigDecimal) return BIG_DECIMAL;
+ else return UNKNOWN;
+ }
+}
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
new file mode 100644
index 0000000000..0608d94a19
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/GValue.java
@@ -0,0 +1,443 @@
+/*
+ * 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.Path;
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Element;
+import org.apache.tinkerpop.gremlin.structure.Property;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Stream;
+
+/**
+ * A {@code GValue} is a variable or literal value that is used in a {@link Traversal}. It is composed of a key-value
+ * pair where the key is the name given to the variable and the value is the object that the variable resolved to. If
+ * the name is not given, the value was provided literally in the traversal. The value of the variable can be any
+ * object. The {@code GValue} also includes the {@link GType} that describes the type it contains.
+ */
+public class GValue<V> implements Cloneable, Serializable {
+ private final String name;
+ private final GType type;
+
+ private final V value;
+
+ private GValue(final GType type, final V value) {
+ this(null, type, value);
+ }
+
+ private GValue(final String name, final GType type, final V value) {
+ this.name = name;
+ this.type = type;
+ this.value = value;
+ }
+
+ /**
+ * Determines if the value held by this object was defined as a variable or a literal value. Literal values simply
+ * have no name.
+ */
+ public boolean isVariable() {
+ return this.name != null;
+ }
+
+ /**
+ * Gets the name of the variable if it was defined as such and returns empty if the value was a literal.
+ */
+ public String getName() {
+ return this.name;
+ }
+
+ /**
+ * Gets the type of the value. The explicit type could be determined with {@code instanceof} on the value, but this
+ * might be helpful for cases where the value was constructed with a {@code null} value which might just return as
+ * {@code Object}.
+ */
+ public GType getType() {
+ return this.type;
+ }
+
+ /**
+ * Determines if the value held is of a {@code null} value.
+ */
+ public boolean isNull() {
+ return this.value == null;
+ }
+
+ /**
+ * Gets the value.
+ */
+ public V get() {
+ return this.value;
+ }
+
+ @Override
+ public String toString() {
+ return isVariable() ?
+ String.format("%s&%s", name, value) : Objects.toString(value);
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ final GValue<?> gValue = (GValue<?>) o;
+ return Objects.equals(name, gValue.name) && type == gValue.type && Objects.equals(value, gValue.value);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name, type, value);
+ }
+
+ /**
+ * Create a new {@code Var} from a particular value but without the specified name. If the argument provide is
+ * already a {@code GValue} then it is returned as-is.
+ *
+ * @param value the value of the variable
+ */
+ public static <V> GValue<V> of(final V value) {
+ if (value instanceof GValue) return (GValue) value;
+ return new GValue<>(GType.getType(value), value);
+ }
+
+ /**
+ * Create a new {@code Var} with the specified name and value.. If the argument provide is already a
+ * {@code GValue} then it is returned as-is.
+ *
+ * @param name the name of the variable
+ * @param value the value of the variable
+ */
+ public static <V> GValue<V> of(final String name, final V value) {
+ if (value instanceof GValue) throw new IllegalArgumentException("value cannot be a GValue");
+ return new GValue<>(name, GType.getType(value), value);
+ }
+
+ /**
+ * Create a new {@code GValue} for a string value.
+ */
+ public static GValue<String> ofString(final String value) {
+ return new GValue<>(GType.STRING, value);
+ }
+
+ /**
+ * Create a new {@code GValue} for a string value with a specified name.
+ */
+ public static GValue<String> ofString(final String name, final String value) {
+ return new GValue<>(name, GType.STRING, value);
+ }
+
+ /**
+ * Create a new {@code GValue} for an integer value.
+ */
+ public static GValue<Integer> ofInteger(final Integer value) {
+ return new GValue<>(GType.INTEGER, value);
+ }
+
+ /**
+ * Create a new {@code GValue} for an integer value with a specified name.
+ */
+ public static GValue<Integer> ofInteger(final String name, final Integer value) {
+ return new GValue<>(name, GType.INTEGER, value);
+ }
+
+ /**
+ * Create a new {@code GValue} for a boolean value.
+ */
+ public static GValue<Boolean> ofBoolean(final Boolean value) {
+ return new GValue<>(GType.BOOLEAN, value);
+ }
+
+ /**
+ * Create a new {@code GValue} for a boolean value with a specified name.
+ */
+ public static GValue<Boolean> ofBoolean(final String name, final Boolean value) {
+ return new GValue<>(name, GType.BOOLEAN, value);
+ }
+
+ /**
+ * Create a new {@code GValue} for a double value.
+ */
+ public static GValue<Double> ofDouble(final Double value) {
+ return new GValue<>(GType.DOUBLE, value);
+ }
+
+ /**
+ * Create a new {@code GValue} for a double value with a specified name.
+ */
+ public static GValue<Double> ofDouble(final String name, final Double value) {
+ return new GValue<>(name, GType.DOUBLE, value);
+ }
+
+ /**
+ * Create a new {@code GValue} for a BigInteger value.
+ */
+ public static GValue<BigInteger> ofBigInteger(final BigInteger value) {
+ return new GValue<>(GType.BIG_INTEGER, value);
+ }
+
+ /**
+ * Create a new {@code GValue} for a BigInteger value with a specified name.
+ */
+ public static GValue<BigInteger> ofBigInteger(final String name, final BigInteger value) {
+ return new GValue<>(name, GType.BIG_INTEGER, value);
+ }
+
+ /**
+ * Create a new {@code GValue} for a BigDecimal value.
+ */
+ public static GValue<BigDecimal> ofBigDecimal(final BigDecimal value) {
+ return new GValue<>(GType.BIG_DECIMAL, value);
+ }
+
+ /**
+ * Create a new {@code GValue} for a BigDecimal value with a specified name.
+ */
+ public static GValue<BigDecimal> ofBigDecimal(final String name, final BigDecimal value) {
+ return new GValue<>(name, GType.BIG_DECIMAL, value);
+ }
+
+ /**
+ * Create a new {@code GValue} for a long value.
+ */
+ public static GValue<Long> ofLong(final Long value) {
+ return new GValue<>(GType.LONG, value);
+ }
+
+ /**
+ * Create a new {@code GValue} for a long value with a specified name.
+ */
+ public static GValue<Long> ofLong(final String name, final Long value) {
+ return new GValue<>(name, GType.LONG, value);
+ }
+
+ /**
+ * Create a new {@code GValue} for a map value.
+ */
+ public static GValue<Map> ofMap(final Map value) {
+ return new GValue<>(GType.MAP, value);
+ }
+
+ /**
+ * Create a new {@code GValue} for a map value with a specified name.
+ */
+ public static GValue<Map> ofMap(final String name, final Map value) {
+ return new GValue<>(name, GType.MAP, value);
+ }
+
+ /**
+ * Create a new {@code GValue} for a list value.
+ */
+ public static <T> GValue<List<T>> ofList(final List<T> value) {
+ return new GValue<>(GType.LIST, value);
+ }
+
+ /**
+ * Create a new {@code GValue} for a list value with a specified name.
+ */
+ public static <T> GValue<List<T>> ofList(final String name, final List<T> value) {
+ return new GValue<>(name, GType.LIST, value);
+ }
+
+ /**
+ * Create a new {@code GValue} for a set value.
+ */
+ public static GValue<Set> ofSet(final Set value) {
+ return new GValue<>(GType.SET, value);
+ }
+
+ /**
+ * Create a new {@code GValue} for a set value with a specified name.
+ */
+ public static GValue<Set> ofSet(final String name, final Set value) {
+ return new GValue<>(name, GType.SET, value);
+ }
+
+ /**
+ * Create a new {@code GValue} for a vertex value.
+ */
+ public static GValue<Vertex> ofVertex(final Vertex value) {
+ return new GValue<>(GType.VERTEX, value);
+ }
+
+ /**
+ * Create a new {@code GValue} for a vertex value with a specified name.
+ */
+ public static GValue<Vertex> ofVertex(final String name, final Vertex value) {
+ return new GValue<>(name, GType.VERTEX, value);
+ }
+
+ /**
+ * Create a new {@code GValue} for an edge value.
+ */
+ public static GValue<Edge> ofEdge(final Edge value) {
+ return new GValue<>(GType.EDGE, value);
+ }
+
+ /**
+ * Create a new {@code GValue} for an edge value with a specified name.
+ */
+ public static GValue<Edge> ofEdge(final String name, final Edge value) {
+ return new GValue<>(name, GType.EDGE, value);
+ }
+
+ /**
+ * Create a new {@code GValue} for a path value.
+ */
+ public static GValue<Path> ofPath(final Path value) {
+ return new GValue<>(GType.PATH, value);
+ }
+
+ /**
+ * Create a new {@code GValue} for a path value with a specified name.
+ */
+ public static GValue<Path> ofPath(final String name, final Path value) {
+ return new GValue<>(name, GType.PATH, value);
+ }
+
+ /**
+ * Create a new {@code GValue} for a property value.
+ */
+ public static GValue<Property> ofProperty(final Property value) {
+ return new GValue<>(GType.PROPERTY, value);
+ }
+
+ /**
+ * Create a new {@code GValue} for a property value with a specified name.
+ */
+ public static GValue<Property> ofProperty(final String name, final Property value) {
+ return new GValue<>(name, GType.PROPERTY, value);
+ }
+
+ /**
+ * If the object is a {@code GValue} then get its value, otherwise return the object as-is.
+ */
+ public static <T> T getFrom(final Object o) {
+ return o instanceof GValue ? ((GValue<T>) o).get() : (T) o;
+ }
+
+ /**
+ * Tests if the object is a {@link GValue} and if so, checks the type of the value against the provided
+ * {@link GType}.
+ */
+ public static boolean valueInstanceOf(final Object o, final GType type) {
+ return o instanceof GValue && ((GValue) o).getType() == type;
+ }
+
+ /**
+ * Tests if the object is a {@link GValue} and if so, checks if the type of the value is a collection.
+ */
+ public static boolean valueInstanceOfCollection(final Object o) {
+ return o instanceof GValue && ((GValue) o).getType().isCollection();
+ }
+
+ /**
+ * Tests if the object is a {@link GValue} and if so, checks if the type of the value is a numeric.
+ */
+ public static boolean valueInstanceOfNumeric(final Object o) {
+ return o instanceof GValue && ((GValue) o).getType().isNumeric();
+ }
+
+ /**
+ * Checks the type of the object against the provided {@link GType}. If the object is a {@link GValue} then it
+ * can directly check the type, otherwise it will test the given object's class itself using the mappign on the
+ * {@link GType}.
+ */
+ public static boolean instanceOf(final Object o, final GType type) {
+ if (null == o)
+ return false;
+ else if (o instanceof GValue)
+ return ((GValue) o).getType() == type;
+ else
+ return type.getJavaType().isAssignableFrom(o.getClass());
+ }
+
+ /**
+ * Returns {@code true} if the object is a collection or a {@link GValue} that contains a {@link Collection}.
+ */
+ public static boolean instanceOfCollection(final Object o) {
+ return o instanceof Collection || (o instanceof GValue && ((GValue) o).getType().isCollection());
+ }
+
+ /**
+ * Returns {@code true} if the object is an element or a {@link GValue} that contains an {@link Element}.
+ */
+ public static boolean instanceOfElement(final Object o) {
+ return o instanceof Element || (o instanceof GValue && ((GValue) o).getType().isElement());
+ }
+
+ /**
+ * Returns {@code true} if the object is a number or a {@link GValue} that contains a number.
+ */
+ public static boolean instanceOfNumber(final Object o) {
+ return o instanceof Number || (o instanceof GValue && ((GValue) o).getType().isNumeric());
+ }
+
+ /**
+ * The elements in object array argument are examined to see if they are {@link GValue} objects. If they are, they
+ * are preserved as is. If they are not then they are wrapped in a {@link GValue} object.
+ */
+ public static <T> GValue<T>[] ensureGValues(final Object[] args) {
+ return Stream.of(args).map(GValue::of).toArray(GValue[]::new);
+ }
+
+ /**
+ * Converts {@link GValue} objects argument array to their values to prevent them from leaking to the Graph API.
+ * Providers extending from this step should use this method to get actual values to prevent any {@link GValue}
+ * objects from leaking to the Graph API.
+ */
+ public static Object[] resolveToValues(final GValue<?>[] gvalues) {
+ final Object[] values = new Object[gvalues.length];
+ for (int i = 0; i < gvalues.length; i++) {
+ values[i] = gvalues[i].get();
+ }
+ return values;
+ }
+
+ /**
+ * Takes an argument that is either a {@code GValue} or an object and if the former, returns the child object and
+ * if the latter returns the object itself.
+ */
+ public static Object valueOf(final Object either) {
+ if (either instanceof GValue)
+ return ((GValue<?>) either).get();
+ else
+ return either;
+ }
+
+ /**
+ * Takes an argument that is either a {@code GValue} or an object and returns its {@code Number} form, otherwise
+ * throws an exception.
+ */
+ public static Number numberOf(final Object either) {
+ final Object o = valueOf(either);
+ if (o instanceof Number)
+ return (Number) o;
+ else
+ throw new IllegalStateException("Argument is not a number");
+ }
+}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/CoinStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/CoinStep.java
index e4a44abe93..5fd63ee3de 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/CoinStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/CoinStep.java
@@ -21,6 +21,7 @@ package org.apache.tinkerpop.gremlin.process.traversal.step.filter;
import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
import org.apache.tinkerpop.gremlin.process.traversal.step.Seedable;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
@@ -29,16 +30,23 @@ import java.util.Random;
import java.util.Set;
/**
+ * A filter step that will randomly allow traversers to pass through the step based on a probability value.
+ *
* @author Marko A. Rodriguez (http://markorodriguez.com)
*/
public final class CoinStep<S> extends FilterStep<S> implements Seedable {
private final Random random = new Random();
- private final double probability;
+ private final GValue<Double> probability;
public CoinStep(final Traversal.Admin traversal, final double probability) {
super(traversal);
- this.probability = probability;
+ this.probability = GValue.ofDouble(probability);
+ }
+
+ public CoinStep(final Traversal.Admin traversal, final GValue<Double> probability) {
+ super(traversal);
+ this.probability = null == probability ? GValue.ofDouble(null) : probability;
}
@Override
@@ -47,7 +55,11 @@ public final class CoinStep<S> extends FilterStep<S> implements Seedable {
}
public double getProbability() {
- return this.probability;
+ return probability.get();
+ }
+
+ public GValue<Double> getProbabilityGValue() {
+ return probability;
}
@Override
@@ -55,11 +67,11 @@ public final class CoinStep<S> extends FilterStep<S> implements Seedable {
long newBulk = 0l;
if (traverser.bulk() < 100) {
for (int i = 0; i < traverser.bulk(); i++) {
- if (this.probability >= random.nextDouble())
+ if (this.probability.get() >= random.nextDouble())
newBulk++;
}
} else {
- newBulk = Math.round(this.probability * traverser.bulk());
+ newBulk = Math.round(this.probability.get() * traverser.bulk());
}
if (0 == newBulk) return false;
traverser.setBulk(newBulk);
@@ -73,7 +85,7 @@ public final class CoinStep<S> extends FilterStep<S> implements Seedable {
@Override
public int hashCode() {
- return super.hashCode() ^ Double.hashCode(this.probability);
+ return super.hashCode() ^ Double.hashCode(this.probability.get());
}
@Override
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 f5f7280764..db3f72cfe7 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,8 @@ 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;
import org.apache.tinkerpop.gremlin.process.traversal.step.Writing;
@@ -59,6 +61,11 @@ public class AddEdgeStep<S> extends ScalarMapStep<S, Edge>
this.parameters.set(this, T.label, edgeLabel);
}
+ public AddEdgeStep(final Traversal.Admin traversal, final GValue<String> edgeLabel) {
+ super(traversal);
+ this.parameters.set(this, T.label, edgeLabel);
+ }
+
public AddEdgeStep(final Traversal.Admin traversal, final Traversal.Admin<S,String> edgeLabelTraversal) {
super(traversal);
this.parameters.set(this, T.label, edgeLabelTraversal);
@@ -107,7 +114,7 @@ public class AddEdgeStep<S> extends ScalarMapStep<S, Edge>
edgeLabel, e.getMessage()));
}
- if (!(theTo instanceof Vertex))
+ if (!GValue.instanceOf(theTo, 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()));
@@ -121,13 +128,13 @@ public class AddEdgeStep<S> extends ScalarMapStep<S, Edge>
edgeLabel, e.getMessage()));
}
- if (!(theFrom instanceof Vertex))
+ if (!GValue.instanceOf(theFrom, 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 = GValue.getFrom(theTo);
+ Vertex fromVertex = GValue.getFrom(theFrom);
if (toVertex instanceof Attachable)
toVertex = ((Attachable<Vertex>) toVertex)
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStep.java
index 0dfb55c2a1..cfde7d84fc 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStep.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.Scoping;
import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
import org.apache.tinkerpop.gremlin.process.traversal.step.Writing;
@@ -52,6 +53,10 @@ public class AddVertexStep<S> extends ScalarMapStep<S, Vertex>
this.parameters.set(this, T.label, null == label ? Vertex.DEFAULT_LABEL : label);
userProvidedLabel = label != null;
}
+ public AddVertexStep(final Traversal.Admin traversal, final GValue<String> label) {
+ super(traversal);
+ this.parameters.set(this, T.label, null == label ? Vertex.DEFAULT_LABEL : label);
+ }
public AddVertexStep(final Traversal.Admin traversal, final Traversal.Admin<S,String> vertexLabelTraversal) {
super(traversal);
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/CombineStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/CombineStep.java
index ccf601acab..67c120c03a 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/CombineStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/CombineStep.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;
@@ -37,7 +38,7 @@ import java.util.Set;
*/
public final class CombineStep<S, E> extends ScalarMapStep<S, List<?>> implements TraversalParent, ListFunction {
private Traversal.Admin<S, E> valueTraversal;
- private Object parameterItems;
+ private GValue<Object> parameterItems;
public CombineStep(final Traversal.Admin traversal, final Object values) {
super(traversal);
@@ -45,7 +46,7 @@ public final class CombineStep<S, E> extends ScalarMapStep<S, List<?>> implement
if (values instanceof Traversal) {
valueTraversal = integrateChild(((Traversal<S, E>) values).asAdmin());
} else {
- parameterItems = values;
+ parameterItems = values instanceof GValue ? (GValue<Object>) values : GValue.of(values);
}
}
@@ -53,9 +54,9 @@ public final class CombineStep<S, E> extends ScalarMapStep<S, List<?>> implement
public String getStepName() { return "combine"; }
@Override
- protected List<?> map(Traverser.Admin<S> traverser) {
+ protected List<?> map(final 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 combined = new ArrayList(listA);
combined.addAll(listB);
@@ -68,7 +69,11 @@ public final class CombineStep<S, E> extends ScalarMapStep<S, List<?>> implement
return (null == valueTraversal) ? Collections.emptyList() : Collections.singletonList(valueTraversal);
}
- public Object getParameterItems() {
+ public Object getParameter() {
+ return parameterItems.get();
+ }
+
+ public GValue<Object> getParameterItems() {
return parameterItems;
}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConjoinStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConjoinStep.java
index ce6818b473..e6bb27a2e7 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConjoinStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConjoinStep.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.traverser.TraverserRequirement;
import org.apache.tinkerpop.gremlin.process.traversal.util.ListFunction;
@@ -34,11 +35,15 @@ import java.util.Set;
* A map step that returns the result of joining every element in the traverser using the delimiter argument.
*/
public final class ConjoinStep<S> extends ScalarMapStep<S, String> implements ListFunction {
- private String delimiter;
+ private GValue<String> delimiter;
public ConjoinStep(final Traversal.Admin traversal, final String delimiter) {
+ this(traversal, GValue.of(delimiter));
+ }
+
+ public ConjoinStep(final Traversal.Admin traversal, final GValue<String> delimiter) {
super(traversal);
- if (null == delimiter) { throw new IllegalArgumentException("Input delimiter to conjoin step can't be null."); }
+ if (null == delimiter || null == delimiter.get()) { throw new IllegalArgumentException("Input delimiter to conjoin step can't be null."); }
this.delimiter = delimiter;
}
@@ -46,7 +51,7 @@ public final class ConjoinStep<S> extends ScalarMapStep<S, String> implements Li
public String getStepName() { return "conjoin"; }
@Override
- protected String map(Traverser.Admin<S> traverser) {
+ protected String map(final Traverser.Admin<S> traverser) {
final Collection elements = convertTraverserToCollection(traverser);
if (elements.isEmpty()) { return ""; }
@@ -54,12 +59,12 @@ public final class ConjoinStep<S> extends ScalarMapStep<S, String> implements Li
for (Object elem : elements) {
if (elem != null) {
- joinResult.append(String.valueOf(elem)).append(delimiter);
+ joinResult.append(elem).append(delimiter.get());
}
}
if (joinResult.length() != 0) {
- joinResult.delete(joinResult.length() - delimiter.length(), joinResult.length());
+ joinResult.delete(joinResult.length() - delimiter.get().length(), joinResult.length());
return joinResult.toString();
} else {
return null;
@@ -67,6 +72,10 @@ public final class ConjoinStep<S> extends ScalarMapStep<S, String> implements Li
}
public String getDelimiter() {
+ return this.delimiter.get();
+ }
+
+ public GValue<String> getDelimiterGValue() {
return this.delimiter;
}
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 9434cc3b47..3646b599b2 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
@@ -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.traverser.TraverserRequirement;
import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
@@ -29,29 +30,36 @@ import java.util.Set;
public class ConstantStep<S, E> extends ScalarMapStep<S, E> {
- private final E constant;
+ private final GValue<E> constant;
public ConstantStep(final Traversal.Admin traversal, final E constant) {
+ this(traversal, constant instanceof GValue ? (GValue) constant : GValue.of(constant));
+ }
+
+ public ConstantStep(final Traversal.Admin traversal, final GValue<E> constant) {
super(traversal);
- this.constant = constant;
+ this.constant = null == constant ? GValue.of(null) : constant;
}
public E getConstant() {
+ return this.constant.get();
+ }
+ public GValue<E> getConstantGValue() {
return this.constant;
}
@Override
protected E map(final Traverser.Admin<S> traverser) {
- return this.constant;
+ return this.constant.get();
}
@Override
public String toString() {
- return StringFactory.stepString(this, this.constant);
+ return StringFactory.stepString(this, this.constant.get());
}
@Override
public int hashCode() {
- return super.hashCode() ^ Objects.hashCode(this.constant);
+ return super.hashCode() ^ Objects.hashCode(this.constant.get());
}
}
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..27922b984e 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,37 @@ 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 Object getParameterItems() {
+ return parameterItems;
+ }
+
+ public GValue<Object> getParameterItemsGValue() {
+ 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..c82eac3f64 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);
}
}
@@ -51,7 +53,11 @@ public final class DisjunctStep<S, E> extends ScalarMapStep<S, Set<?>> implement
}
public Object getParameterItems() {
- return this.parameterItems;
+ return parameterItems;
+ }
+
+ public GValue<Object> getParameterItemsGValue() {
+ return parameterItems;
}
@Override
@@ -60,7 +66,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/GraphStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GraphStep.java
index 3b1720ff9a..c009588864 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,6 +25,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.GraphComputing;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.AbstractStep;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer;
@@ -42,7 +43,9 @@ 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.Optional;
import java.util.function.Supplier;
/**
@@ -53,7 +56,8 @@ public class GraphStep<S, E extends Element> extends AbstractStep<S, E> implemen
protected Parameters parameters = new Parameters();
protected final Class<E> returnClass;
- protected Object[] ids;
+ protected GValue<?>[] ids;
+ protected boolean legacyLogicForPassingNoIds = false;
protected transient Supplier<Iterator<E>> iteratorSupplier;
protected boolean isStart;
protected boolean done = false;
@@ -64,11 +68,40 @@ public class GraphStep<S, E extends Element> extends AbstractStep<S, E> implemen
public GraphStep(final Traversal.Admin traversal, final Class<E> returnClass, final boolean isStart, final Object... ids) {
super(traversal);
this.returnClass = returnClass;
- this.ids = (ids != null && ids.length == 1 && ids[0] instanceof Collection) ? ((Collection) ids[0]).toArray(new Object[((Collection) ids[0]).size()]) : ids;
+
+ // if ids is a single collection like g.V(['a','b','c']), then unroll it into an array of ids
+ this.ids = GValue.ensureGValues(tryUnrollSingleCollectionArgument(ids));
+
this.isStart = isStart;
+
this.iteratorSupplier = () -> (Iterator<E>) (Vertex.class.isAssignableFrom(this.returnClass) ?
- this.getTraversal().getGraph().get().vertices(this.ids) :
- this.getTraversal().getGraph().get().edges(this.ids));
+ this.getTraversal().getGraph().get().vertices(GValue.resolveToValues(this.ids)) :
+ this.getTraversal().getGraph().get().edges(GValue.resolveToValues(this.ids)));
+ }
+
+ /**
+ * Unrolls a single collection argument into an array of ids. This is useful for steps like
+ * {@code g.V(['a','b','c'])}.
+ */
+ protected static Object[] tryUnrollSingleCollectionArgument(final Object[] ids) {
+ final Object[] tempIds;
+ if (ids != null && ids.length == 1) {
+ final Optional<Collection> opt;
+ if (ids[0] instanceof GValue && ((GValue<?>) ids[0]).getType().isCollection())
+ opt = Optional.of((Collection) ((GValue) ids[0]).get());
+ else if (ids[0] instanceof Collection)
+ opt = Optional.of((Collection) ids[0]);
+ else
+ opt = Optional.empty();
+
+ if (opt.isPresent()) {
+ tempIds = opt.get().toArray(new Object[opt.get().size()]);
+ } else
+ tempIds = ids;
+ } else {
+ tempIds = ids;
+ }
+ return tempIds;
}
public String toString() {
@@ -109,24 +142,39 @@ public class GraphStep<S, E extends Element> extends AbstractStep<S, E> implemen
this.iteratorSupplier = iteratorSupplier;
}
- public Object[] getIds() {
+ /**
+ * Get the ids associated with this step. If there are {@link GValue} objects present they will be returned
+ * alongside literal ids. Prefer {@link #getIdsAsValues()} if you prefer to work with literal ids only.
+ */
+ public GValue[] getIds() {
return this.ids;
}
+ /**
+ * Gets the ids associated with this step as literal values rather than {@link GValue} objects.
+ */
+ public Object[] getIdsAsValues() {
+ if (legacyLogicForPassingNoIds) return null;
+ return GValue.resolveToValues(this.ids);
+ }
+
public void addIds(final Object... newIds) {
- if ((this.ids == null || this.ids.length == 0) &&
- newIds.length == 1 &&
- newIds[0] instanceof Collection && ((Collection) newIds[0]).isEmpty())
- this.ids = null;
- else
- this.ids = ArrayUtils.addAll(this.ids,
- (newIds.length == 1 && newIds[0] instanceof Collection) ?
- ((Collection) newIds[0]).toArray(new Object[((Collection) newIds[0]).size()]) :
- newIds);
+ // there is some logic that has been around for a long time that used to set ids to null. it only happened here
+ // in this method and only occurred when the ids were already null or empty and the newIds were length 1 and
+ // an instance of List and that list was empty. so basically it would trigger for something like g.V().hasId([])
+ // which in turn would trigger an empty iterator in TinkerGraphStep and zero results. trying to maintain that
+ // logic now with GValue in the mix is tough because the context of what the meaning is gets lost by the time
+ // you get to calling getResolvedIds(). using a flag to try to maintain that legacy logic, but ultimately, all
+ // this needs to be rethought.
+ this.legacyLogicForPassingNoIds = newIds.length == 1 && ((newIds[0] instanceof List && ((List) newIds[0]).isEmpty()) ||
+ (newIds[0] instanceof GValue && ((GValue) newIds[0]).getType().isCollection() && ((List) ((GValue) newIds[0]).get()).isEmpty()));
+
+ final GValue[] gvalues = GValue.ensureGValues(tryUnrollSingleCollectionArgument(newIds));
+ this.ids = ArrayUtils.addAll(this.ids, gvalues);
}
public void clearIds() {
- this.ids = new Object[0];
+ this.ids = new GValue[0];
}
@Override
@@ -137,9 +185,12 @@ public class GraphStep<S, E extends Element> extends AbstractStep<S, E> implemen
public void convertElementsToIds() {
if (null != this.ids) {
- for (int i = 0; i < this.ids.length; i++) { // if this is going to OLAP, convert to ids so you don't serialize elements
- if (this.ids[i] instanceof Element)
- this.ids[i] = ((Element) this.ids[i]).id();
+ // if this is going to OLAP, convert to ids so you don't serialize elements
+ for (int i = 0; i < this.ids.length; i++) {
+ final GValue<?> current = this.ids[i];
+ if (current.getType().isElement()) {
+ this.ids[i] = GValue.of(current.getName(), ((Element) current.get()).id());
+ }
}
}
}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/IntersectStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/IntersectStep.java
index 651dec7502..3c37db29e0 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/IntersectStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/IntersectStep.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 IntersectStep<S, E> extends ScalarMapStep<S, Set<?>> implements TraversalParent, ListFunction {
private Traversal.Admin<S, E> valueTraversal;
- private Object parameterItems;
+ private GValue<Object> parameterItems;
public IntersectStep(final Traversal.Admin traversal, final Object values) {
super(traversal);
@@ -44,7 +45,7 @@ public final class IntersectStep<S, E> extends ScalarMapStep<S, Set<?>> implemen
if (values instanceof Traversal) {
valueTraversal = integrateChild(((Traversal<S, E>) values).asAdmin());
} else {
- parameterItems = values;
+ parameterItems = values instanceof GValue ? (GValue<Object>) values : GValue.of(values);
}
}
@@ -53,16 +54,20 @@ public final class IntersectStep<S, E> extends ScalarMapStep<S, Set<?>> implemen
}
public Object getParameterItems() {
- return this.parameterItems;
+ return parameterItems;
+ }
+
+ public GValue<Object> getParameterItemsGValue() {
+ return parameterItems;
}
@Override
public String getStepName() { return "intersect"; }
@Override
- protected Set<?> map(Traverser.Admin<S> traverser) {
+ protected Set<?> map(final Traverser.Admin<S> traverser) {
final Set setA = convertTraverserToSet(traverser);
- final Collection setB = (null != valueTraversal) ? convertTraversalToCollection(traverser, this.valueTraversal) : convertArgumentToCollection(parameterItems);
+ final Collection setB = (null != valueTraversal) ? convertTraversalToCollection(traverser, this.valueTraversal) : convertArgumentToCollection(parameterItems.get());
final Set intersection = new HashSet();
for (Object element : setB) {
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeEdgeStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeEdgeStep.java
index bb22d218e5..5beb203a24 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeEdgeStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeEdgeStep.java
@@ -34,6 +34,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
import org.apache.tinkerpop.gremlin.process.traversal.lambda.ConstantTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.event.EventUtil;
import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil;
import org.apache.tinkerpop.gremlin.structure.Direction;
@@ -71,6 +72,10 @@ public class MergeEdgeStep<S> extends MergeElementStep<S, Edge, Object> {
super(traversal, isStart, merge);
}
+ public MergeEdgeStep(final Traversal.Admin traversal, final boolean isStart, final GValue<Map> merge) {
+ super(traversal, isStart, merge);
+ }
+
public MergeEdgeStep(final Traversal.Admin traversal, final boolean isStart, final Traversal.Admin<S,Map> mergeTraversal) {
super(traversal, isStart, mergeTraversal);
}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeElementStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeElementStep.java
index 44e954fb31..6835387c5e 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeElementStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeElementStep.java
@@ -35,6 +35,8 @@ import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
import org.apache.tinkerpop.gremlin.process.traversal.lambda.ConstantTraversal;
import org.apache.tinkerpop.gremlin.process.traversal.lambda.IdentityTraversal;
import org.apache.tinkerpop.gremlin.process.traversal.step.Deleting;
+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.TraversalOptionParent;
import org.apache.tinkerpop.gremlin.process.traversal.step.Writing;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.Parameters;
@@ -80,6 +82,11 @@ public abstract class MergeElementStep<S, E, C> extends FlatMapStep<S, E>
validate(mergeMap, false);
}
+ public MergeElementStep(final Traversal.Admin traversal, final boolean isStart, final GValue<Map> mergeMap) {
+ this(traversal, isStart, new ConstantTraversal<>(mergeMap));
+ validate(mergeMap.get(), false);
+ }
+
public MergeElementStep(final Traversal.Admin traversal, final boolean isStart,
final Traversal.Admin mergeTraversal) {
super(traversal);
@@ -279,7 +286,7 @@ public abstract class MergeElementStep<S, E, C> extends FlatMapStep<S, E>
op, allowedTokens, k));
}
if (k == T.label) {
- if (!(v instanceof String)) {
+ if (!(GValue.instanceOf(v, GType.STRING))) {
throw new IllegalArgumentException(String.format(
"%s() and option(onCreate) args expect T.label value to be of String - found: %s", op,
v.getClass().getSimpleName()));
@@ -318,7 +325,8 @@ public abstract class MergeElementStep<S, E, C> extends FlatMapStep<S, E>
* null Map == empty Map
*/
protected Map materializeMap(final Traverser.Admin<S> traverser, Traversal.Admin<S, ?> mapTraversal) {
- Map map = (Map) TraversalUtil.apply(traverser, mapTraversal);
+ final Object o = TraversalUtil.apply(traverser, mapTraversal);
+ Map map = GValue.getFrom(o);
// PartitionStrategy uses parameters as a mechanism for setting the partition key. trying to be as specific
// as possible here wrt parameters usage to avoid misuse
@@ -360,7 +368,7 @@ public abstract class MergeElementStep<S, E, C> extends FlatMapStep<S, E>
return id != null ? graph.traversal().V(id) : graph.traversal().V();
}
- protected GraphTraversal searchVerticesLabelConstraint(GraphTraversal t, final String label) {
+ protected GraphTraversal searchVerticesLabelConstraint(final GraphTraversal t, final String label) {
return label != null ? t.hasLabel(label) : t;
}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeStep.java
index d11fdf0894..2f86240a42 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeStep.java
@@ -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;
@@ -40,7 +41,7 @@ import java.util.Set;
*/
public final class MergeStep<S, E> extends ScalarMapStep<S, E> implements TraversalParent, ListFunction {
private Traversal.Admin<S, E> valueTraversal;
- private Object parameterItems;
+ private GValue<Object> parameterItems;
public MergeStep(final Traversal.Admin traversal, final Object values) {
super(traversal);
@@ -48,10 +49,22 @@ public final class MergeStep<S, E> extends ScalarMapStep<S, E> implements Traver
if (values instanceof Traversal) {
valueTraversal = integrateChild(((Traversal<S, E>) values).asAdmin());
} else {
- parameterItems = values;
+ parameterItems = GValue.of(values);;
}
}
+ public Traversal.Admin<S, E> getValueTraversal() {
+ return valueTraversal;
+ }
+
+ public Object getParameterItems() {
+ return parameterItems;
+ }
+
+ public GValue<Object> getParameterItemsGValue() {
+ return parameterItems;
+ }
+
@Override
public String getStepName() { return "merge"; }
@@ -61,7 +74,7 @@ public final class MergeStep<S, E> extends ScalarMapStep<S, E> implements Traver
final Map mapA = (incoming instanceof Map) ? (Map) incoming : null;
if (mapA != null) {
- final Object mapB = (valueTraversal != null) ? TraversalUtil.apply(traverser, valueTraversal) : parameterItems;
+ final Object mapB = (valueTraversal != null) ? TraversalUtil.apply(traverser, valueTraversal) : parameterItems.get();
if (!(mapB instanceof Map)) {
throw new IllegalArgumentException(
String.format(
@@ -76,13 +89,13 @@ public final class MergeStep<S, E> extends ScalarMapStep<S, E> implements Traver
} else {
final Collection listA = convertTraverserToCollection(traverser);
- if (parameterItems 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)
- : convertArgumentToCollection(parameterItems);
+ : convertArgumentToCollection(parameterItems.get());
final Set elements = new HashSet();
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeVertexStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeVertexStep.java
index 9aab3790ac..e15ff745bc 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeVertexStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeVertexStep.java
@@ -30,6 +30,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
import org.apache.tinkerpop.gremlin.process.traversal.lambda.CardinalityValueTraversal;
import org.apache.tinkerpop.gremlin.process.traversal.lambda.ConstantTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.event.EventUtil;
import org.apache.tinkerpop.gremlin.structure.Graph;
import org.apache.tinkerpop.gremlin.structure.T;
@@ -60,6 +61,10 @@ public class MergeVertexStep<S> extends MergeElementStep<S, Vertex, Map> {
super(traversal, isStart, merge);
}
+ public MergeVertexStep(final Traversal.Admin traversal, final boolean isStart, final GValue<Map> merge) {
+ super(traversal, isStart, merge);
+ }
+
public MergeVertexStep(final Traversal.Admin traversal, final boolean isStart, final Traversal.Admin<S,Map> mergeTraversal) {
super(traversal, isStart, mergeTraversal);
}
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..a07b204190 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,29 @@ 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 Object getParameterItems() {
+ return parameterItems;
+ }
+
+ public GValue<Object> getParameterItemsGValue() {
+ 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/VertexStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/VertexStep.java
index bd429f049c..b6230e0538 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/VertexStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/VertexStep.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.Configuring;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.Parameters;
import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
import org.apache.tinkerpop.gremlin.structure.Direction;
@@ -39,20 +40,31 @@ import java.util.Set;
import java.util.stream.Collectors;
/**
+ * Handles the logic of traversing to adjacent vertices or edges given a direction and edge labels for steps like,
+ * {@code out}, {@code in}, {@code both}, {@code outE}, {@code inE}, and {@code bothE}.
+ *
* @author Marko A. Rodriguez (http://markorodriguez.com)
*/
public class VertexStep<E extends Element> extends FlatMapStep<Vertex, E> implements AutoCloseable, Configuring {
protected Parameters parameters = new Parameters();
private final String[] edgeLabels;
+ private final GValue<String>[] edgeLabelsGValue;
private Direction direction;
private final Class<E> returnClass;
public VertexStep(final Traversal.Admin traversal, final Class<E> returnClass, final Direction direction, final String... edgeLabels) {
+ this(traversal, returnClass, direction, GValue.ensureGValues(edgeLabels));
+ }
+
+ public VertexStep(final Traversal.Admin traversal, final Class<E> returnClass, final Direction direction, final GValue<String>... edgeLabels) {
super(traversal);
this.direction = direction;
- this.edgeLabels = edgeLabels;
this.returnClass = returnClass;
+ this.edgeLabelsGValue = edgeLabels;
+
+ // convert the GValue<String> to a String[] for the edgeLabels field to cache the values
+ this.edgeLabels = Arrays.stream(this.edgeLabelsGValue).map(GValue::get).toArray(String[]::new);
}
@Override
@@ -67,6 +79,9 @@ public class VertexStep<E extends Element> extends FlatMapStep<Vertex, E> implem
@Override
protected Iterator<E> flatMap(final Traverser.Admin<Vertex> traverser) {
+ // not passing GValue to graphs at this point. if a graph wants to support GValue, it should implement
+ // its own step to do so. in this way, we keep things backwards compatible and don't force folks to have
+ // deal with this until they are ready.
return Vertex.class.isAssignableFrom(this.returnClass) ?
(Iterator<E>) traverser.get().vertices(this.direction, this.edgeLabels) :
(Iterator<E>) traverser.get().edges(this.direction, this.edgeLabels);
@@ -80,6 +95,10 @@ public class VertexStep<E extends Element> extends FlatMapStep<Vertex, E> implem
return this.edgeLabels;
}
+ public GValue<String>[] getEdgeLabelsGValue() {
+ return this.edgeLabelsGValue;
+ }
+
public Class<E> getReturnClass() {
return this.returnClass;
}
@@ -88,10 +107,16 @@ public class VertexStep<E extends Element> extends FlatMapStep<Vertex, E> implem
this.direction = this.direction.opposite();
}
+ /**
+ * Determines if the step returns vertices.
+ */
public boolean returnsVertex() {
return this.returnClass.equals(Vertex.class);
}
+ /**
+ * Determines if the step returns edges.
+ */
public boolean returnsEdge() {
return this.returnClass.equals(Edge.class);
}
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 0502f18541..fa27d5af92 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
@@ -19,6 +19,7 @@
package org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect;
import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
import org.apache.tinkerpop.gremlin.util.iterator.ArrayIterator;
/**
@@ -26,29 +27,39 @@ import org.apache.tinkerpop.gremlin.util.iterator.ArrayIterator;
*/
public final class InjectStep<S> extends StartStep<S> {
- private final S[] injections;
+ private final GValue<S>[] injections;
@SafeVarargs
public InjectStep(final Traversal.Admin traversal, final S... injections) {
super(traversal);
- this.injections = injections;
- this.start = new ArrayIterator<>(this.injections);
+ this.injections = GValue.ensureGValues(injections);
+ this.start = new ArrayIterator<>(GValue.resolveToValues(this.injections));
}
@Override
public InjectStep<S> clone() {
final InjectStep<S> clone = (InjectStep<S>) super.clone();
- clone.start = new ArrayIterator<>(clone.injections);
+ clone.start = new ArrayIterator<>(GValue.resolveToValues(clone.injections));
return clone;
}
@Override
public void reset() {
super.reset();
- this.start = new ArrayIterator<>(this.injections);
+ this.start = new ArrayIterator<>(GValue.resolveToValues(this.injections));
}
- public S[] getInjections() {
+ /**
+ * Get the injections of the step.
+ */
+ public GValue<S>[] getInjectionsGValue() {
return this.injections;
}
+
+ /**
+ * Gets the injections of the step but unwraps the {@link GValue}.
+ */
+ public S[] getInjections() {
+ return (S[]) GValue.resolveToValues(this.injections);
+ }
}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/AbstractStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/AbstractStep.java
index d4545ead5c..f0af790c73 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/AbstractStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/AbstractStep.java
@@ -27,6 +27,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.util.EmptyTraversal;
import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalInterruptedException;
import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
+import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashSet;
@@ -228,5 +229,4 @@ public abstract class AbstractStep<S, E> implements Step<S, E> {
}
return traverser;
}
-
}
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 c20c68fde0..35689f8367 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,10 +19,12 @@
package org.apache.tinkerpop.gremlin.process.traversal.step.util;
import org.apache.tinkerpop.gremlin.process.traversal.P;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GType;
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.process.traversal.step.GValue;
import java.io.Serializable;
import java.util.Collection;
@@ -154,11 +156,11 @@ public class HasContainer implements Serializable, Cloneable, Predicate<Element>
if (predicateValue instanceof Collection) {
final Collection collection = (Collection) predicateValue;
if (!collection.isEmpty()) {
- return ((Collection) predicateValue).stream().allMatch(c -> null == c || c instanceof String);
+ return ((Collection) predicateValue).stream().allMatch(c -> null == c || GValue.instanceOf(c, GType.STRING));
}
}
- return predicateValue instanceof String;
+ return GValue.instanceOf(predicateValue, GType.STRING);
}
return false;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/Parameters.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/Parameters.java
index d1654a344e..9b4a926c74 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/Parameters.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/Parameters.java
@@ -22,6 +22,7 @@ package org.apache.tinkerpop.gremlin.process.traversal.step.util;
import org.apache.commons.lang3.ArrayUtils;
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.Scoping;
import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil;
@@ -165,7 +166,7 @@ public class Parameters implements Cloneable, Serializable {
/**
* Gets the array of keys/values of the parameters while resolving parameter values that contain
- * {@link Traversal} instances.
+ * {@link Traversal} or {@link GValue} instances.
*/
public <S> Object[] getKeyValues(final Traverser.Admin<S> traverser, final Object... exceptKeys) {
if (this.parameters.isEmpty()) return EMPTY_ARRAY;
@@ -173,14 +174,28 @@ public class Parameters implements Cloneable, Serializable {
for (final Map.Entry<Object, List<Object>> entry : this.parameters.entrySet()) {
if (!ArrayUtils.contains(exceptKeys, entry.getKey())) {
for (final Object value : entry.getValue()) {
- keyValues.add(entry.getKey() instanceof Traversal.Admin ? TraversalUtil.apply(traverser, (Traversal.Admin<S, ?>) entry.getKey()) : entry.getKey());
- keyValues.add(value instanceof Traversal.Admin ? TraversalUtil.apply(traverser, (Traversal.Admin<S, ?>) value) : value);
+ keyValues.add(resolve(entry.getKey(), traverser));
+ keyValues.add(resolve(value, traverser));
}
}
}
return keyValues.toArray(new Object[keyValues.size()]);
}
+ /**
+ * Takes an object and tests if it is a {@link GValue} or a {@link Traversal} and if so, resolves it to its value
+ * otherwise it just returns itself.
+ */
+ private static <S> Object resolve(final Object object, final Traverser.Admin<S> traverser) {
+ if (object instanceof Traversal.Admin) {
+ return TraversalUtil.apply(traverser, (Traversal.Admin<S, ?>) object);
+ } else if (object instanceof GValue) {
+ return ((GValue) object).get();
+ } else {
+ return object;
+ }
+ }
+
/**
* Gets an immutable set of the parameters without evaluating them in the context of a {@link Traverser} as
* is done in {@link #getKeyValues(Traverser.Admin, Object...)}.
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/ElementIdStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/ElementIdStrategy.java
index 67c08254a8..e47b782185 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/ElementIdStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/ElementIdStrategy.java
@@ -94,11 +94,12 @@ public final class ElementIdStrategy extends AbstractTraversalStrategy<Traversal
// note that it is then only necessary to replace the step if the id is a non-element. other tests
// in the suite validate that items in getIds() is uniform so it is ok to just test the first item
// in the list.
- if (graphStep.getIds().length > 0 && !(graphStep.getIds()[0] instanceof Element)) {
+ final Object[] ids = graphStep.getIdsAsValues();
+ if (ids.length > 0 && !(ids[0] instanceof Element)) {
if (graphStep instanceof HasContainerHolder)
- ((HasContainerHolder) graphStep).addHasContainer(new HasContainer(this.idPropertyKey, P.within(Arrays.asList(graphStep.getIds()))));
+ ((HasContainerHolder) graphStep).addHasContainer(new HasContainer(this.idPropertyKey, P.within(Arrays.asList(ids))));
else
- TraversalHelper.insertAfterStep(new HasStep(traversal, new HasContainer(this.idPropertyKey, P.within(Arrays.asList(graphStep.getIds())))), graphStep, traversal);
+ TraversalHelper.insertAfterStep(new HasStep(traversal, new HasContainer(this.idPropertyKey, P.within(Arrays.asList(ids)))), graphStep, traversal);
graphStep.clearIds();
}
}
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-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategy.java
index 6f34d62226..b44b62f0e3 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategy.java
@@ -193,7 +193,7 @@ public final class SubgraphStrategy extends AbstractTraversalStrategy<TraversalS
continue;
if (edgeCriterion != null) {
- final VertexStep<Edge> someEStep = new VertexStep<>(traversal, Edge.class, step.getDirection(), step.getEdgeLabels());
+ final VertexStep<Edge> someEStep = new VertexStep<>(traversal, Edge.class, step.getDirection(), step.getEdgeLabelsGValue());
final Step<Edge, Vertex> someVStep = step.getDirection() == Direction.BOTH ?
new EdgeOtherVertexStep(traversal) :
new EdgeVertexStep(traversal, step.getDirection().opposite());
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/AdjacentToIncidentStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/AdjacentToIncidentStrategy.java
index d8e538ab37..b33d527c2c 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/AdjacentToIncidentStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/AdjacentToIncidentStrategy.java
@@ -118,7 +118,7 @@ public final class AdjacentToIncidentStrategy extends AbstractTraversalStrategy<
final Step newStep;
if (step instanceof VertexStep) {
final VertexStep vs = (VertexStep) step;
- newStep = new VertexStep<>(traversal, Edge.class, vs.getDirection(), vs.getEdgeLabels());
+ newStep = new VertexStep<>(traversal, Edge.class, vs.getDirection(), vs.getEdgeLabelsGValue());
} else if (step instanceof PropertiesStep) {
final PropertiesStep ps = (PropertiesStep) step;
newStep = new PropertiesStep(traversal, PropertyType.PROPERTY, ps.getPropertyKeys());
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/IncidentToAdjacentStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/IncidentToAdjacentStrategy.java
index 75d55adcd0..813b60b955 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/IncidentToAdjacentStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/IncidentToAdjacentStrategy.java
@@ -110,7 +110,7 @@ public final class IncidentToAdjacentStrategy extends AbstractTraversalStrategy<
* @param step2 the vertex-emitting step to replace
*/
private static void optimizeSteps(final Traversal.Admin traversal, final VertexStep step1, final Step step2) {
- final Step newStep = new VertexStep(traversal, Vertex.class, step1.getDirection(), step1.getEdgeLabels());
+ final Step newStep = new VertexStep(traversal, Vertex.class, step1.getDirection(), step1.getEdgeLabelsGValue());
for (final String label : (Iterable<String>) step2.getLabels()) {
newStep.addLabel(label);
}
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 d2713218c5..e8b154fef6 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
@@ -26,6 +26,8 @@ import org.apache.tinkerpop.gremlin.process.traversal.P;
import org.apache.tinkerpop.gremlin.process.traversal.Step;
import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GType;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
import org.apache.tinkerpop.gremlin.process.traversal.step.LambdaHolder;
import org.apache.tinkerpop.gremlin.process.traversal.step.filter.AndStep;
import org.apache.tinkerpop.gremlin.process.traversal.step.filter.DedupGlobalStep;
@@ -124,26 +126,25 @@ public final class InlineFilterStrategy extends AbstractTraversalStrategy<Traver
&& ((VertexStep) step.getPreviousStep()).returnsEdge()
&& 0 == ((VertexStep) step.getPreviousStep()).getEdgeLabels().length) {
final VertexStep<Edge> previousStep = (VertexStep<Edge>) step.getPreviousStep();
- final List<String> edgeLabels = new ArrayList<>();
+ final List<Object> edgeLabels = new ArrayList<>();
for (final HasContainer hasContainer : new ArrayList<>(step.getHasContainers())) {
if (hasContainer.getKey().equals(T.label.getAccessor())) {
- if (hasContainer.getBiPredicate() == Compare.eq &&
- hasContainer.getValue() instanceof String &&
+ if (hasContainer.getBiPredicate() == Compare.eq && GValue.instanceOf(hasContainer.getValue(), GType.STRING) &&
edgeLabels.isEmpty()) {
- edgeLabels.add((String) hasContainer.getValue());
+ edgeLabels.add(hasContainer.getValue());
step.removeHasContainer(hasContainer);
} else if (hasContainer.getBiPredicate() == Contains.within &&
hasContainer.getValue() instanceof Collection &&
((Collection) hasContainer.getValue()).containsAll(edgeLabels)) {
- edgeLabels.addAll((Collection<String>) hasContainer.getValue());
+ edgeLabels.addAll((Collection) hasContainer.getValue());
step.removeHasContainer(hasContainer);
} else if (hasContainer.getPredicate() instanceof OrP && edgeLabels.isEmpty()) {
boolean removeContainer = true;
final List<P<?>> orps = ((OrP) hasContainer.getPredicate()).getPredicates();
- final List<String> newEdges = new ArrayList<>();
+ final List<Object> newEdges = new ArrayList<>();
for (int i = 0; i < orps.size(); i++) {
- if (orps.get(i).getBiPredicate() == Compare.eq && orps.get(i).getValue() instanceof String)
- newEdges.add((String) orps.get(i).getValue());
+ if (orps.get(i).getBiPredicate() == Compare.eq && GValue.instanceOf(orps.get(i).getValue(), GType.STRING))
+ newEdges.add(orps.get(i).getValue());
else {
removeContainer = false;
break;
@@ -157,7 +158,7 @@ public final class InlineFilterStrategy extends AbstractTraversalStrategy<Traver
}
}
if (!edgeLabels.isEmpty()) {
- final VertexStep<Edge> newVertexStep = new VertexStep<>(traversal, Edge.class, previousStep.getDirection(), edgeLabels.toArray(new String[edgeLabels.size()]));
+ final VertexStep<Edge> newVertexStep = new VertexStep<>(traversal, Edge.class, previousStep.getDirection(), GValue.ensureGValues(edgeLabels.toArray()));
TraversalHelper.replaceStep(previousStep, newVertexStep, traversal);
TraversalHelper.copyLabels(previousStep, newVertexStep, false);
if (step.getHasContainers().isEmpty()) {
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ListFunction.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ListFunction.java
index ab693b9e29..5bf91c41e8 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ListFunction.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ListFunction.java
@@ -39,7 +39,7 @@ public interface ListFunction {
* @param iterable an Iterable or array.
* @return The iterable type as a Collection or null if argument isn't iterable.
*/
- public static Collection asCollection(Object iterable) {
+ public static Collection asCollection(final Object iterable) {
if (iterable instanceof Collection) {
return (Collection) iterable;
} else if ((iterable != null && iterable.getClass().isArray()) || iterable instanceof Iterable) {
@@ -56,7 +56,7 @@ public interface ListFunction {
* @param iterable an Iterable or array.
* @return The iterable type as a Collection or null if argument isn't iterable.
*/
- public static Set asSet(Object iterable) {
+ public static Set asSet(final Object iterable) {
if (iterable instanceof Iterable || iterable != null && iterable.getClass().isArray()) {
return IteratorUtils.asSet(iterable);
} else {
@@ -71,7 +71,7 @@ public interface ListFunction {
*/
public String getStepName();
- public default Collection convertArgumentToCollection(Object arg) {
+ public default Collection convertArgumentToCollection(final Object arg) {
if (null == arg) {
throw new IllegalArgumentException(
String.format("Argument provided for %s step can't be null.", getStepName()));
@@ -90,7 +90,7 @@ public interface ListFunction {
return incoming;
}
- public default <S> Collection convertTraverserToCollection(Traverser.Admin<S> traverser) {
+ public default <S> Collection convertTraverserToCollection(final Traverser.Admin<S> traverser) {
final S items = traverser.get();
if (null == items) {
@@ -111,7 +111,7 @@ public interface ListFunction {
return incoming;
}
- public default <S, E> Collection convertTraversalToCollection(Traverser.Admin<S> traverser, final Traversal.Admin<S, E> traversal) {
+ public default <S, E> Collection convertTraversalToCollection(final Traverser.Admin<S> traverser, final Traversal.Admin<S, E> traversal) {
final Object array = TraversalUtil.apply(traverser, traversal);
if (null == array) {
@@ -134,7 +134,7 @@ public interface ListFunction {
return input;
}
- public default Set convertArgumentToSet(Object arg) {
+ public default Set convertArgumentToSet(final Object arg) {
if (null == arg) {
throw new IllegalArgumentException(
String.format("Argument provided for %s step can't be null.", getStepName()));
@@ -153,7 +153,7 @@ public interface ListFunction {
return incoming;
}
- public default <S> Set convertTraverserToSet(Traverser.Admin<S> traverser) {
+ public default <S> Set convertTraverserToSet(final Traverser.Admin<S> traverser) {
final S items = traverser.get();
if (null == items) {
@@ -174,7 +174,7 @@ public interface ListFunction {
return incoming;
}
- public default <S, E> Set convertTraversalToSet(Traverser.Admin<S> traverser, final Traversal.Admin<S, E> traversal) {
+ public default <S, E> Set convertTraversalToSet(final Traverser.Admin<S> traverser, final Traversal.Admin<S, E> traversal) {
final Object array = TraversalUtil.apply(traverser, traversal);
if (null == array) {
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/VertexProperty.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/VertexProperty.java
index af7a18a1d9..962140adb5 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/VertexProperty.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/VertexProperty.java
@@ -18,9 +18,6 @@
*/
package org.apache.tinkerpop.gremlin.structure;
-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.dsl.graph.__;
import org.apache.tinkerpop.gremlin.process.traversal.lambda.CardinalityValueTraversal;
import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyVertexProperty;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java
index b06509a4b0..7fa37b5acb 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java
@@ -38,6 +38,8 @@ import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions;
import org.apache.tinkerpop.gremlin.process.traversal.Scope;
import org.apache.tinkerpop.gremlin.process.traversal.Text;
import org.apache.tinkerpop.gremlin.process.traversal.TextP;
+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.filter.RangeGlobalStep;
import org.apache.tinkerpop.gremlin.process.traversal.step.map.FoldStep;
import org.apache.tinkerpop.gremlin.process.traversal.step.map.GroupCountStep;
@@ -325,7 +327,7 @@ public enum GryoVersion {
add(GryoTypeReg.of(P.class, 124, new GryoSerializersV3.PSerializer()));
add(GryoTypeReg.of(TextP.class, 186, new GryoSerializersV3.TextPSerializer()));
- add(GryoTypeReg.of(Text.RegexPredicate.class, 197)); // ***LAST ID***
+ add(GryoTypeReg.of(Text.RegexPredicate.class, 197));
add(GryoTypeReg.of(Lambda.class, 125, new GryoSerializersV3.LambdaSerializer()));
add(GryoTypeReg.of(Order.class, 127));
add(GryoTypeReg.of(Scope.class, 128));
@@ -422,6 +424,9 @@ public enum GryoVersion {
add(GryoTypeReg.of(Stack.class, 181));
add(GryoTypeReg.of(ReferenceMap.class, 182));
+ add(GryoTypeReg.of(GValue.class, 199, new JavaSerializer()));
+ add(GryoTypeReg.of(GType.class, 200, new JavaSerializer())); // ***LAST ID***
+
// placeholder serializers for classes that don't live here in core. this will allow them to be used if
// present or ignored if the class isn't available. either way the registration numbers are held as
// placeholders so that the format stays stable
@@ -538,7 +543,7 @@ public enum GryoVersion {
add(GryoTypeReg.of(Pop.class, 133));
add(GryoTypeReg.of(SackFunctions.Barrier.class, 135));
add(GryoTypeReg.of(Pick.class, 137));
- add(GryoTypeReg.of(DT.class, 198)); // ***LAST ID***
+ add(GryoTypeReg.of(DT.class, 198));
add(GryoTypeReg.of(Merge.class, 196));
add(GryoTypeReg.of(HashSetSupplier.class, 136, new UtilSerializers.HashSetSupplierSerializer()));
add(GryoTypeReg.of(MultiComparator.class, 165));
@@ -629,6 +634,9 @@ public enum GryoVersion {
add(GryoTypeReg.of(LabelledCounter.class, 180));
add(GryoTypeReg.of(Stack.class, 181));
add(GryoTypeReg.of(ReferenceMap.class, 182));
+
+ add(GryoTypeReg.of(GValue.class, 199, new JavaSerializer()));
+ add(GryoTypeReg.of(GType.class, 200, new JavaSerializer())); // ***LAST ID***
}};
}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/CollectionUtil.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/CollectionUtil.java
index 1242d16af7..27d41d8e18 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/CollectionUtil.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/CollectionUtil.java
@@ -19,6 +19,9 @@
package org.apache.tinkerpop.gremlin.util;
+import org.apache.commons.lang3.ArrayUtils;
+
+import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -29,22 +32,36 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+/**
+ * Utility class for working with collections and arrays.
+ */
public final class CollectionUtil {
- private CollectionUtil() {
- }
+ private CollectionUtil() { }
+ /**
+ * Converts varargs to a {@code List}.
+ */
public static <E> List<E> asList(final E... elements) {
return new ArrayList<>(Arrays.asList(elements));
}
+ /**
+ * Converts varargs to a {@code Set}.
+ */
public static <E> LinkedHashSet<E> asSet(final E... elements) {
return asSet(Arrays.asList(elements));
}
+ /**
+ * Converts {@code Collection} to a {@code Set}.
+ */
public static <E> LinkedHashSet<E> asSet(final Collection<E> elements) {
return new LinkedHashSet<>(elements);
}
+ /**
+ * Converts varargs to a {@code Map} where the elements are key/value pairs.
+ */
public static <K,V> LinkedHashMap<K,V> asMap(final Object... elements) {
final LinkedHashMap<K,V> map = new LinkedHashMap<>();
for (int i = 0; i < elements.length; i+=2) {
@@ -55,6 +72,11 @@ public final class CollectionUtil {
return map;
}
+ /**
+ * Clones a given {@code ConcurrentHashMap} by creating a new map and copying all entries from the original map.
+ * If the value of an entry is a {@code Set} or an {@code ArrayList}, a deep copy of the value is created.
+ * Otherwise, the value is copied as is.
+ */
public static <K,V> ConcurrentHashMap<K,V> clone(final ConcurrentHashMap<K,V> map) {
final ConcurrentHashMap<K, V> result = new ConcurrentHashMap<>(map.size());
@@ -74,4 +96,22 @@ public final class CollectionUtil {
return result;
}
+
+ /**
+ * Adds the element argument to the start of the supplied array argument, but if the array is null then return the
+ * element as a new array with just that item in it.
+ */
+ public static <T> T[] addFirst(final T[] array, final T element, final Class<T> clazz) {
+ if (null == array && null == element) {
+ final T[] singleElementArray = (T[]) Array.newInstance(clazz, 1);
+ singleElementArray[0] = null;
+ return singleElementArray;
+ } else if (null == array) {
+ final T[] singleElementArray = (T[]) Array.newInstance(clazz, 1);
+ singleElementArray[0] = element;
+ return singleElementArray;
+ } else {
+ return ArrayUtils.addFirst(array, element);
+ }
+ }
}
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/jsr223/VariableResolverPluginTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/jsr223/VariableResolverPluginTest.java
new file mode 100644
index 0000000000..0d3dc5fd96
--- /dev/null
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/jsr223/VariableResolverPluginTest.java
@@ -0,0 +1,117 @@
+/*
+ * 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.jsr223;
+
+import org.apache.tinkerpop.gremlin.language.grammar.GremlinParser;
+import org.apache.tinkerpop.gremlin.language.grammar.VariableResolver;
+import org.junit.Test;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.IsInstanceOf.instanceOf;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.fail;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class VariableResolverPluginTest {
+
+ @Test
+ public void shouldProduceNullVariableResolver() {
+ final Map<String, Object> bindings = new HashMap<>();
+ final VariableResolverPlugin plugin = VariableResolverPlugin.build().
+ resolver(VariableResolver.NullVariableResolver.class.getSimpleName()).create();
+ final VariableResolver resolver = ((VariableResolverCustomizer) plugin.getCustomizers().
+ get()[0]).getVariableResolverMaker().apply(bindings);
+ assertThat(resolver, instanceOf(VariableResolver.NullVariableResolver.class));
+ }
+
+ @Test
+ public void shouldProduceNoVariableResolver() {
+ final Map<String, Object> bindings = new HashMap<>();
+ final VariableResolverPlugin plugin = VariableResolverPlugin.build().
+ resolver(VariableResolver.NoVariableResolver.class.getSimpleName()).create();
+ final VariableResolver resolver = ((VariableResolverCustomizer) plugin.getCustomizers().
+ get()[0]).getVariableResolverMaker().apply(bindings);
+ assertThat(resolver, instanceOf(VariableResolver.NoVariableResolver.class));
+ }
+
+ @Test
+ public void shouldProduceDefaultVariableResolver() {
+ final Map<String, Object> bindings = new HashMap<>();
+ final VariableResolverPlugin plugin = VariableResolverPlugin.build().
+ resolver(VariableResolver.DefaultVariableResolver.class.getSimpleName()).create();
+ final VariableResolver resolver = ((VariableResolverCustomizer) plugin.getCustomizers().
+ get()[0]).getVariableResolverMaker().apply(bindings);
+ assertThat(resolver, instanceOf(VariableResolver.DefaultVariableResolver.class));
+ }
+
+ @Test
+ public void shouldProduceDirectVariableResolver() {
+ final Map<String, Object> bindings = new HashMap<>();
+ final VariableResolverPlugin plugin = VariableResolverPlugin.build().
+ resolver(VariableResolver.DirectVariableResolver.class.getSimpleName()).create();
+ final VariableResolver resolver = ((VariableResolverCustomizer) plugin.getCustomizers().
+ get()[0]).getVariableResolverMaker().apply(bindings);
+ assertThat(resolver, instanceOf(VariableResolver.DirectVariableResolver.class));
+ }
+
+ @Test
+ public void shouldProduceDefaultedVariableResolverWhenNoSpecified() {
+ final Map<String, Object> bindings = new HashMap<>();
+ final VariableResolverPlugin plugin = VariableResolverPlugin.build().create();
+ final VariableResolver resolver = ((VariableResolverCustomizer) plugin.getCustomizers().
+ get()[0]).getVariableResolverMaker().apply(bindings);
+ assertThat(resolver, instanceOf(VariableResolver.DirectVariableResolver.class));
+ }
+
+ @Test
+ public void shouldProduceCustomVariableResolverForFullyQualifiedClassName() {
+ final Map<String, Object> bindings = new HashMap<>();
+ final VariableResolverPlugin plugin = VariableResolverPlugin.build().
+ resolver(CustomVariableResolver.class.getName()).create();
+ final VariableResolver resolver = ((VariableResolverCustomizer) plugin.getCustomizers().
+ get()[0]).getVariableResolverMaker().apply(bindings);
+ assertThat(resolver, instanceOf(CustomVariableResolver.class));
+ }
+
+ @Test
+ public void shouldProduceExceptionVariableResolverIfResolverNotFound() {
+ try {
+ final VariableResolverPlugin plugin = VariableResolverPlugin.build().
+ resolver("NotAResolver").create();
+ fail("The resolver does not exist and should have failed");
+ } catch (Exception re) {
+ assertThat(re.getMessage(), containsString("VariableResolver class not found: NotAResolver"));
+ }
+ }
+
+ /**
+ * Custom test implementation of {@link VariableResolver} that is not part of the standard set of implementations.
+ * This class does nothing.
+ */
+ public static class CustomVariableResolver implements VariableResolver<Object> {
+ public CustomVariableResolver(final Map<String, Object> m) {
+ }
+
+ @Override
+ public Object apply(final String varName, final GremlinParser.VariableContext variableContext) {
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/ArgumentVisitorTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/ArgumentVisitorTest.java
index 4dd0af45c6..6a665787d3 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/ArgumentVisitorTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/ArgumentVisitorTest.java
@@ -84,58 +84,56 @@ public class ArgumentVisitorTest {
public static Iterable<Object[]> generateTestParameters() {
return Arrays.asList(new Object[][]{
{Boolean.class, "x", new VariableResolverException("x"), createAntlr(VariableResolver.NoVariableResolver.instance())},
- {Boolean.class, "true", true, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", true)))},
- {Boolean.class, "false", false, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", true)))},
- {Boolean.class, "x", true, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", true)))},
+ {Boolean.class, "true", true, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", true)))},
+ {Boolean.class, "false", false, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", true)))},
+ {Boolean.class, "x", true, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", true)))},
{Integer.class, "x", new VariableResolverException("x"), createAntlr(VariableResolver.NoVariableResolver.instance())},
- {Integer.class, "0", 0, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 100)))},
- {Integer.class, "0i", 0, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 100)))},
- {Integer.class, "0L", 0L, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 100)))},
- {Integer.class, "x", 0, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 0)))},
- {Integer.class, "x", 0L, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 0L)))},
+ {Integer.class, "0", 0, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", 100)))},
+ {Integer.class, "0i", 0, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", 100)))},
+ {Integer.class, "0L", 0L, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", 100)))},
+ {Integer.class, "x", 0, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", 0)))},
+ {Integer.class, "x", 0L, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", 0L)))},
{Float.class, "x", new VariableResolverException("x"), createAntlr(VariableResolver.NoVariableResolver.instance())},
- {Float.class, "0.0d", 0.0, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 1000.0)))},
- {Float.class, "0d", 0.0, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 1000.0)))},
- {Float.class, "0F", 0.0F, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 1000.0F)))},
- {Float.class, "x", 0.0, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 0.0)))},
- {Float.class, "x", 0.0F, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 0.0F)))},
+ {Float.class, "0.0d", 0.0, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", 1000.0)))},
+ {Float.class, "0d", 0.0, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", 1000.0)))},
+ {Float.class, "0F", 0.0F, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", 1000.0F)))},
+ {Float.class, "x", 0.0, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", 0.0)))},
+ {Float.class, "x", 0.0F, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", 0.0F)))},
{String.class, "x", new VariableResolverException("x"), createAntlr(VariableResolver.NoVariableResolver.instance())},
- {String.class, "'test'", "test", createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
- {String.class, "x", "test", createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "test")))},
- {String.class, "x", "graphson", createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", IO.graphson)))},
+ {String.class, "'test'", "test", createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+ {String.class, "x", "test", createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "test")))},
+ {String.class, "x", "graphson", createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", IO.graphson)))},
{StringNullable.class, "x", new VariableResolverException("x"), createAntlr(VariableResolver.NoVariableResolver.instance())},
- {StringNullable.class, "null", null, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
- {StringNullable.class, "x", null, createAntlr(new VariableResolver.DefaultVariableResolver(nullMap))},
+ {StringNullable.class, "null", null, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+ {StringNullable.class, "x", null, createAntlr(new VariableResolver.DirectVariableResolver(nullMap))},
{Object.class, "x", new VariableResolverException("x"), createAntlr(VariableResolver.NoVariableResolver.instance())},
- {Object.class, "'test'", "test", createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
- {Object.class, "x", "test", createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "test")))},
- {Object.class, "x", now, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", now)))},
- {Object.class, "[1,2,3]", Arrays.asList(1, 2, 3), createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", now)))},
- {Object.class, "x", P.eq(100), createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", P.eq(100))))},
- {Direction.class, "Direction.OUT", Direction.OUT, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
- {Direction.class, "OUT", Direction.OUT, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
- {Vertex.class, "x", new VariableResolverException("x"), createAntlr(VariableResolver.NoVariableResolver.instance())},
- {Vertex.class, "new Vertex(1i,'person')", new ReferenceVertex(1, "person"), createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", Direction.from)))},
- {Vertex.class, "x", new ReferenceVertex(1, "person"), createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", new ReferenceVertex(1, "person"))))},
- {Order.class, "Order.desc", Order.desc, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
- {Scope.class, "Scope.local", Scope.local, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
- {Scope.class, "local", Scope.local, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
- {T.class, "T.label", T.label, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
- {T.class, "label", T.label, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
- {VertexProperty.Cardinality.class, "Cardinality.list", VertexProperty.Cardinality.list, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
- {VertexProperty.Cardinality.class, "list", VertexProperty.Cardinality.list, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
- {DT.class, "DT.hour", DT.hour, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
- {DT.class, "hour", DT.hour, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
- {Merge.class, "Merge.onMatch", Merge.onMatch, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
- {Merge.class, "onMatch", Merge.onMatch, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
- {Pop.class, "Pop.last", Pop.last, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
- {Pop.class, "last", Pop.last, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
- {Operator.class, "Operator.sum", Operator.sum, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
- {Operator.class, "sum", Operator.sum, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
- {Column.class, "Column.keys", Column.keys, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
- {Column.class, "keys", Column.keys, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
- {SackFunctions.Barrier.class, "Barrier.normSack", SackFunctions.Barrier.normSack, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
- {SackFunctions.Barrier.class, "Barrier.normSack", SackFunctions.Barrier.normSack, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
+ {Object.class, "'test'", "test", createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+ {Object.class, "x", "test", createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "test")))},
+ {Object.class, "x", now, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", now)))},
+ {Object.class, "[1,2,3]", Arrays.asList(1, 2, 3), createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", now)))},
+ {Object.class, "x", P.eq(100), createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", P.eq(100))))},
+ {Direction.class, "Direction.OUT", Direction.OUT, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+ {Direction.class, "OUT", Direction.OUT, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+ {Vertex.class, "new Vertex(1i,'person')", new ReferenceVertex(1, "person"), createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", Direction.from)))},
+ {Order.class, "Order.desc", Order.desc, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+ {Scope.class, "Scope.local", Scope.local, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+ {Scope.class, "local", Scope.local, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+ {T.class, "T.label", T.label, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+ {T.class, "label", T.label, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+ {VertexProperty.Cardinality.class, "Cardinality.list", VertexProperty.Cardinality.list, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+ {VertexProperty.Cardinality.class, "list", VertexProperty.Cardinality.list, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+ {DT.class, "DT.hour", DT.hour, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+ {DT.class, "hour", DT.hour, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+ {Merge.class, "Merge.onMatch", Merge.onMatch, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+ {Merge.class, "onMatch", Merge.onMatch, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+ {Pop.class, "Pop.last", Pop.last, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+ {Pop.class, "last", Pop.last, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+ {Operator.class, "Operator.sum", Operator.sum, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+ {Operator.class, "sum", Operator.sum, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+ {Column.class, "Column.keys", Column.keys, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+ {Column.class, "keys", Column.keys, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+ {SackFunctions.Barrier.class, "Barrier.normSack", SackFunctions.Barrier.normSack, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+ {SackFunctions.Barrier.class, "Barrier.normSack", SackFunctions.Barrier.normSack, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
});
}
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 4e7168a7f5..a286e2e5fd 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
@@ -41,7 +41,7 @@ public class GremlinQueryParserTest {
public void shouldParseVariables() {
final GremlinAntlrToJava gremlinAntlrToJava = new GremlinAntlrToJava("g",
EmptyGraph.instance(), __::start, g,
- new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("z", 50)));
+ new VariableResolver.DirectVariableResolver(ElementHelper.asMap("z", 50)));
final GraphTraversal<?, ?> t = (GraphTraversal<?, ?>) GremlinQueryParser.parse("g.V().has('name',gt(z))", gremlinAntlrToJava);
assertEquals(g.V().has("name", P.gt(50)).asAdmin().getGremlinLang(),
@@ -52,7 +52,7 @@ public class GremlinQueryParserTest {
public void shouldParseVariablesInVarargs() {
final GremlinAntlrToJava gremlinAntlrToJava = new GremlinAntlrToJava("g",
EmptyGraph.instance(), __::start, g,
- new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 100,
+ new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", 100,
"y", 200,
"z", 50)));
@@ -73,7 +73,7 @@ public class GremlinQueryParserTest {
public void shouldNotParseVariablesInList() {
final GremlinAntlrToJava gremlinAntlrToJava = new GremlinAntlrToJava("g",
EmptyGraph.instance(), __::start, g,
- new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 100,
+ new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", 100,
"y", 200,
"z", 50)));
GremlinQueryParser.parse("g.V([x, y, 300]).has('name',gt(z))", gremlinAntlrToJava);
@@ -83,7 +83,7 @@ public class GremlinQueryParserTest {
public void shouldNotParseVariablesWhichAreTraversalBased() {
final GremlinAntlrToJava gremlinAntlrToJava = new GremlinAntlrToJava("g",
EmptyGraph.instance(), __::start, g,
- new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 100,
+ new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", 100,
"y", 200,
"z", __.out())));
GremlinQueryParser.parse("g.V([x, y, 300]).where(z)", gremlinAntlrToJava);
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/translator/GremlinTranslatorTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/translator/GremlinTranslatorTest.java
index 90022b34d5..82e3461cc5 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/translator/GremlinTranslatorTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/translator/GremlinTranslatorTest.java
@@ -703,6 +703,33 @@ public class GremlinTranslatorTest {
null,
null,
"g.V().has_label(None)"},
+ {"g.V().hasLabel(null, null)",
+ null,
+ "g.V().hasLabel(string0, string0)",
+ "g.V().HasLabel((string) null, (string) null)",
+ "g.V().HasLabel(nil, nil)",
+ "g.V().hasLabel((String) null, (String) null)",
+ null,
+ null,
+ "g.V().has_label(None, None)"},
+ {"g.V().hasLabel(null, null, null)",
+ null,
+ "g.V().hasLabel(string0, string0, string0)",
+ "g.V().HasLabel((string) null, (string) null, (string) null)",
+ "g.V().HasLabel(nil, nil, nil)",
+ "g.V().hasLabel((String) null, (String) null, (String) null)",
+ null,
+ null,
+ "g.V().has_label(None, None, None)"},
+ {"g.V().hasLabel(\"person\", null)",
+ null,
+ "g.V().hasLabel(string0, string1)",
+ "g.V().HasLabel(\"person\", (string) null)",
+ "g.V().HasLabel(\"person\", nil)",
+ "g.V().hasLabel(\"person\", null)",
+ null,
+ null,
+ "g.V().has_label('person', None)"},
{"g.V().hasLabel('person')",
null,
"g.V().hasLabel(string0)",
@@ -724,9 +751,9 @@ public class GremlinTranslatorTest {
{"g.V().hasLabel(null, 'software', 'class')",
null,
"g.V().hasLabel(string0, string1, string2)",
- "g.V().HasLabel(null, \"software\", \"class\")",
+ "g.V().HasLabel((string) null, \"software\", \"class\")",
"g.V().HasLabel(nil, \"software\", \"class\")",
- "g.V().hasLabel(null, 'software', 'class')",
+ "g.V().hasLabel((String) null, 'software', 'class')",
"g.V().hasLabel(null, \"software\", \"class\")",
"g.V().hasLabel(null, \"software\", \"class\")",
"g.V().has_label(None, 'software', 'class')"},
@@ -1045,6 +1072,24 @@ public class GremlinTranslatorTest {
null,
null,
null},
+ {"g.V().hasLabel(x, y)",
+ null,
+ null,
+ "g.V().HasLabel((string) x, (string) y)",
+ "g.V().HasLabel(x, y)",
+ null,
+ null,
+ null,
+ "g.V().has_label(x, y)"},
+ {"g.V().conjoin(x)",
+ null,
+ null,
+ "g.V().Conjoin((string) x)",
+ "g.V().Conjoin(x)",
+ null,
+ null,
+ null,
+ null},
{"g.mergeV([name:\"alice\", T.label:\"person\"]).option(Merge.onCreate, [age:Cardinality.single(81)])",
null,
"g.mergeV(map0).option(Merge.onCreate, map1)",
@@ -1063,6 +1108,15 @@ public class GremlinTranslatorTest {
"g.mergeV(new LinkedHashMap<Object, Object>() {{ put(\"name\", \"alice\"); put(T.label, \"person\"); }}).option(Merge.onCreate, new LinkedHashMap<Object, Object>() {{ put(\"age\", Cardinality.single(81)); }})",
"g.mergeV(new Map([[\"name\", \"alice\"], [T.label, \"person\"]])).option(Merge.onCreate, new Map([[\"age\", CardinalityValue.single(81)]]))",
"g.merge_v({ 'name': 'alice', T.label: 'person' }).option(Merge.on_create, { 'age': CardinalityValue.single(81) })"},
+ {"g.V().branch(__.label().is(\"person\").count()).option(xx1, __.values(\"age\")).option(xx2, __.values(\"lang\")).option(xx2, __.values(\"name\")).option(Pick.any, __.label())",
+ null,
+ "g.V().branch(__.label().is(string0).count()).option(xx1, __.values(string1)).option(xx2, __.values(string2)).option(xx2, __.values(string3)).option(Pick.any, __.label())",
+ "g.V().Branch<object>(__.Label().Is(\"person\").Count()).Option(xx1, __.Values<object>(\"age\")).Option(xx2, __.Values<object>(\"lang\")).Option(xx2, __.Values<object>(\"name\")).Option(Pick.Any, __.Label())",
+ "g.V().Branch(gremlingo.T__.Label().Is(\"person\").Count()).Option(xx1, gremlingo.T__.Values(\"age\")).Option(xx2, gremlingo.T__.Values(\"lang\")).Option(xx2, gremlingo.T__.Values(\"name\")).Option(gremlingo.Pick.Any, gremlingo.T__.Label())",
+ null,
+ null,
+ null,
+ "g.V().branch(__.label().is_('person').count()).option(xx1, __.values('age')).option(xx2, __.values('lang')).option(xx2, __.values('name')).option(Pick.any_, __.label())"},
{"g.V().toList()",
null,
null,
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/GTypeTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/GTypeTest.java
new file mode 100644
index 0000000000..9596445860
--- /dev/null
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/GTypeTest.java
@@ -0,0 +1,77 @@
+/*
+ * 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.Path;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Property;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.junit.Test;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Collections;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+
+public class GTypeTest {
+
+ @Test
+ public void shouldReturnTrueForNumericTypes() {
+ assertThat(GType.INTEGER.isNumeric(), is(true));
+ assertThat(GType.DOUBLE.isNumeric(), is(true));
+ assertThat(GType.LONG.isNumeric(), is(true));
+ assertThat(GType.BIG_INTEGER.isNumeric(), is(true));
+ assertThat(GType.BIG_DECIMAL.isNumeric(), is(true));
+ }
+
+ @Test
+ public void shouldReturnFalseForNonNumericTypes() {
+ assertThat(GType.STRING.isNumeric(), is(false));
+ assertThat(GType.BOOLEAN.isNumeric(), is(false));
+ assertThat(GType.EDGE.isNumeric(), is(false));
+ assertThat(GType.VERTEX.isNumeric(), is(false));
+ }
+
+ @Test
+ public void shouldReturnCorrectGType() {
+ assertEquals(GType.STRING, GType.getType("test"));
+ assertEquals(GType.INTEGER, GType.getType(123));
+ assertEquals(GType.BOOLEAN, GType.getType(true));
+ assertEquals(GType.DOUBLE, GType.getType(123.45));
+ assertEquals(GType.LONG, GType.getType(123L));
+ assertEquals(GType.MAP, GType.getType(Collections.emptyMap()));
+ assertEquals(GType.LIST, GType.getType(Collections.emptyList()));
+ assertEquals(GType.SET, GType.getType(Collections.emptySet()));
+ assertEquals(GType.VERTEX, GType.getType(mock(Vertex.class)));
+ assertEquals(GType.EDGE, GType.getType(mock(Edge.class)));
+ assertEquals(GType.PATH, GType.getType(mock(Path.class)));
+ assertEquals(GType.PROPERTY, GType.getType(mock(Property.class)));
+ assertEquals(GType.BIG_INTEGER, GType.getType(BigInteger.ONE));
+ assertEquals(GType.BIG_DECIMAL, GType.getType(BigDecimal.ONE));
+ }
+
+ @Test
+ public void shouldReturnUnknownForUnmatchedTypes() {
+ assertEquals(GType.UNKNOWN, GType.getType(new Object()));
+ }
+}
\ No newline at end of file
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/GValueTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/GValueTest.java
new file mode 100644
index 0000000000..10bfafed29
--- /dev/null
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/GValueTest.java
@@ -0,0 +1,641 @@
+/*
+ * 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.Path;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Property;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.mockito.Mockito.mock;
+
+public class GValueTest {
+
+ @Test
+ public void shouldReturnAnExistingGValue() {
+ final GValue<Integer> gValue = GValue.of(123);
+ final Object returnedGValue = GValue.of(gValue);
+ assertEquals(gValue, returnedGValue);
+ assertSame(gValue, returnedGValue);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void shouldReturnAnExistInTypedGValue() {
+ final Object gValue = GValue.of("x", 123);
+ GValue.of("x", gValue);
+ }
+
+ @Test
+ public void shouldCreateGValueFromValue() {
+ final GValue<Integer> gValue = GValue.of(123);
+ assertEquals(123, gValue.get().intValue());
+ assertEquals(GType.INTEGER, gValue.getType());
+ assertThat(gValue.isVariable(), is(false));
+ }
+
+ @Test
+ public void shouldCreateGValueFromNameAndValue() {
+ final GValue<Integer> gValue = GValue.of("varName", 123);
+ assertEquals(123, gValue.get().intValue());
+ assertEquals(GType.INTEGER, gValue.getType());
+ assertEquals("varName", gValue.getName());
+ assertThat(gValue.isVariable(), is(true));
+ }
+
+ @Test
+ public void shouldCreateGValueFromString() {
+ final GValue<String> gValue = GValue.ofString("test");
+ assertEquals("test", gValue.get());
+ assertEquals(GType.STRING, gValue.getType());
+ assertThat(gValue.isVariable(), is(false));
+ }
+
+ @Test
+ public void shouldCreateGValueFromStringWithName() {
+ final GValue<String> gValue = GValue.ofString("varName", "test");
+ assertEquals("test", gValue.get());
+ assertEquals(GType.STRING, gValue.getType());
+ assertEquals("varName", gValue.getName());
+ assertThat(gValue.isVariable(), is(true));
+ }
+
+ @Test
+ public void shouldCreateGValueFromInteger() {
+ final GValue<Integer> gValue = GValue.ofInteger(123);
+ assertEquals(123, gValue.get().intValue());
+ assertEquals(GType.INTEGER, gValue.getType());
+ assertThat(gValue.isVariable(), is(false));
+ }
+
+ @Test
+ public void shouldCreateGValueFromIntegerWithName() {
+ final GValue<Integer> gValue = GValue.ofInteger("varName", 123);
+ assertEquals(123, gValue.get().intValue());
+ assertEquals(GType.INTEGER, gValue.getType());
+ assertEquals("varName", gValue.getName());
+ assertThat(gValue.isVariable(), is(true));
+ }
+
+ @Test
+ public void shouldCreateGValueFromBoolean() {
+ final GValue<Boolean> gValue = GValue.ofBoolean(true);
+ assertEquals(true, gValue.get());
+ assertEquals(GType.BOOLEAN, gValue.getType());
+ assertThat(gValue.isVariable(), is(false));
+ }
+
+ @Test
+ public void shouldCreateGValueFromBooleanWithName() {
+ final GValue<Boolean> gValue = GValue.ofBoolean("varName", true);
+ assertEquals(true, gValue.get());
+ assertEquals(GType.BOOLEAN, gValue.getType());
+ assertEquals("varName", gValue.getName());
+ assertThat(gValue.isVariable(), is(true));
+ }
+
+ @Test
+ public void shouldCreateGValueFromDouble() {
+ final GValue<Double> gValue = GValue.ofDouble(123.45);
+ assertEquals(123.45, gValue.get(), 0.0);
+ assertEquals(GType.DOUBLE, gValue.getType());
+ assertThat(gValue.isVariable(), is(false));
+ }
+
+ @Test
+ public void shouldCreateGValueFromDoubleWithName() {
+ final GValue<Double> gValue = GValue.ofDouble("varName", 123.45);
+ assertEquals(123.45, gValue.get(), 0.0);
+ assertEquals(GType.DOUBLE, gValue.getType());
+ assertEquals("varName", gValue.getName());
+ assertThat(gValue.isVariable(), is(true));
+ }
+
+ @Test
+ public void shouldCreateGValueFromBigInteger() {
+ final GValue<BigInteger> gValue = GValue.ofBigInteger(BigInteger.ONE);
+ assertEquals(BigInteger.ONE, gValue.get());
+ assertEquals(GType.BIG_INTEGER, gValue.getType());
+ assertThat(gValue.isVariable(), is(false));
+ }
+
+ @Test
+ public void shouldCreateGValueFromBigIntegerWithName() {
+ final GValue<BigInteger> gValue = GValue.ofBigInteger("varName", BigInteger.ONE);
+ assertEquals(BigInteger.ONE, gValue.get());
+ assertEquals(GType.BIG_INTEGER, gValue.getType());
+ assertEquals("varName", gValue.getName());
+ assertThat(gValue.isVariable(), is(true));
+ }
+
+ @Test
+ public void shouldCreateGValueFromBigDecimal() {
+ final GValue<BigDecimal> gValue = GValue.ofBigDecimal(BigDecimal.ONE);
+ assertEquals(BigDecimal.ONE, gValue.get());
+ assertEquals(GType.BIG_DECIMAL, gValue.getType());
+ assertThat(gValue.isVariable(), is(false));
+ }
+
+ @Test
+ public void shouldCreateGValueFromBigDecimalWithName() {
+ final GValue<BigDecimal> gValue = GValue.ofBigDecimal("varName", BigDecimal.ONE);
+ assertEquals(BigDecimal.ONE, gValue.get());
+ assertEquals(GType.BIG_DECIMAL, gValue.getType());
+ assertEquals("varName", gValue.getName());
+ assertThat(gValue.isVariable(), is(true));
+ }
+
+ @Test
+ public void shouldCreateGValueFromLong() {
+ final GValue<Long> gValue = GValue.ofLong(123L);
+ assertEquals(123L, gValue.get().longValue());
+ assertEquals(GType.LONG, gValue.getType());
+ assertThat(gValue.isVariable(), is(false));
+ }
+
+ @Test
+ public void shouldCreateGValueFromLongWithName() {
+ final GValue<Long> gValue = GValue.ofLong("varName", 123L);
+ assertEquals(123L, gValue.get().longValue());
+ assertEquals(GType.LONG, gValue.getType());
+ assertEquals("varName", gValue.getName());
+ assertThat(gValue.isVariable(), is(true));
+ }
+
+ @Test
+ public void shouldCreateGValueFromMap() {
+ final Map<String, String> map = new HashMap<String,String>() {{
+ put("key", "value");
+ }};
+ final GValue<Map> gValue = GValue.ofMap(map);
+ assertEquals(map, gValue.get());
+ assertEquals(GType.MAP, gValue.getType());
+ assertThat(gValue.isVariable(), is(false));
+ }
+
+ @Test
+ public void shouldCreateGValueFromMapWithName() {
+ final Map<String, String> map = new HashMap<String,String>() {{
+ put("key", "value");
+ }};
+ final GValue<Map> gValue = GValue.ofMap("varName", map);
+ assertEquals(map, gValue.get());
+ assertEquals(GType.MAP, gValue.getType());
+ assertEquals("varName", gValue.getName());
+ assertThat(gValue.isVariable(), is(true));
+ }
+
+ @Test
+ public void shouldCreateGValueFromList() {
+ final List<String> list = Arrays.asList("value1", "value2");
+ final GValue<List<String>> gValue = GValue.ofList(list);
+ assertEquals(list, gValue.get());
+ assertEquals(GType.LIST, gValue.getType());
+ assertThat(gValue.isVariable(), is(false));
+ }
+
+ @Test
+ public void shouldCreateGValueFromListWithName() {
+ final List<String> list = Arrays.asList("value1", "value2");
+ final GValue<List<String>> gValue = GValue.ofList("varName", list);
+ assertEquals(list, gValue.get());
+ assertEquals(GType.LIST, gValue.getType());
+ assertEquals("varName", gValue.getName());
+ assertThat(gValue.isVariable(), is(true));
+ }
+
+ @Test
+ public void shouldCreateGValueFromSet() {
+ final Set<String> set = new HashSet<>(Arrays.asList("value1", "value2"));
+ final GValue<Set> gValue = GValue.ofSet(set);
+ assertEquals(set, gValue.get());
+ assertEquals(GType.SET, gValue.getType());
+ assertThat(gValue.isVariable(), is(false));
+ }
+
+ @Test
+ public void shouldCreateGValueFromSetWithName() {
+ final Set<String> set = new HashSet<>(Arrays.asList("value1", "value2"));
+ final GValue<Set> gValue = GValue.ofSet("varName", set);
+ assertEquals(set, gValue.get());
+ assertEquals(GType.SET, gValue.getType());
+ assertEquals("varName", gValue.getName());
+ assertThat(gValue.isVariable(), is(true));
+ }
+
+ @Test
+ public void shouldCreateGValueFromVertex() {
+ final Vertex vertex = mock(Vertex.class);
+ final GValue<Vertex> gValue = GValue.ofVertex(vertex);
+ assertEquals(vertex, gValue.get());
+ assertEquals(GType.VERTEX, gValue.getType());
+ assertThat(gValue.isVariable(), is(false));
+ }
+
+ @Test
+ public void shouldCreateGValueFromVertexWithName() {
+ final Vertex vertex = mock(Vertex.class);
+ final GValue<Vertex> gValue = GValue.ofVertex("varName", vertex);
+ assertEquals(vertex, gValue.get());
+ assertEquals(GType.VERTEX, gValue.getType());
+ assertEquals("varName", gValue.getName());
+ assertThat(gValue.isVariable(), is(true));
+ }
+
+ @Test
+ public void shouldCreateGValueFromEdge() {
+ final Edge edge = mock(Edge.class);
+ final GValue<Edge> gValue = GValue.ofEdge(edge);
+ assertEquals(edge, gValue.get());
+ assertEquals(GType.EDGE, gValue.getType());
+ assertThat(gValue.isVariable(), is(false));
+ }
+
+ @Test
+ public void shouldCreateGValueFromEdgeWithName() {
+ final Edge edge = mock(Edge.class);
+ final GValue<Edge> gValue = GValue.ofEdge("varName", edge);
+ assertEquals(edge, gValue.get());
+ assertEquals(GType.EDGE, gValue.getType());
+ assertEquals("varName", gValue.getName());
+ assertThat(gValue.isVariable(), is(true));
+ }
+
+ @Test
+ public void shouldCreateGValueFromPath() {
+ final Path path = mock(Path.class);
+ final GValue<Path> gValue = GValue.ofPath(path);
+ assertEquals(path, gValue.get());
+ assertEquals(GType.PATH, gValue.getType());
+ assertThat(gValue.isVariable(), is(false));
+ }
+
+ @Test
+ public void shouldCreateGValueFromPathWithName() {
+ final Path path = mock(Path.class);
+ final GValue<Path> gValue = GValue.ofPath("varName", path);
+ assertEquals(path, gValue.get());
+ assertEquals(GType.PATH, gValue.getType());
+ assertEquals("varName", gValue.getName());
+ assertThat(gValue.isVariable(), is(true));
+ }
+
+ @Test
+ public void shouldCreateGValueFromProperty() {
+ final Property property = mock(Property.class);
+ final GValue<Property> gValue = GValue.ofProperty(property);
+ assertEquals(property, gValue.get());
+ assertEquals(GType.PROPERTY, gValue.getType());
+ assertThat(gValue.isVariable(), is(false));
+ }
+
+ @Test
+ public void shouldCreateGValueFromPropertyWithName() {
+ final Property property = mock(Property.class);
+ final GValue<Property> gValue = GValue.ofProperty("varName", property);
+ assertEquals(property, gValue.get());
+ assertEquals(GType.PROPERTY, gValue.getType());
+ assertEquals("varName", gValue.getName());
+ assertThat(gValue.isVariable(), is(true));
+ }
+
+ @Test
+ public void shouldBeAnInstanceOf() {
+ assertThat(GValue.instanceOf(GValue.of("string"), GType.STRING), is(true));
+ assertThat(GValue.instanceOf(GValue.ofInteger(1), GType.INTEGER), is(true));
+ assertThat(GValue.instanceOf("string", GType.STRING), is(true));
+ assertThat(GValue.instanceOf(1, GType.INTEGER), is(true));
+ }
+
+ @Test
+ public void shouldNotBeAnInstanceOf() {
+ assertThat(GValue.instanceOf(GValue.of("string"), GType.INTEGER), is(false));
+ assertThat(GValue.instanceOf(GValue.ofInteger(1), GType.STRING), is(false));
+ assertThat(GValue.instanceOf("string", GType.INTEGER), is(false));
+ assertThat(GValue.instanceOf(1, GType.STRING), is(false));
+ }
+
+ @Test
+ public void shouldBeAnInstanceOfCollection() {
+ assertThat(GValue.instanceOfCollection(GValue.of(Arrays.asList("string"))), is(true));
+ assertThat(GValue.instanceOfCollection(GValue.ofSet(new HashSet(Arrays.asList("string")))), is(true));
+ assertThat(GValue.instanceOfCollection(Arrays.asList("string")), is(true));
+ assertThat(GValue.instanceOfCollection(new HashSet(Arrays.asList("string"))), is(true));
+ }
+
+ @Test
+ public void shouldNotBeAnInstanceOfCollection() {
+ assertThat(GValue.instanceOfCollection(GValue.of(new HashMap())), is(false));
+ assertThat(GValue.instanceOfCollection(GValue.ofInteger(1)), is(false));
+ assertThat(GValue.instanceOfCollection(new HashMap()), is(false));
+ assertThat(GValue.instanceOfCollection(1), is(false));
+ }
+
+ @Test
+ public void shouldBeAnInstanceOfNumber() {
+ assertThat(GValue.instanceOfNumber(GValue.of(1)), is(true));
+ assertThat(GValue.instanceOfNumber(GValue.of(1L)), is(true));
+ assertThat(GValue.instanceOfNumber(GValue.of(1D)), is(true));
+ assertThat(GValue.instanceOfNumber(GValue.of(BigInteger.valueOf((1L)))), is(true));
+ assertThat(GValue.instanceOfNumber(GValue.of(BigDecimal.valueOf((1.0)))), is(true));
+ assertThat(GValue.instanceOfNumber(GValue.ofInteger(1)), is(true));
+ assertThat(GValue.instanceOfNumber(GValue.ofLong(1L)), is(true));
+ assertThat(GValue.instanceOfNumber(GValue.ofDouble(1D)), is(true));
+ assertThat(GValue.instanceOfNumber(GValue.ofBigInteger(BigInteger.valueOf((1L)))), is(true));
+ assertThat(GValue.instanceOfNumber(GValue.ofBigDecimal(BigDecimal.valueOf((1.0)))), is(true));
+ }
+
+ @Test
+ public void shouldNotBeAnInstanceOfNumber() {
+ assertThat(GValue.instanceOfNumber(GValue.of("string")), is(false));
+ assertThat(GValue.instanceOfNumber(GValue.of(Arrays.asList("string"))), is(false));
+ }
+
+ @Test
+ public void shouldBeAnInstanceOfElement() {
+ assertThat(GValue.instanceOfElement(GValue.ofVertex(mock(Vertex.class))), is(true));
+ assertThat(GValue.instanceOfElement(GValue.ofEdge(mock(Edge.class))), is(true));
+ }
+
+ @Test
+ public void shouldNotBeAnInstanceOfElement() {
+ assertThat(GValue.instanceOfElement(GValue.of("string")), is(false));
+ assertThat(GValue.instanceOfElement(GValue.of(Arrays.asList("string"))), is(false));
+ }
+
+ @Test
+ public void shouldHaveForMatchingType() {
+ final GValue<Integer> gValue = GValue.of(123);
+ assertThat(GValue.valueInstanceOf(gValue, GType.INTEGER), is(true));
+ }
+
+ @Test
+ public void valueInstanceOfShouldReturnFalseForNonMatchingType() {
+ final GValue<Integer> gValue = GValue.of(123);
+ assertThat(GValue.valueInstanceOf(gValue, GType.STRING), is(false));
+ }
+
+ @Test
+ public void valueInstanceOfShouldReturnFalseForNonGValueObject() {
+ String nonGValue = "test";
+ assertThat(GValue.valueInstanceOf(nonGValue, GType.STRING), is(false));
+ }
+
+ @Test
+ public void valueInstanceOfShouldReturnFalseForNullObject() {
+ assertThat(GValue.valueInstanceOf(null, GType.STRING), is(false));
+ }
+
+ @Test
+ public void getShouldReturnGValueValue() {
+ final GValue<Integer> gValue = GValue.of(123);
+ assertThat(GValue.getFrom(gValue), is(123));
+ }
+
+ @Test
+ public void getShouldReturnObjectAsIs() {
+ final String value = "test";
+ assertThat(GValue.getFrom(value), is(value));
+ }
+
+ @Test
+ public void getShouldReturnNullForNullInput() {
+ assertThat(GValue.getFrom(null), is((Object) null));
+ }
+
+ @Test
+ public void valueInstanceOfCollectionShouldReturnTrueForGValueWithCollectionType() {
+ final GValue<List<String>> gValue = GValue.ofList(Arrays.asList("value1", "value2"));
+ assertThat(GValue.valueInstanceOfCollection(gValue), is(true));
+ }
+
+ @Test
+ public void valueInstanceOfCollectionShouldReturnFalseForGValueWithNonCollectionType() {
+ final GValue<Integer> gValue = GValue.of(123);
+ assertThat(GValue.valueInstanceOfCollection(gValue), is(false));
+ }
+
+ @Test
+ public void valueInstanceOfCollectionShouldReturnFalseForNonGValueObject() {
+ assertThat(GValue.valueInstanceOfCollection("test"), is(false));
+ }
+
+ @Test
+ public void valueInstanceOfCollectionShouldReturnFalseForNullObject() {
+ assertThat(GValue.valueInstanceOfCollection(null), is(false));
+ }
+
+ @Test
+ public void valueInstanceOfNumericShouldReturnTrueForGValueWithNumericType() {
+ final GValue<Integer> gValue = GValue.of(123);
+ assertThat(GValue.valueInstanceOfNumeric(gValue), is(true));
+ }
+
+ @Test
+ public void valueInstanceOfNumericShouldReturnFalseForGValueWithNonNumericType() {
+ assertThat(GValue.valueInstanceOfNumeric("test"), is(false));
+ }
+
+ @Test
+ public void valueInstanceOfNumericShouldReturnFalseForNonGValueObject() {
+ assertThat(GValue.valueInstanceOfNumeric("test"), is(false));
+ }
+
+ @Test
+ public void valueInstanceOfNumericShouldReturnFalseForNullObject() {
+ assertThat(GValue.valueInstanceOfNumeric(null), is(false));
+ }
+
+ @Test
+ public void shouldConvertObjectArrayToGValues() {
+ final Object[] input = {1, "string", true};
+ final GValue<?>[] expected = {GValue.of(1), GValue.of("string"), GValue.of(true)};
+ final GValue<?>[] result = GValue.ensureGValues(input);
+ assertArrayEquals(expected, result);
+ }
+
+ @Test
+ public void shouldPreserveExistingGValuesInArray() {
+ final GValue<Integer> gValue = GValue.of(123);
+ final Object[] input = {gValue, "string"};
+ final GValue<?>[] expected = {gValue, GValue.of("string")};
+ final GValue<?>[] result = GValue.ensureGValues(input);
+ assertArrayEquals(expected, result);
+ }
+
+ @Test
+ public void shouldHandleEmptyArray() {
+ final Object[] input = {};
+ final GValue<?>[] expected = {};
+ final GValue<?>[] result = GValue.ensureGValues(input);
+ assertArrayEquals(expected, result);
+ }
+
+ @Test
+ public void shouldHandleArrayWithNullValues() {
+ final Object[] input = {null, "string"};
+ final GValue<?>[] expected = {GValue.of(null), GValue.of("string")};
+ final GValue<?>[] result = GValue.ensureGValues(input);
+ assertArrayEquals(expected, result);
+ }
+
+ @Test
+ public void shouldResolveGValuesToValues() {
+ final GValue<?>[] input = {GValue.of(1), GValue.of("string"), GValue.of(true)};
+ final Object[] expected = {1, "string", true};
+ final Object[] result = GValue.resolveToValues(input);
+ assertArrayEquals(expected, result);
+ }
+
+ @Test
+ public void shouldHandleEmptyGValuesArray() {
+ final GValue<?>[] input = {};
+ final Object[] expected = {};
+ final Object[] result = GValue.resolveToValues(input);
+ assertArrayEquals(expected, result);
+ }
+
+ @Test
+ public void shouldHandleGValuesArrayWithNullValues() {
+ final GValue<?>[] input = {GValue.of(null), GValue.of("string")};
+ final Object[] expected = {null, "string"};
+ final Object[] result = GValue.resolveToValues(input);
+ assertArrayEquals(expected, result);
+ }
+
+ @Test
+ public void shouldHandleMixedTypeGValuesArray() {
+ final GValue<?>[] input = {GValue.of(1), GValue.of("string"), GValue.of(true), GValue.of(123.45)};
+ final Object[] expected = {1, "string", true, 123.45};
+ final Object[] result = GValue.resolveToValues(input);
+ assertArrayEquals(expected, result);
+ }
+
+ @Test
+ public void equalsShouldReturnTrueForSameObject() {
+ final GValue<Integer> gValue = GValue.of(123);
+ assertEquals(true, gValue.equals(gValue));
+ }
+
+ @Test
+ public void equalsShouldReturnFalseForNull() {
+ final GValue<Integer> gValue = GValue.of(123);
+ assertEquals(false, gValue.equals(null));
+ }
+
+ @Test
+ public void equalsShouldReturnFalseForDifferentClass() {
+ final GValue<Integer> gValue = GValue.of(123);
+ assertEquals(false, gValue.equals("string"));
+ }
+
+ @Test
+ public void equalsShouldReturnTrueForEqualGValues() {
+ final GValue<Integer> gValue1 = GValue.of(123);
+ final GValue<Integer> gValue2 = GValue.of(123);
+ assertEquals(true, gValue1.equals(gValue2));
+ }
+
+ @Test
+ public void equalsShouldReturnFalseForDifferentNames() {
+ final GValue<Integer> gValue1 = GValue.of("name1", 123);
+ final GValue<Integer> gValue2 = GValue.of("name2", 123);
+ assertEquals(false, gValue1.equals(gValue2));
+ }
+
+ @Test
+ public void equalsShouldReturnFalseForDifferentTypes() {
+ final GValue<Integer> gValue1 = GValue.of(123);
+ final GValue<String> gValue2 = GValue.of("123");
+ assertEquals(false, gValue1.equals(gValue2));
+ }
+
+ @Test
+ public void equalsShouldReturnFalseForDifferentValues() {
+ final GValue<Integer> gValue1 = GValue.of(123);
+ final GValue<Integer> gValue2 = GValue.of(456);
+ assertEquals(false, gValue1.equals(gValue2));
+ }
+
+ @Test
+ public void valueOfShouldReturnGValueValue() {
+ final GValue<Integer> gValue = GValue.of(123);
+ assertEquals(123, GValue.valueOf(gValue));
+ }
+
+ @Test
+ public void valueOfShouldReturnObjectAsIs() {
+ final String value = "test";
+ assertEquals("test", GValue.valueOf(value));
+ }
+
+ @Test
+ public void valueOfShouldReturnNullForNullInput() {
+ assertNull(GValue.valueOf(null));
+ assertNull(null);
+ }
+
+ @Test
+ public void numberOfShouldReturnGValueValue() {
+ final GValue<Integer> gValue = GValue.ofInteger(1234);
+ assertEquals(1234, GValue.numberOf(gValue));
+ }
+
+ @Test
+ public void numberOfShouldReturnObjectAsIs() {
+ assertEquals(1234, GValue.numberOf(1234));
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void numberOfShouldThrowBecauseGValueNotNumberType() {
+ assertEquals(1234, GValue.numberOf("1234"));
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void numberOfShouldThrowBecauseObjectNotNumberType() {
+ final GValue<String> gValue = GValue.of("1234");
+ GValue.numberOf(gValue);
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void numberOfShouldThrowBecauseNullIntegerGType() {
+ GValue.numberOf(GValue.of(null, GType.INTEGER));
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void numberOfShouldThrowBecauseNullObject() {
+ GValue.numberOf(null);
+ }
+}
\ No newline at end of file
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConjoinStepTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConjoinStepTest.java
index a84c691182..35d9fe29f9 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConjoinStepTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConjoinStepTest.java
@@ -41,7 +41,7 @@ public class ConjoinStepTest extends StepTest {
@Test
public void testReturnTypes() {
try {
- __.__(Collections.emptyList()).conjoin(null).next();
+ __.__(Collections.emptyList()).conjoin((String) null).next();
fail();
} catch (Exception e) {
assertTrue(e.getMessage().contains("Input delimiter to conjoin step can't be null"));
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/ParametersTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/ParametersTest.java
index 0983540dcb..f509926359 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/ParametersTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/ParametersTest.java
@@ -21,6 +21,7 @@ package org.apache.tinkerpop.gremlin.process.traversal.step.util;
import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
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.step.TraversalParent;
import org.junit.Test;
@@ -356,4 +357,14 @@ public class ParametersTest {
verify(mock).integrateChild(__.outE("knows").asAdmin());
}
+
+ @Test
+ public void shouldGetKeyValuesAndResolveGValues() {
+ final Parameters parameters = new Parameters();
+ parameters.set(null, "a", "axe", "b", GValue.of("B", "bat"), "c", GValue.of("C", "cat"));
+
+ final Object[] params = parameters.getKeyValues(mock(Traverser.Admin.class));
+ assertEquals(6, params.length);
+ assertThat(Arrays.equals(new Object[] {"a", "axe", "b", "bat", "c", "cat"}, params), is(true));
+ }
}
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/CollectionUtilTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/CollectionUtilTest.java
index 73bd39b415..7b938c1a22 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/CollectionUtilTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/CollectionUtilTest.java
@@ -22,10 +22,20 @@ import org.apache.tinkerpop.gremlin.AssertHelper;
import org.junit.Test;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
public class CollectionUtilTest {
@@ -70,4 +80,104 @@ public class CollectionUtilTest {
final ConcurrentHashMap<?, ?> cloned = CollectionUtil.clone(source);
assertTrue(source.equals(cloned));
}
+
+ @Test
+ public void shouldCloneEmptyConcurrentHashMap() {
+ final ConcurrentHashMap<String, String> source = new ConcurrentHashMap<>();
+ final ConcurrentHashMap<?, ?> cloned = CollectionUtil.clone(source);
+ assertTrue(source.equals(cloned));
+ }
+
+ @Test
+ public void shouldCloneConcurrentHashMapWithMixedTypes() {
+ final ConcurrentHashMap<String, Object> source = new ConcurrentHashMap<>();
+ source.put("key1", "value1");
+ source.put("key2", new ArrayList<>(Arrays.asList("a", "b")));
+ source.put("key3", new HashSet<>(Arrays.asList("x", "y")));
+
+ final ConcurrentHashMap<?, ?> cloned = CollectionUtil.clone(source);
+ assertTrue(source.equals(cloned));
+ }
+
+ @Test
+ public void shouldAddFirstWhenBothArgumentsNull() {
+ String[] result = CollectionUtil.addFirst(null, null, String.class);
+ assertArrayEquals(new String[]{null}, result);
+ }
+
+ @Test
+ public void shouldAddFirstWhenArrayNull() {
+ String[] result = CollectionUtil.addFirst(null, "element", String.class);
+ assertArrayEquals(new String[]{"element"}, result);
+ }
+
+ @Test
+ public void shoulAddFirstWhenNeitherArgumentNull() {
+ Integer[] array = {1, 2, 3};
+ Integer[] result = CollectionUtil.addFirst(array, 0, Integer.class);
+ assertArrayEquals(new Integer[]{0, 1, 2, 3}, result);
+ }
+
+ @Test
+ public void shouldAddFirstWhenEmptyArray() {
+ String[] array = {};
+ String[] result = CollectionUtil.addFirst(array, "element", String.class);
+ assertArrayEquals(new String[]{"element"}, result);
+ }
+
+ @Test
+ public void shouldAddFirstWhenIntegers() {
+ Integer[] array = {1, 2, 3};
+ Integer[] result = CollectionUtil.addFirst(array, 0, Integer.class);
+ assertArrayEquals(new Integer[]{0, 1, 2, 3}, result);
+ }
+
+ @Test
+ public void shouldConvertVarargsToList() {
+ List<String> result = CollectionUtil.asList("a", "b", "c");
+ assertEquals(Arrays.asList("a", "b", "c"), result);
+ }
+
+ @Test
+ public void shouldConvertEmptyVarargsToList() {
+ List<String> result = CollectionUtil.asList();
+ assertEquals(Collections.emptyList(), result);
+ }
+
+ @Test
+ public void shouldConvertVarargsToSet() {
+ Set<String> result = CollectionUtil.asSet("a", "b", "c");
+ assertEquals(new LinkedHashSet<>(Arrays.asList("a", "b", "c")), result);
+ }
+
+ @Test
+ public void shouldConvertEmptyVarargsToSet() {
+ Set<String> result = CollectionUtil.asSet();
+ assertEquals(new LinkedHashSet<>(), result);
+ }
+
+ @Test
+ public void shouldConvertCollectionToSet() {
+ Collection<String> collection = Arrays.asList("a", "b", "c");
+ Set<String> result = CollectionUtil.asSet(collection);
+ assertEquals(new LinkedHashSet<>(collection), result);
+ }
+
+ @Test
+ public void shouldConvertVarargsToMap() {
+ Map<String, String> result = CollectionUtil.asMap("key1", "value1", "key2", "value2");
+ Map<String, String> expected = new LinkedHashMap<>();
+ expected.put("key1", "value1");
+ expected.put("key2", "value2");
+ assertEquals(expected, result);
+ }
+
+ @Test
+ public void shouldConvertVarargsToMapWithOddNumberOfElements() {
+ Map<String, String> result = CollectionUtil.asMap("key1", "value1", "key2");
+ Map<String, String> expected = new LinkedHashMap<>();
+ expected.put("key1", "value1");
+ expected.put("key2", null);
+ assertEquals(expected, result);
+ }
}
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs
index 98f8b0b5b4..98d49d8df7 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs
@@ -115,13 +115,6 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
_parameters.Add(name, parsedValue);
}
- [Given("using the parameter (\\w+) of P.(\\w+)\\(\"(.*)\"\\)")]
- public void UsingParameterP(string name, string pval, string value)
- {
- var parsedValue = ParseValue(value.Replace("\\\"", "\""), _graphName!);
- _parameters.Add(name, new P(pval, parsedValue));
- }
-
[Given("the traversal of")]
public void TranslateTraversal(string traversalText)
{
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
index e72e7aa112..b324e8be68 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
@@ -63,17 +63,17 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
new Dictionary<string, List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>>
{
{"g_V_branchXlabel_eq_person__a_bX_optionXa__ageX_optionXb__langX_optionXb__nameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>()}, // skipping as it contains a lambda
- {"g_V_branchXlabel_isXpersonX_countX_optionX1__ageX_optionX0__langX_optionX0__nameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Branch<object>(__.Label().Is("person").Count()).Option(p["xx1"], (ITraversal) __.Values<object>("age")).Option(p["xx2"], (ITraversal) __.Values<object>("lang")).Option(p["xx2"], (ITraversal) __.Values<object>("name"))}},
- {"g_V_branchXlabel_isXpersonX_countX_optionX1__ageX_optionX0__langX_optionX0__nameX_optionXany__labelX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Branch<object>(__.Label().Is("person").Count()).Option(p["xx1"], (ITraversal) __.Values<object>("age")).Option(p["xx2"], (ITraversal) __.Values<object>("lang")).Option(p["xx2"], (ITraversal) __.Values<object>("name")).Option(Pick.Any, __.Label())}},
+ {"g_V_branchXlabel_isXpersonX_countX_optionX1__ageX_optionX0__langX_optionX0__nameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Branch<object>(__.Label().Is("person").Count()).Option(p["xx1"], __.Values<object>("age")).Option(p["xx2"], __.Values<object>("lang")).Option(p["xx2"], __.Values<object>("name"))}},
+ {"g_V_branchXlabel_isXpersonX_countX_optionX1__ageX_optionX0__langX_optionX0__nameX_optionXany__labelX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Branch<object>(__.Label().Is("person").Count()).Option(p["xx1"], __.Values<object>("age")).Option(p["xx2"], __.Values<object>("lang")).Option(p["xx2"], __.Values<object>("name")).Option(Pick.Any, __.Label())}},
{"g_V_branchXageX_optionXltX30X__youngX_optionXgtX30X__oldX_optionXnone__on_the_edgeX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Branch<object>(__.Values<object>("age")).Option(P.Lt(30), __.Constant<object>("young")).Option(P.Gt(30), __.Constant<object>("old")).Option(Pick.None, __.Constant<object>("on the edge"))}},
{"g_V_branchXidentityX_optionXhasLabelXsoftwareX__inXcreatedX_name_order_foldX_optionXhasXname_vadasX__ageX_optionXneqX123X__bothE_countX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Branch<object>(__.Identity()).Option(__.HasLabel("software"), __.In("created").Values<object>("name").Order().Fold()).Option(__.Has("name", "vadas"), __.Values<object>("age")).Option(P.Neq(123), __.BothE().Count())}},
- {"g_V_chooseXout_countX_optionX2L_nameX_optionX3L_ageX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Choose<object>(__.Out().Count()).Option(p["xx1"], (ITraversal) __.Values<object>("name")).Option(p["xx2"], (ITraversal) __.Values<object>("age"))}},
+ {"g_V_chooseXout_countX_optionX2L_nameX_optionX3L_ageX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Choose<object>(__.Out().Count()).Option(p["xx1"], __.Values<object>("name")).Option(p["xx2"], __.Values<object>("age"))}},
{"g_V_chooseXlabel_eqXpersonX__outXknowsX__inXcreatedXX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>()}, // skipping as it contains a lambda
{"g_V_chooseXhasLabelXpersonX_and_outXcreatedX__outXknowsX__identityX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Choose<object>(__.HasLabel("person").And().Out("created"), __.Out("knows"), __.Identity()).Values<object>("name")}},
{"g_V_chooseXlabelX_optionXblah__outXknowsXX_optionXbleep__outXcreatedXX_optionXnone__identityX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Choose<object>(__.Label()).Option("blah", __.Out("knows")).Option("bleep", __.Out("created")).Option(Pick.None, __.Identity()).Values<object>("name")}},
{"g_V_chooseXoutXknowsX_count_isXgtX0XX__outXknowsXX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Choose<object>(__.Out("knows").Count().Is(P.Gt(0)), __.Out("knows")).Values<object>("name")}},
{"g_V_hasLabelXpersonX_asXp1X_chooseXoutEXknowsX__outXknowsXX_asXp2X_selectXp1_p2X_byXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").As("p1").Choose<object>(__.OutE("knows"), __.Out("knows")).As("p2").Select<object>("p1", "p2").By("name")}},
- {"g_V_hasLabelXpersonX_chooseXageX__optionX27L__constantXyoungXX_optionXnone__constantXoldXX_groupCount", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Choose<object>(__.Values<object>("age")).Option(p["xx1"], (ITraversal) __.Constant<object>("young")).Option(Pick.None, __.Constant<object>("old")).GroupCount<object>()}},
+ {"g_V_hasLabelXpersonX_chooseXageX__optionX27L__constantXyoungXX_optionXnone__constantXoldXX_groupCount", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Choose<object>(__.Values<object>("age")).Option(p["xx1"], __.Constant<object>("young")).Option(Pick.None, __.Constant<object>("old")).GroupCount<object>()}},
{"g_injectX1X_chooseXisX1X__constantX10Xfold__foldX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(p["xx2"]).Choose<object>(__.Is(p["xx2"]), __.Constant<object>(p["xx1"]).Fold(), __.Fold<object>())}},
{"g_injectX2X_chooseXisX1X__constantX10Xfold__foldX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(p["xx3"]).Choose<object>(__.Is(p["xx2"]), __.Constant<object>(p["xx1"]).Fold(), __.Fold<object>())}},
{"g_V_localXpropertiesXlocationX_order_byXvalueX_limitX2XX_value", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Local<object>(__.Properties<object>("location").Order().By(T.Value, Order.Asc).Range<object>(0, 2)).Value<object>()}},
@@ -234,6 +234,8 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
{"g_VX1X_out_hasXid_2X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V((Vertex) p["v2"]).Has("age", P.Gt(30))}},
{"g_V_hasXblahX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("blah")}},
{"g_V_hasXperson_name_markoX_age", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("person", "name", "marko").Values<object>("age")}},
+ {"g_V_hasXperson_name_markovarX_age", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("person", "name", (object) p["xx1"]).Values<object>("age")}},
+ {"g_V_hasXpersonvar_name_markoX_age", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has((string) p["xx1"], "name", "marko").Values<object>("age")}},
{"g_VX1X_outE_hasXweight_inside_0_06X_inV", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).OutE().Has("weight", P.Inside(0.0, 0.6)).InV()}},
{"g_EX11X_outV_outE_hasXid_10X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E(p["eid11"]).OutV().OutE().Has(T.Id, (object) p["eid10"])}},
{"g_EX11X_outV_outE_hasXid_10AsStringX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E(p["eid11"]).OutV().OutE().Has(T.Id, (object) p["eid10"])}},
@@ -269,9 +271,9 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
{"g_V_hasXlabel_isXpersonXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has(T.Label, __.Is("person"))}},
{"g_V_hasXname_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name", (object) null)}},
{"g_V_hasIdXemptyX_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasId(p["xx1"]).Count()}},
- {"g_V_hasIdXwithinXemptyXX_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasId(p["xx1"]).Count()}},
- {"g_V_hasIdXwithoutXemptyXX_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasId(p["xx1"]).Count()}},
- {"g_V_notXhasIdXwithinXemptyXXX_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Not(__.HasId(p["xx1"])).Count()}},
+ {"g_V_hasIdXwithinXemptyXX_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasId(P.Within(new List<object> { })).Count()}},
+ {"g_V_hasIdXwithoutXemptyXX_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasId(P.Without(new List<object> { })).Count()}},
+ {"g_V_notXhasIdXwithinXemptyXXX_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Not(__.HasId(P.Within(new List<object> { }))).Count()}},
{"g_V_hasIdXnullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasId(null)}},
{"g_V_hasIdXeqXnullXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasId(P.Eq(null))}},
{"g_V_hasIdX2_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasId(p["vid2"], null)}},
@@ -279,7 +281,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
{"g_V_hasIdX1AsString_2AsString_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasId(p["vid1"], p["vid2"], null)}},
{"g_V_hasIdXnull_2X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasId(null, p["vid2"])}},
{"g_V_hasIdX1X_hasIdX2X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasId(p["vid1"]).HasId(p["vid2"])}},
- {"g_V_in_hasIdXneqX1XX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().In().HasId(p["xx1"])}},
+ {"g_V_in_hasIdXneqX1XX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().In().HasId(P.Neq(p["xx1"]))}},
{"g_VX1X_out_hasIdX2X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out().HasId(p["vid2"])}},
{"g_VX1X_out_hasXid_2_3X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out().HasId(p["vid2"], p["vid3"])}},
{"g_VX1X_out_hasXid_2AsString_3AsStringX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out().HasId(p["vid2"], p["vid3"])}},
@@ -292,21 +294,23 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
{"g_V_bothE_properties_dedup_hasKeyXweightX_value", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().BothE().Properties<object>().Dedup().HasKey("weight").Value<object>()}},
{"g_V_bothE_properties_dedup_hasKeyXweightX_hasValueXltX0d3XX_value", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().BothE().Properties<object>().Dedup().HasKey("weight").HasValue(P.Lt(0.3)).Value<object>(), (g,p) =>g.V().BothE().Properties<object>().Dedup().HasKey("weight").HasValue(P.Lt(0.3)).Value<object>()}},
{"g_V_properties_hasKeyXnullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Properties<object>().HasKey((string) null)}},
- {"g_V_properties_hasKeyXnull_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Properties<object>().HasKey(null, null)}},
+ {"g_V_properties_hasKeyXnull_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Properties<object>().HasKey(null, (string) null)}},
{"g_V_properties_hasKeyXnull_ageX_value", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Properties<object>().HasKey(null, "age").Value<object>()}},
{"g_E_properties_hasKeyXnullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E().Properties<object>().HasKey((string) null)}},
- {"g_E_properties_hasKeyXnull_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E().Properties<object>().HasKey(null, null)}},
+ {"g_E_properties_hasKeyXnull_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E().Properties<object>().HasKey(null, (string) null)}},
{"g_E_properties_hasKeyXnull_weightX_value", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E().Properties<object>().HasKey(null, "weight").Value<object>()}},
{"g_EX7X_hasLabelXknowsX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E(p["eid7"]).HasLabel("knows")}},
{"g_E_hasLabelXknowsX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E().HasLabel("knows")}},
{"g_E_hasLabelXuses_traversesX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E().HasLabel("uses", "traverses")}},
{"g_V_hasLabelXperson_software_blahX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person", "software", "blah")}},
{"g_V_hasLabelXpersonX_hasLabelXsoftwareX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").HasLabel("software")}},
+ {"g_V_hasLabelXpersonvarX_hasLabelXsoftwareX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel((string) p["xx1"]).HasLabel("software")}},
+ {"g_V_hasLabelXpersonvar_softwarevarX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel((string) p["xx1"], (string) p["xx2"])}},
{"g_V_hasLabelXpersonX_hasXage_notXlteX10X_andXnotXbetweenX11_20XXXX_andXltX29X_orXeqX35XXXX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Has("age", P.Not(P.Lte(10).And(P.Not(P.Between(11, 20)))).And(P.Lt(29).Or(P.Eq(35)))).Values<object>("name")}},
{"g_V_hasLabelXnullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel((string) null)}},
{"g_V_hasXlabel_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has(T.Label, (object) null)}},
- {"g_V_hasLabelXnull_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel(null, null)}},
- {"g_V_hasLabelXnull_personX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel(null, "person")}},
+ {"g_V_hasLabelXnull_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel((string) null, (string) null)}},
+ {"g_V_hasLabelXnull_personX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel((string) null, "person")}},
{"g_E_hasLabelXnullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E().HasLabel((string) null)}},
{"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)}},
@@ -695,7 +699,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
{"g_injectXaX_concat_Xinject_List_b_cX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>("a").Concat(__.Inject(p["xx1"]))}},
{"g_injectXListXa_bXcX_concat_XdX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(p["xx1"], "c").Concat("d")}},
{"g_injectXnullX_concat_XinjectX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(null).Concat()}},
- {"g_injectXnull_aX_concat_Xnull_bX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(null, "a").Concat(null, "b")}},
+ {"g_injectXnull_aX_concat_Xnull_bX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(null, "a").Concat((string) null, "b")}},
{"g_injectXhello_hiX_concat_XV_valuesXnameXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>("hello", "hi").Concat(__.V().Order().By(T.Id).Values<object>("name"))}},
{"g_V_hasLabel_value_concat_X_X_concat_XpersonX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Values<object>("name").Concat(" ").Concat("person")}},
{"g_hasLabelXpersonX_valuesXnameX_asXaX_constantXMrX_concatXselectXaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Values<object>("name").As("a").Constant<object>("Mr.").Concat(__.Select<object>("a"))}},
@@ -703,17 +707,18 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
{"g_VX1X_outE_asXaX_VX1X_valuesXnamesX_concatXselectXaX_labelX_concatXselectXaX_inV_valuesXnameXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).OutE().As("a").V(p["vid1"]).Values<object>("name").Concat(__.Select<object>("a").Label()).Concat(__.Select<object>("a").InV().Values<object>("name"))}},
{"g_VX1X_outE_asXaX_VX1X_valuesXnamesX_concatXselectXaX_label_selectXaX_inV_valuesXnameXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).OutE().As("a").V(p["vid1"]).Values<object>("name").Concat(__.Select<object>("a").Label(), __.Select<object>("a").InV().Values<object>("name"))}},
{"g_addVXconstantXprefix_X_concatXVX1X_labelX_label", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name", "marko").Property("age", 29).As("marko").AddV("person").Property("name", "vadas").Property("age", 27).As("vadas").AddV("software").Property("name", "lop").Property("lang", "java").As("lop").AddV("person").Property("name", "josh").Property("age", 32).As("josh").AddV("software").Property("name", "ripple [...]
- {"g_injectXnullX_conjoinX1X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(null).Conjoin("1")}},
- {"g_V_valuesXnameX_conjoinX1X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name").Conjoin("1")}},
- {"g_V_valuesXnonexistantX_fold_conjoinX_X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("nonexistant").Fold().Conjoin(";")}},
- {"g_V_valuesXnameX_order_fold_conjoinX_X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name").Order().Fold().Conjoin("_")}},
- {"g_V_valuesXageX_order_fold_conjoinX_X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Order().Fold().Conjoin(";")}},
- {"g_V_out_path_byXvaluesXnameX_toUpperX_conjoinXMARKOX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Out().Path().By(__.Values<object>("name").ToUpper()).Conjoin("MARKO")}},
- {"g_injectXmarkoX_conjoinX_X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(p["xx1"]).Conjoin("-")}},
- {"g_V_valueMapXlocationX_selectXvaluesX_unfold_orderXlocalX_conjoinX1X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ValueMap<object, object>("location").Select<object>(Column.Values).Unfold<object>().Order(Scope.Local).Conjoin("1")}},
- {"g_V_out_out_path_byXnameX_conjoinXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Out().Out().Path().By("name").Conjoin("")}},
- {"g_injectXa_null_bX_conjoinXxyzX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(p["xx1"]).Conjoin("xyz")}},
- {"g_injectX3_threeX_conjoinX_X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(p["xx1"]).Conjoin(";")}},
+ {"g_injectXnullX_conjoinX1X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(null).Conjoin((string) "1")}},
+ {"g_V_valuesXnameX_conjoinX1X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name").Conjoin((string) "1")}},
+ {"g_V_valuesXnonexistantX_fold_conjoinX_X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("nonexistant").Fold().Conjoin((string) ";")}},
+ {"g_V_valuesXnameX_order_fold_conjoinX_X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name").Order().Fold().Conjoin((string) "_")}},
+ {"g_V_valuesXageX_order_fold_conjoinXsemicolonX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Order().Fold().Conjoin((string) ";")}},
+ {"g_V_valuesXageX_order_fold_conjoinXslashX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Order().Fold().Conjoin((string) p["xx1"])}},
+ {"g_V_out_path_byXvaluesXnameX_toUpperX_conjoinXMARKOX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Out().Path().By(__.Values<object>("name").ToUpper()).Conjoin((string) "MARKO")}},
+ {"g_injectXmarkoX_conjoinX_X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(p["xx1"]).Conjoin((string) "-")}},
+ {"g_V_valueMapXlocationX_selectXvaluesX_unfold_orderXlocalX_conjoinX1X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ValueMap<object, object>("location").Select<object>(Column.Values).Unfold<object>().Order(Scope.Local).Conjoin((string) "1")}},
+ {"g_V_out_out_path_byXnameX_conjoinXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Out().Out().Path().By("name").Conjoin((string) "")}},
+ {"g_injectXa_null_bX_conjoinXxyzX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(p["xx1"]).Conjoin((string) "xyz")}},
+ {"g_injectX3_threeX_conjoinX_X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(p["xx1"]).Conjoin((string) ";")}},
{"g_V_connectedComponent_hasXcomponentX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ConnectedComponent().Has("gremlin.connectedComponentVertexProgram.component")}},
{"g_V_dedup_connectedComponent_hasXcomponentX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Dedup().ConnectedComponent().Has("gremlin.connectedComponentVertexProgram.component")}},
{"g_V_hasLabelXsoftwareX_connectedComponent_project_byXnameX_byXcomponentX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("software").ConnectedComponent().Project<object>("name", "component").By("name").By("gremlin.connectedComponentVertexProgram.component")}},
@@ -797,7 +802,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
{"g_V_elementMap", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ElementMap<object>()}},
{"g_V_elementMapXname_ageX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ElementMap<object>("name", "age")}},
{"g_EX11X_elementMap", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E(p["eid11"]).ElementMap<object>()}},
- {"g_V_elementMapXname_age_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ElementMap<object>("name", "age", null)}},
+ {"g_V_elementMapXname_age_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ElementMap<object>("name", "age", (string) null)}},
{"g_V_asXaX_flatMapXselectXaXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").FlatMap<object>(__.Select<object>("a"))}},
{"g_V_fold", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Fold()}},
{"g_V_fold_unfold", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Fold().Unfold<object>()}},
@@ -1169,8 +1174,8 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
{"g_V_hasXageX_propertiesXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("age").Properties<object>("name").Value<object>()}},
{"g_V_hasXageX_propertiesXname_ageX_value", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("age").Properties<object>("name", "age").Value<object>()}},
{"g_V_hasXageX_propertiesXage_nameX_value", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("age").Properties<object>("age", "name").Value<object>()}},
- {"g_V_propertiesXname_age_nullX_value", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Properties<object>("name", "age", null).Value<object>()}},
- {"g_V_valuesXname_age_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name", "age", null)}},
+ {"g_V_propertiesXname_age_nullX_value", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Properties<object>("name", "age", (string) null).Value<object>()}},
+ {"g_V_valuesXname_age_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name", "age", (string) null)}},
{"g_injectX__feature___test__nullX_rTrim", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>("feature ", "one test ", null, "", " ", " abc", "abc ", " abc ", "  ").RTrim()}},
{"g_injectX__feature___test__nullX_rTrimXlocalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(new List<object> { " feature ", " one test ", null, "", " ", " abc", "abc ", " abc ", "  " }).RTrim<object>(Scope.Local)}},
{"g_injectX__feature__X_rTrim", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(" feature ").RTrim()}},
@@ -1356,7 +1361,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
{"g_V_hasLabelXpersonX_filterXoutEXcreatedXX_valueMapXtrueX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Filter(__.OutE("created")).ValueMap<object, object>(true)}},
{"g_V_hasLabelXpersonX_filterXoutEXcreatedXX_valueMap_withXtokensX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Filter(__.OutE("created")).ValueMap<object, object>().With(WithOptions.Tokens)}},
{"g_VX1X_valueMapXname_locationX_byXunfoldX_by", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).ValueMap<object, object>("name", "location").By(__.Unfold<object>()).By()}},
- {"g_V_valueMapXname_age_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ValueMap<object, object>("name", "age", null)}},
+ {"g_V_valueMapXname_age_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ValueMap<object, object>("name", "age", (string) null)}},
{"g_V_valueMapXname_ageX_byXisXxXXbyXunfoldX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ValueMap<object, object>("name", "age").By(__.Is("x")).By(__.Unfold<object>())}},
{"g_VXnullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(null)}},
{"g_VXlistXnullXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["xx1"])}},
diff --git a/gremlin-go/driver/cucumber/cucumberSteps_test.go b/gremlin-go/driver/cucumber/cucumberSteps_test.go
index fd49c7d8b4..38fbdb6207 100644
--- a/gremlin-go/driver/cucumber/cucumberSteps_test.go
+++ b/gremlin-go/driver/cucumber/cucumberSteps_test.go
@@ -47,7 +47,7 @@ var parsers map[*regexp.Regexp]func(string, string) interface{}
func init() {
parsers = map[*regexp.Regexp]func(string, string) interface{}{
- regexp.MustCompile(`^str\[(.*)]$`): func(stringVal, graphName string) interface{} { return stringVal }, //returns the string value as is
+ regexp.MustCompile(`^str\[(.*)]$`): func(stringVal, graphName string) interface{} { return stringVal }, //returns the string value as is
regexp.MustCompile(`^dt\[(.*)]$`): toDateTime,
regexp.MustCompile(`^d\[(.*)]\.[bslfdmn]$`): toNumeric,
regexp.MustCompile(`^d\[(.*)]\.[i]$`): toInt32,
@@ -821,18 +821,6 @@ func (tg *tinkerPopGraph) usingTheParameterDefined(name string, params string) e
return nil
}
-func (tg *tinkerPopGraph) usingTheParameterOfP(paramName, pVal, stringVal string) error {
- predicate := reflect.ValueOf(gremlingo.P).MethodByName(strings.Title(pVal)).Interface().(func(...interface{}) gremlingo.Predicate)
- values := parseValue(stringVal, tg.graphName)
- switch reflect.TypeOf(values).Kind() {
- case reflect.Array, reflect.Slice:
- tg.parameters[paramName] = predicate(values.([]interface{})...)
- default:
- tg.parameters[paramName] = predicate(values)
- }
- return nil
-}
-
func (tg *tinkerPopGraph) theTraversalWillRaiseAnError() error {
if _, ok := tg.error[true]; ok {
return nil
@@ -912,7 +900,6 @@ func InitializeScenario(ctx *godog.ScenarioContext) {
ctx.Step(`^the result should have a count of (\d+)$`, tg.theResultShouldHaveACountOf)
ctx.Step(`^the traversal of$`, tg.theTraversalOf)
ctx.Step(`^using the parameter (.+) defined as "(.+)"$`, tg.usingTheParameterDefined)
- ctx.Step(`^using the parameter (.+) of P\.(.+)\("(.+)"\)$`, tg.usingTheParameterOfP)
ctx.Step(`^the traversal will raise an error$`, tg.theTraversalWillRaiseAnError)
ctx.Step(`^the traversal will raise an error with message (\w+) text of "(.+)"$`, tg.theTraversalWillRaiseAnErrorWithMessageContainingTextOf)
}
diff --git a/gremlin-go/driver/cucumber/gremlin.go b/gremlin-go/driver/cucumber/gremlin.go
index 591bdd0c7c..667ae6d1f3 100644
--- a/gremlin-go/driver/cucumber/gremlin.go
+++ b/gremlin-go/driver/cucumber/gremlin.go
@@ -204,6 +204,8 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[
"g_VX1X_out_hasXid_2X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["v2"]).Has("age", gremlingo.P.Gt(30))}},
"g_V_hasXblahX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("blah")}},
"g_V_hasXperson_name_markoX_age": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("person", "name", "marko").Values("age")}},
+ "g_V_hasXperson_name_markovarX_age": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("person", "name", p["xx1"]).Values("age")}},
+ "g_V_hasXpersonvar_name_markoX_age": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has(p["xx1"], "name", "marko").Values("age")}},
"g_VX1X_outE_hasXweight_inside_0_06X_inV": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).OutE().Has("weight", gremlingo.P.Inside(0.0, 0.6)).InV()}},
"g_EX11X_outV_outE_hasXid_10X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E(p["eid11"]).OutV().OutE().Has(gremlingo.T.Id, p["eid10"])}},
"g_EX11X_outV_outE_hasXid_10AsStringX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E(p["eid11"]).OutV().OutE().Has(gremlingo.T.Id, p["eid10"])}},
@@ -239,9 +241,9 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[
"g_V_hasXlabel_isXpersonXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has(gremlingo.T.Label, gremlingo.T__.Is("person"))}},
"g_V_hasXname_nullX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", nil)}},
"g_V_hasIdXemptyX_count": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasId(p["xx1"]).Count()}},
- "g_V_hasIdXwithinXemptyXX_count": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasId(p["xx1"]).Count()}},
- "g_V_hasIdXwithoutXemptyXX_count": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasId(p["xx1"]).Count()}},
- "g_V_notXhasIdXwithinXemptyXXX_count": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Not(gremlingo.T__.HasId(p["xx1"])).Count()}},
+ "g_V_hasIdXwithinXemptyXX_count": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasId(gremlingo.P.Within([]interface{}{})).Count()}},
+ "g_V_hasIdXwithoutXemptyXX_count": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasId(gremlingo.P.Without([]interface{}{})).Count()}},
+ "g_V_notXhasIdXwithinXemptyXXX_count": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Not(gremlingo.T__.HasId(gremlingo.P.Within([]interface{}{}))).Count()}},
"g_V_hasIdXnullX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasId(nil)}},
"g_V_hasIdXeqXnullXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasId(gremlingo.P.Eq(nil))}},
"g_V_hasIdX2_nullX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasId(p["vid2"], nil)}},
@@ -249,7 +251,7 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[
"g_V_hasIdX1AsString_2AsString_nullX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasId(p["vid1"], p["vid2"], nil)}},
"g_V_hasIdXnull_2X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasId(nil, p["vid2"])}},
"g_V_hasIdX1X_hasIdX2X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasId(p["vid1"]).HasId(p["vid2"])}},
- "g_V_in_hasIdXneqX1XX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().In().HasId(p["xx1"])}},
+ "g_V_in_hasIdXneqX1XX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().In().HasId(gremlingo.P.Neq(p["xx1"]))}},
"g_VX1X_out_hasIdX2X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Out().HasId(p["vid2"])}},
"g_VX1X_out_hasXid_2_3X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Out().HasId(p["vid2"], p["vid3"])}},
"g_VX1X_out_hasXid_2AsString_3AsStringX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Out().HasId(p["vid2"], p["vid3"])}},
@@ -272,6 +274,8 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[
"g_E_hasLabelXuses_traversesX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E().HasLabel("uses", "traverses")}},
"g_V_hasLabelXperson_software_blahX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("person", "software", "blah")}},
"g_V_hasLabelXpersonX_hasLabelXsoftwareX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("person").HasLabel("software")}},
+ "g_V_hasLabelXpersonvarX_hasLabelXsoftwareX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel(p["xx1"]).HasLabel("software")}},
+ "g_V_hasLabelXpersonvar_softwarevarX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel(p["xx1"], p["xx2"])}},
"g_V_hasLabelXpersonX_hasXage_notXlteX10X_andXnotXbetweenX11_20XXXX_andXltX29X_orXeqX35XXXX_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("person").Has("age", gremlingo.P.Not(gremlingo.P.Lte(10).And(gremlingo.P.Not(gremlingo.P.Between(11, 20)))).And(gremlingo.P.Lt(29).Or(gremlingo.P.Eq(35)))).Values("name")}},
"g_V_hasLabelXnullX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel(nil)}},
"g_V_hasXlabel_nullX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has(gremlingo.T.Label, nil)}},
@@ -677,7 +681,8 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[
"g_V_valuesXnameX_conjoinX1X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("name").Conjoin("1")}},
"g_V_valuesXnonexistantX_fold_conjoinX_X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("nonexistant").Fold().Conjoin(";")}},
"g_V_valuesXnameX_order_fold_conjoinX_X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("name").Order().Fold().Conjoin("_")}},
- "g_V_valuesXageX_order_fold_conjoinX_X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Order().Fold().Conjoin(";")}},
+ "g_V_valuesXageX_order_fold_conjoinXsemicolonX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Order().Fold().Conjoin(";")}},
+ "g_V_valuesXageX_order_fold_conjoinXslashX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Order().Fold().Conjoin(p["xx1"])}},
"g_V_out_path_byXvaluesXnameX_toUpperX_conjoinXMARKOX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Out().Path().By(gremlingo.T__.Values("name").ToUpper()).Conjoin("MARKO")}},
"g_injectXmarkoX_conjoinX_X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(p["xx1"]).Conjoin("-")}},
"g_V_valueMapXlocationX_selectXvaluesX_unfold_orderXlocalX_conjoinX1X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().ValueMap("location").Select(gremlingo.Column.Values).Unfold().Order(gremlingo.Scope.Local).Conjoin("1")}},
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/feature-steps.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/feature-steps.js
index e590415406..bad8161e70 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/feature-steps.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/feature-steps.js
@@ -117,10 +117,6 @@ Given('the traversal of', function (traversalText) {
this.traversal = gremlin[this.scenario].shift()(p);
});
-Given(/^using the parameter (.+) of P\.(.+)\("(.+)"\)$/, function (paramName, pval, stringValue) {
- this.parameters[paramName] = new P(pval, parseValue.call(this, stringValue))
-});
-
Given(/^using the parameter (.+) defined as "(.+)"$/, function (paramName, stringValue) {
// Remove escaped chars
stringValue = stringValue.replace(/\\"/g, '"');
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
index 5251007c64..89e85ac91d 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
@@ -225,6 +225,8 @@ const gremlins = {
g_VX1X_out_hasXid_2X: [function({g, v2}) { return g.V(v2).has("age", P.gt(30)) }],
g_V_hasXblahX: [function({g}) { return g.V().has("blah") }],
g_V_hasXperson_name_markoX_age: [function({g}) { return g.V().has("person", "name", "marko").values("age") }],
+ g_V_hasXperson_name_markovarX_age: [function({g, xx1}) { return g.V().has("person", "name", xx1).values("age") }],
+ g_V_hasXpersonvar_name_markoX_age: [function({g, xx1}) { return g.V().has(xx1, "name", "marko").values("age") }],
g_VX1X_outE_hasXweight_inside_0_06X_inV: [function({g, vid1}) { return g.V(vid1).outE().has("weight", P.inside(0.0, 0.6)).inV() }],
g_EX11X_outV_outE_hasXid_10X: [function({g, eid11, eid10}) { return g.E(eid11).outV().outE().has(T.id, eid10) }],
g_EX11X_outV_outE_hasXid_10AsStringX: [function({g, eid11, eid10}) { return g.E(eid11).outV().outE().has(T.id, eid10) }],
@@ -260,9 +262,9 @@ const gremlins = {
g_V_hasXlabel_isXpersonXX: [function({g}) { return g.V().has(T.label, __.is("person")) }],
g_V_hasXname_nullX: [function({g}) { return g.V().has("name", null) }],
g_V_hasIdXemptyX_count: [function({g, xx1}) { return g.V().hasId(xx1).count() }],
- g_V_hasIdXwithinXemptyXX_count: [function({g, xx1}) { return g.V().hasId(xx1).count() }],
- g_V_hasIdXwithoutXemptyXX_count: [function({g, xx1}) { return g.V().hasId(xx1).count() }],
- g_V_notXhasIdXwithinXemptyXXX_count: [function({g, xx1}) { return g.V().not(__.hasId(xx1)).count() }],
+ g_V_hasIdXwithinXemptyXX_count: [function({g}) { return g.V().hasId(P.within([])).count() }],
+ g_V_hasIdXwithoutXemptyXX_count: [function({g}) { return g.V().hasId(P.without([])).count() }],
+ g_V_notXhasIdXwithinXemptyXXX_count: [function({g}) { return g.V().not(__.hasId(P.within([]))).count() }],
g_V_hasIdXnullX: [function({g}) { return g.V().hasId(null) }],
g_V_hasIdXeqXnullXX: [function({g}) { return g.V().hasId(P.eq(null)) }],
g_V_hasIdX2_nullX: [function({g, vid2}) { return g.V().hasId(vid2, null) }],
@@ -270,7 +272,7 @@ const gremlins = {
g_V_hasIdX1AsString_2AsString_nullX: [function({g, vid2, vid1}) { return g.V().hasId(vid1, vid2, null) }],
g_V_hasIdXnull_2X: [function({g, vid2}) { return g.V().hasId(null, vid2) }],
g_V_hasIdX1X_hasIdX2X: [function({g, vid2, vid1}) { return g.V().hasId(vid1).hasId(vid2) }],
- g_V_in_hasIdXneqX1XX: [function({g, xx1}) { return g.V().in_().hasId(xx1) }],
+ g_V_in_hasIdXneqX1XX: [function({g, xx1}) { return g.V().in_().hasId(P.neq(xx1)) }],
g_VX1X_out_hasIdX2X: [function({g, vid2, vid1}) { return g.V(vid1).out().hasId(vid2) }],
g_VX1X_out_hasXid_2_3X: [function({g, vid3, vid2, vid1}) { return g.V(vid1).out().hasId(vid2, vid3) }],
g_VX1X_out_hasXid_2AsString_3AsStringX: [function({g, vid3, vid2, vid1}) { return g.V(vid1).out().hasId(vid2, vid3) }],
@@ -293,6 +295,8 @@ const gremlins = {
g_E_hasLabelXuses_traversesX: [function({g}) { return g.E().hasLabel("uses", "traverses") }],
g_V_hasLabelXperson_software_blahX: [function({g}) { return g.V().hasLabel("person", "software", "blah") }],
g_V_hasLabelXpersonX_hasLabelXsoftwareX: [function({g}) { return g.V().hasLabel("person").hasLabel("software") }],
+ g_V_hasLabelXpersonvarX_hasLabelXsoftwareX: [function({g, xx1}) { return g.V().hasLabel(xx1).hasLabel("software") }],
+ g_V_hasLabelXpersonvar_softwarevarX: [function({g, xx1, xx2}) { return g.V().hasLabel(xx1, xx2) }],
g_V_hasLabelXpersonX_hasXage_notXlteX10X_andXnotXbetweenX11_20XXXX_andXltX29X_orXeqX35XXXX_name: [function({g}) { return g.V().hasLabel("person").has("age", P.not(P.lte(10).and(P.not(P.between(11, 20)))).and(P.lt(29).or(P.eq(35)))).values("name") }],
g_V_hasLabelXnullX: [function({g}) { return g.V().hasLabel(null) }],
g_V_hasXlabel_nullX: [function({g}) { return g.V().has(T.label, null) }],
@@ -694,7 +698,8 @@ const gremlins = {
g_V_valuesXnameX_conjoinX1X: [function({g}) { return g.V().values("name").conjoin("1") }],
g_V_valuesXnonexistantX_fold_conjoinX_X: [function({g}) { return g.V().values("nonexistant").fold().conjoin(";") }],
g_V_valuesXnameX_order_fold_conjoinX_X: [function({g}) { return g.V().values("name").order().fold().conjoin("_") }],
- g_V_valuesXageX_order_fold_conjoinX_X: [function({g}) { return g.V().values("age").order().fold().conjoin(";") }],
+ g_V_valuesXageX_order_fold_conjoinXsemicolonX: [function({g}) { return g.V().values("age").order().fold().conjoin(";") }],
+ g_V_valuesXageX_order_fold_conjoinXslashX: [function({g, xx1}) { return g.V().values("age").order().fold().conjoin(xx1) }],
g_V_out_path_byXvaluesXnameX_toUpperX_conjoinXMARKOX: [function({g}) { return g.V().out().path().by(__.values("name").toUpper()).conjoin("MARKO") }],
g_injectXmarkoX_conjoinX_X: [function({g, xx1}) { return g.inject(xx1).conjoin("-") }],
g_V_valueMapXlocationX_selectXvaluesX_unfold_orderXlocalX_conjoinX1X: [function({g}) { return g.V().valueMap("location").select(Column.values).unfold().order(Scope.local).conjoin("1") }],
@@ -768,12 +773,32 @@ const gremlins = {
g_injectXa_null_bX_disjunctXa_cX: [function({g, xx1, xx2}) { return g.inject(xx1).disjunct(xx2) }],
g_injectXa_null_bX_disjunctXa_null_cX: [function({g, xx1, xx2}) { return g.inject(xx1).disjunct(xx2) }],
g_injectX3_threeX_disjunctXfive_three_7X: [function({g, xx1, xx2}) { return g.inject(xx1).disjunct(xx2) }],
+ g_E: [function({g}) { return g.E() }],
+ g_EX11X: [function({g, eid11}) { return g.E(eid11) }],
+ g_EX11AsStringX: [function({g, eid11}) { return g.E(eid11) }],
+ g_EXe11X: [function({g, e11}) { return g.E(e11) }],
+ g_EXe7_e11X: [function({g, e7, e11}) { return g.E(e7, e11) }],
+ g_EXlistXe7_e11XX: [function({g, xx1}) { return g.E(xx1) }],
+ g_EXnullX: [function({g}) { return g.E(null) }],
+ g_EXlistXnullXX: [function({g, xx1}) { return g.E(xx1) }],
+ g_EX11_nullX: [function({g, eid11}) { return g.E(eid11, null) }],
g_V_EX11X: [function({g, eid11}) { return g.V().E(eid11) }],
g_EX11X_E: [function({g, eid11}) { return g.E(eid11).E() }],
g_V_EXnullX: [function({g}) { return g.V().E(null) }],
g_V_EXlistXnullXX: [function({g, xx1}) { return g.V().E(xx1) }],
g_injectX1X_EX11_nullX: [function({g, eid11}) { return g.inject(1).E(eid11, null) }],
g_injectX1X_coalesceXEX_hasLabelXtestsX_addEXtestsX_from_V_hasXnameX_XjoshXX_toXV_hasXnameX_XvadasXXX: [function({g}) { return g.addV("person").property("name", "josh").addV("person").property("name", "vadas") }, function({g}) { return g.inject(1).coalesce(__.E().hasLabel("tests"), __.addE("tests").from_(__.V().has("name", "josh")).to(__.V().has("name", "vadas"))) }, function({g}) { return g.E().hasLabel("tests") }],
+ g_VX1X_outE_inV: [function({g, vid1}) { return g.V(vid1).outE().inV() }],
+ g_VX2X_inE_outV: [function({g, vid2}) { return g.V(vid2).inE().outV() }],
+ g_V_outE_hasXweight_1X_outV: [function({g}) { return g.V().outE().has("weight", 1.0).outV() }],
+ g_VX1X_outE_otherV: [function({g, vid1}) { return g.V(vid1).outE().otherV() }],
+ g_VX4X_bothE_otherV: [function({g, vid4}) { return g.V(vid4).bothE().otherV() }],
+ g_VX4X_bothE_hasXweight_lt_1X_otherV: [function({g, vid4}) { return g.V(vid4).bothE().has("weight", P.lt(1.0)).otherV() }],
+ get_g_VX1X_outE_otherV: [function({g, vid1}) { return g.V(vid1).outE().otherV() }],
+ g_VX1X_outEXknowsX_inV: [function({g, vid1}) { return g.V(vid1).outE("knows").inV() }],
+ g_VX1X_outEXknows_createdX_inV: [function({g, vid1}) { return g.V(vid1).outE("knows", "created").inV() }],
+ g_VX1X_outEXknowsX_bothV: [function({g, vid1}) { return g.V(vid1).outE("knows").bothV() }],
+ g_VX1X_outEXknowsX_bothV_name: [function({g, vid1}) { return g.V(vid1).outE("knows").bothV().values("name") }],
g_VX1X_properties_element: [function({g, v2}) { return g.V(v2).properties().element().limit(1) }],
g_V_properties_element: [function({g}) { return g.V().properties().element() }],
g_V_propertiesXageX_element: [function({g}) { return g.V().properties("age").element() }],
@@ -1365,34 +1390,15 @@ const gremlins = {
g_VX1X_out: [function({g, vid1}) { return g.V(vid1).out() }],
g_VX2X_in: [function({g, vid2}) { return g.V(vid2).in_() }],
g_VX4X_both: [function({g, vid4}) { return g.V(vid4).both() }],
- g_E: [function({g}) { return g.E() }],
- g_EX11X: [function({g, eid11}) { return g.E(eid11) }],
- g_EX11AsStringX: [function({g, eid11}) { return g.E(eid11) }],
- g_EXe11X: [function({g, e11}) { return g.E(e11) }],
- g_EXe7_e11X: [function({g, e7, e11}) { return g.E(e7, e11) }],
- g_EXlistXe7_e11XX: [function({g, xx1}) { return g.E(xx1) }],
- g_EXnullX: [function({g}) { return g.E(null) }],
- g_EXlistXnullXX: [function({g, xx1}) { return g.E(xx1) }],
- g_EX11_nullX: [function({g, eid11}) { return g.E(eid11, null) }],
g_VX1X_outE: [function({g, vid1}) { return g.V(vid1).outE() }],
g_VX2X_outE: [function({g, vid2}) { return g.V(vid2).inE() }],
g_VX4X_bothEXcreatedX: [function({g, vid4}) { return g.V(vid4).bothE("created") }],
g_VX4X_bothE: [function({g, vid4}) { return g.V(vid4).bothE() }],
- g_VX1X_outE_inV: [function({g, vid1}) { return g.V(vid1).both() }],
- g_VX2X_inE_outV: [function({g, vid2}) { return g.V(vid2).inE().outV() }],
- g_V_outE_hasXweight_1X_outV: [function({g}) { return g.V().outE().has("weight", 1.0).outV() }],
g_V_out_outE_inV_inE_inV_both_name: [function({g}) { return g.V().out().outE().inV().inE().inV().both().values("name") }],
- g_VX1X_outEXknowsX_bothV_name: [function({g, vid1}) { return g.V(vid1).outE("knows").bothV().values("name") }],
- g_VX1X_outE_otherV: [function({g, vid1}) { return g.V(vid1).outE().otherV() }],
- g_VX4X_bothE_otherV: [function({g, vid4}) { return g.V(vid4).bothE().otherV() }],
- g_VX4X_bothE_hasXweight_lt_1X_otherV: [function({g, vid4}) { return g.V(vid4).bothE().has("weight", P.lt(1.0)).otherV() }],
g_VX2X_inE: [function({g, vid2}) { return g.V(vid2).bothE() }],
- get_g_VX1X_outE_otherV: [function({g, vid1}) { return g.V(vid1).outE().otherV() }],
g_VX1X_outXknowsX: [function({g, vid1}) { return g.V(vid1).out("knows") }],
g_VX1AsStringX_outXknowsX: [function({g, vid1}) { return g.V(vid1).out("knows") }],
g_VX1X_outXknows_createdX: [function({g, vid1}) { return g.V(vid1).out("knows", "created") }],
- g_VX1X_outEXknowsX_inV: [function({g, vid1}) { return g.V(vid1).outE("knows").inV() }],
- g_VX1X_outEXknows_createdX_inV: [function({g, vid1}) { return g.V(vid1).outE("knows", "created").inV() }],
g_V_out_out: [function({g}) { return g.V().out().out() }],
g_VX1X_out_out_out: [function({g, vid1}) { return g.V(vid1).out().out().out() }],
g_VX1X_out_name: [function({g, vid1}) { return g.V(vid1).out().values("name") }],
diff --git a/gremlin-language/src/main/antlr4/Gremlin.g4 b/gremlin-language/src/main/antlr4/Gremlin.g4
index cda26269ac..6394c55568 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
;
@@ -809,7 +809,7 @@ traversalMethod_times
traversalMethod_to
: 'to' LPAREN traversalDirection (COMMA stringLiteralVarargs)? RPAREN #traversalMethod_to_Direction_String
- | 'to' LPAREN stringArgument RPAREN #traversalMethod_to_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-python/src/main/python/radish/feature_steps.py b/gremlin-python/src/main/python/radish/feature_steps.py
index 27b50911de..5f72c5b0dc 100644
--- a/gremlin-python/src/main/python/radish/feature_steps.py
+++ b/gremlin-python/src/main/python/radish/feature_steps.py
@@ -109,17 +109,6 @@ def unsupported_scenario(step):
return
-@given("using the parameter {param_name:w} of P.{p_val:w}({param:QuotedString})")
-def add_p_parameter(step, param_name, p_val, param):
- if (step.context.ignore):
- return
-
- if not hasattr(step.context, "traversal_params"):
- step.context.traversal_params = {}
-
- step.context.traversal_params[param_name] = getattr(P, p_val)(_convert(param.replace('\\"', '"'), step.context))
-
-
@given("using the parameter {param_name:w} defined as {param:QuotedString}")
def add_parameter(step, param_name, param):
if (step.context.ignore):
diff --git a/gremlin-python/src/main/python/radish/gremlin.py b/gremlin-python/src/main/python/radish/gremlin.py
index bba1156256..d082e9e3a3 100644
--- a/gremlin-python/src/main/python/radish/gremlin.py
+++ b/gremlin-python/src/main/python/radish/gremlin.py
@@ -207,6 +207,8 @@ world.gremlins = {
'g_VX1X_out_hasXid_2X': [(lambda g, v2=None:g.V(v2).has('age', P.gt(30)))],
'g_V_hasXblahX': [(lambda g:g.V().has('blah'))],
'g_V_hasXperson_name_markoX_age': [(lambda g:g.V().has('person', 'name', 'marko').values('age'))],
+ 'g_V_hasXperson_name_markovarX_age': [(lambda g, xx1=None:g.V().has('person', 'name', xx1).values('age'))],
+ 'g_V_hasXpersonvar_name_markoX_age': [(lambda g, xx1=None:g.V().has(xx1, 'name', 'marko').values('age'))],
'g_VX1X_outE_hasXweight_inside_0_06X_inV': [(lambda g, vid1=None:g.V(vid1).out_e().has('weight', P.inside(0.0, 0.6)).in_v())],
'g_EX11X_outV_outE_hasXid_10X': [(lambda g, eid11=None,eid10=None:g.E(eid11).out_v().out_e().has(T.id_, eid10))],
'g_EX11X_outV_outE_hasXid_10AsStringX': [(lambda g, eid11=None,eid10=None:g.E(eid11).out_v().out_e().has(T.id_, eid10))],
@@ -242,9 +244,9 @@ world.gremlins = {
'g_V_hasXlabel_isXpersonXX': [(lambda g:g.V().has(T.label, __.is_('person')))],
'g_V_hasXname_nullX': [(lambda g:g.V().has('name', None))],
'g_V_hasIdXemptyX_count': [(lambda g, xx1=None:g.V().has_id(xx1).count())],
- 'g_V_hasIdXwithinXemptyXX_count': [(lambda g, xx1=None:g.V().has_id(xx1).count())],
- 'g_V_hasIdXwithoutXemptyXX_count': [(lambda g, xx1=None:g.V().has_id(xx1).count())],
- 'g_V_notXhasIdXwithinXemptyXXX_count': [(lambda g, xx1=None:g.V().not_(__.has_id(xx1)).count())],
+ 'g_V_hasIdXwithinXemptyXX_count': [(lambda g:g.V().has_id(P.within([])).count())],
+ 'g_V_hasIdXwithoutXemptyXX_count': [(lambda g:g.V().has_id(P.without([])).count())],
+ 'g_V_notXhasIdXwithinXemptyXXX_count': [(lambda g:g.V().not_(__.has_id(P.within([]))).count())],
'g_V_hasIdXnullX': [(lambda g:g.V().has_id(None))],
'g_V_hasIdXeqXnullXX': [(lambda g:g.V().has_id(P.eq(None)))],
'g_V_hasIdX2_nullX': [(lambda g, vid2=None:g.V().has_id(vid2, None))],
@@ -252,7 +254,7 @@ world.gremlins = {
'g_V_hasIdX1AsString_2AsString_nullX': [(lambda g, vid2=None,vid1=None:g.V().has_id(vid1, vid2, None))],
'g_V_hasIdXnull_2X': [(lambda g, vid2=None:g.V().has_id(None, vid2))],
'g_V_hasIdX1X_hasIdX2X': [(lambda g, vid2=None,vid1=None:g.V().has_id(vid1).has_id(vid2))],
- 'g_V_in_hasIdXneqX1XX': [(lambda g, xx1=None:g.V().in_().has_id(xx1))],
+ 'g_V_in_hasIdXneqX1XX': [(lambda g, xx1=None:g.V().in_().has_id(P.neq(xx1)))],
'g_VX1X_out_hasIdX2X': [(lambda g, vid2=None,vid1=None:g.V(vid1).out().has_id(vid2))],
'g_VX1X_out_hasXid_2_3X': [(lambda g, vid3=None,vid2=None,vid1=None:g.V(vid1).out().has_id(vid2, vid3))],
'g_VX1X_out_hasXid_2AsString_3AsStringX': [(lambda g, vid3=None,vid2=None,vid1=None:g.V(vid1).out().has_id(vid2, vid3))],
@@ -275,6 +277,8 @@ world.gremlins = {
'g_E_hasLabelXuses_traversesX': [(lambda g:g.E().has_label('uses', 'traverses'))],
'g_V_hasLabelXperson_software_blahX': [(lambda g:g.V().has_label('person', 'software', 'blah'))],
'g_V_hasLabelXpersonX_hasLabelXsoftwareX': [(lambda g:g.V().has_label('person').has_label('software'))],
+ 'g_V_hasLabelXpersonvarX_hasLabelXsoftwareX': [(lambda g, xx1=None:g.V().has_label(xx1).has_label('software'))],
+ 'g_V_hasLabelXpersonvar_softwarevarX': [(lambda g, xx1=None,xx2=None:g.V().has_label(xx1, xx2))],
'g_V_hasLabelXpersonX_hasXage_notXlteX10X_andXnotXbetweenX11_20XXXX_andXltX29X_orXeqX35XXXX_name': [(lambda g:g.V().has_label('person').has('age', P.not_(P.lte(10).and_(P.not_(P.between(11, 20)))).and_(P.lt(29).or_(P.eq(35)))).values('name'))],
'g_V_hasLabelXnullX': [(lambda g:g.V().has_label(None))],
'g_V_hasXlabel_nullX': [(lambda g:g.V().has(T.label, None))],
@@ -676,7 +680,8 @@ world.gremlins = {
'g_V_valuesXnameX_conjoinX1X': [(lambda g:g.V().values('name').conjoin('1'))],
'g_V_valuesXnonexistantX_fold_conjoinX_X': [(lambda g:g.V().values('nonexistant').fold().conjoin(';'))],
'g_V_valuesXnameX_order_fold_conjoinX_X': [(lambda g:g.V().values('name').order().fold().conjoin('_'))],
- 'g_V_valuesXageX_order_fold_conjoinX_X': [(lambda g:g.V().values('age').order().fold().conjoin(';'))],
+ 'g_V_valuesXageX_order_fold_conjoinXsemicolonX': [(lambda g:g.V().values('age').order().fold().conjoin(';'))],
+ 'g_V_valuesXageX_order_fold_conjoinXslashX': [(lambda g, xx1=None:g.V().values('age').order().fold().conjoin(xx1))],
'g_V_out_path_byXvaluesXnameX_toUpperX_conjoinXMARKOX': [(lambda g:g.V().out().path().by(__.values('name').to_upper()).conjoin('MARKO'))],
'g_injectXmarkoX_conjoinX_X': [(lambda g, xx1=None:g.inject(xx1).conjoin('-'))],
'g_V_valueMapXlocationX_selectXvaluesX_unfold_orderXlocalX_conjoinX1X': [(lambda g:g.V().value_map('location').select(Column.values).unfold().order(Scope.local).conjoin('1'))],
@@ -750,12 +755,32 @@ world.gremlins = {
'g_injectXa_null_bX_disjunctXa_cX': [(lambda g, xx1=None,xx2=None:g.inject(xx1).disjunct(xx2))],
'g_injectXa_null_bX_disjunctXa_null_cX': [(lambda g, xx1=None,xx2=None:g.inject(xx1).disjunct(xx2))],
'g_injectX3_threeX_disjunctXfive_three_7X': [(lambda g, xx1=None,xx2=None:g.inject(xx1).disjunct(xx2))],
+ 'g_E': [(lambda g:g.E())],
+ 'g_EX11X': [(lambda g, eid11=None:g.E(eid11))],
+ 'g_EX11AsStringX': [(lambda g, eid11=None:g.E(eid11))],
+ 'g_EXe11X': [(lambda g, e11=None:g.E(e11))],
+ 'g_EXe7_e11X': [(lambda g, e7=None,e11=None:g.E(e7, e11))],
+ 'g_EXlistXe7_e11XX': [(lambda g, xx1=None:g.E(xx1))],
+ 'g_EXnullX': [(lambda g:g.E(None))],
+ 'g_EXlistXnullXX': [(lambda g, xx1=None:g.E(xx1))],
+ 'g_EX11_nullX': [(lambda g, eid11=None:g.E(eid11, None))],
'g_V_EX11X': [(lambda g, eid11=None:g.V().E(eid11))],
'g_EX11X_E': [(lambda g, eid11=None:g.E(eid11).E())],
'g_V_EXnullX': [(lambda g:g.V().E(None))],
'g_V_EXlistXnullXX': [(lambda g, xx1=None:g.V().E(xx1))],
'g_injectX1X_EX11_nullX': [(lambda g, eid11=None:g.inject(1).E(eid11, None))],
'g_injectX1X_coalesceXEX_hasLabelXtestsX_addEXtestsX_from_V_hasXnameX_XjoshXX_toXV_hasXnameX_XvadasXXX': [(lambda g:g.add_v('person').property('name', 'josh').add_v('person').property('name', 'vadas')), (lambda g:g.inject(1).coalesce(__.E().has_label('tests'), __.add_e('tests').from_(__.V().has('name', 'josh')).to(__.V().has('name', 'vadas')))), (lambda g:g.E().has_label('tests'))],
+ 'g_VX1X_outE_inV': [(lambda g, vid1=None:g.V(vid1).out_e().in_v())],
+ 'g_VX2X_inE_outV': [(lambda g, vid2=None:g.V(vid2).in_e().out_v())],
+ 'g_V_outE_hasXweight_1X_outV': [(lambda g:g.V().out_e().has('weight', 1.0).out_v())],
+ 'g_VX1X_outE_otherV': [(lambda g, vid1=None:g.V(vid1).out_e().other_v())],
+ 'g_VX4X_bothE_otherV': [(lambda g, vid4=None:g.V(vid4).both_e().other_v())],
+ 'g_VX4X_bothE_hasXweight_lt_1X_otherV': [(lambda g, vid4=None:g.V(vid4).both_e().has('weight', P.lt(1.0)).other_v())],
+ 'get_g_VX1X_outE_otherV': [(lambda g, vid1=None:g.V(vid1).out_e().other_v())],
+ 'g_VX1X_outEXknowsX_inV': [(lambda g, vid1=None:g.V(vid1).out_e('knows').in_v())],
+ 'g_VX1X_outEXknows_createdX_inV': [(lambda g, vid1=None:g.V(vid1).out_e('knows', 'created').in_v())],
+ 'g_VX1X_outEXknowsX_bothV': [(lambda g, vid1=None:g.V(vid1).out_e('knows').both_v())],
+ 'g_VX1X_outEXknowsX_bothV_name': [(lambda g, vid1=None:g.V(vid1).out_e('knows').both_v().values('name'))],
'g_VX1X_properties_element': [(lambda g, v2=None:g.V(v2).properties().element().limit(1))],
'g_V_properties_element': [(lambda g:g.V().properties().element())],
'g_V_propertiesXageX_element': [(lambda g:g.V().properties('age').element())],
@@ -1347,34 +1372,15 @@ world.gremlins = {
'g_VX1X_out': [(lambda g, vid1=None:g.V(vid1).out())],
'g_VX2X_in': [(lambda g, vid2=None:g.V(vid2).in_())],
'g_VX4X_both': [(lambda g, vid4=None:g.V(vid4).both())],
- 'g_E': [(lambda g:g.E())],
- 'g_EX11X': [(lambda g, eid11=None:g.E(eid11))],
- 'g_EX11AsStringX': [(lambda g, eid11=None:g.E(eid11))],
- 'g_EXe11X': [(lambda g, e11=None:g.E(e11))],
- 'g_EXe7_e11X': [(lambda g, e7=None,e11=None:g.E(e7, e11))],
- 'g_EXlistXe7_e11XX': [(lambda g, xx1=None:g.E(xx1))],
- 'g_EXnullX': [(lambda g:g.E(None))],
- 'g_EXlistXnullXX': [(lambda g, xx1=None:g.E(xx1))],
- 'g_EX11_nullX': [(lambda g, eid11=None:g.E(eid11, None))],
'g_VX1X_outE': [(lambda g, vid1=None:g.V(vid1).out_e())],
'g_VX2X_outE': [(lambda g, vid2=None:g.V(vid2).in_e())],
'g_VX4X_bothEXcreatedX': [(lambda g, vid4=None:g.V(vid4).both_e('created'))],
'g_VX4X_bothE': [(lambda g, vid4=None:g.V(vid4).both_e())],
- 'g_VX1X_outE_inV': [(lambda g, vid1=None:g.V(vid1).both())],
- 'g_VX2X_inE_outV': [(lambda g, vid2=None:g.V(vid2).in_e().out_v())],
- 'g_V_outE_hasXweight_1X_outV': [(lambda g:g.V().out_e().has('weight', 1.0).out_v())],
'g_V_out_outE_inV_inE_inV_both_name': [(lambda g:g.V().out().out_e().in_v().in_e().in_v().both().values('name'))],
- 'g_VX1X_outEXknowsX_bothV_name': [(lambda g, vid1=None:g.V(vid1).out_e('knows').both_v().values('name'))],
- 'g_VX1X_outE_otherV': [(lambda g, vid1=None:g.V(vid1).out_e().other_v())],
- 'g_VX4X_bothE_otherV': [(lambda g, vid4=None:g.V(vid4).both_e().other_v())],
- 'g_VX4X_bothE_hasXweight_lt_1X_otherV': [(lambda g, vid4=None:g.V(vid4).both_e().has('weight', P.lt(1.0)).other_v())],
'g_VX2X_inE': [(lambda g, vid2=None:g.V(vid2).both_e())],
- 'get_g_VX1X_outE_otherV': [(lambda g, vid1=None:g.V(vid1).out_e().other_v())],
'g_VX1X_outXknowsX': [(lambda g, vid1=None:g.V(vid1).out('knows'))],
'g_VX1AsStringX_outXknowsX': [(lambda g, vid1=None:g.V(vid1).out('knows'))],
'g_VX1X_outXknows_createdX': [(lambda g, vid1=None:g.V(vid1).out('knows', 'created'))],
- 'g_VX1X_outEXknowsX_inV': [(lambda g, vid1=None:g.V(vid1).out_e('knows').in_v())],
- 'g_VX1X_outEXknows_createdX_inV': [(lambda g, vid1=None:g.V(vid1).out_e('knows', 'created').in_v())],
'g_V_out_out': [(lambda g:g.V().out().out())],
'g_VX1X_out_out_out': [(lambda g, vid1=None:g.V(vid1).out().out().out())],
'g_VX1X_out_name': [(lambda g, vid1=None:g.V(vid1).out().values('name'))],
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 4bcb90f110..a282f69759 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
@@ -32,6 +32,7 @@ import org.antlr.v4.runtime.CommonTokenStream;
import org.apache.tinkerpop.gremlin.language.grammar.GremlinAntlrToJava;
import org.apache.tinkerpop.gremlin.language.grammar.GremlinLexer;
import org.apache.tinkerpop.gremlin.language.grammar.GremlinParser;
+import org.apache.tinkerpop.gremlin.language.grammar.VariableResolver;
import org.apache.tinkerpop.gremlin.language.translator.GremlinTranslator;
import org.apache.tinkerpop.gremlin.language.translator.Translator;
import org.apache.tinkerpop.gremlin.process.traversal.Merge;
@@ -62,6 +63,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;
@@ -92,7 +94,7 @@ public final class StepDefinition {
private World world;
private GraphTraversalSource g;
- private final Map<String, String> stringParameters = new HashMap<>();
+ private final Map<String, Object> stringParameters = new HashMap<>();
private Traversal traversal;
private Object result;
private Throwable error;
@@ -182,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());
@@ -234,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 -> {
@@ -285,19 +287,26 @@ public final class StepDefinition {
@Given("using the parameter {word} defined as {string}")
public void usingTheParameterXDefinedAsX(final String key, final String value) {
- stringParameters.put(key, convertToString(value));
- }
-
- @Given("using the parameter {word} of P.{word}\\({string})")
- public void usingTheParameterXOfPX(final String key, final String pval, final String string) {
- stringParameters.put(key, String.format("P.%s(%s)", pval, convertToString(string)));
+ // when parameters are used literally, they are converted to string representations that can be recognized by
+ // the grammar and parsed inline. when they are used as variables, they are converted to objects that can be
+ // applied to the script as variables.
+ if (world.useParametersLiterally())
+ stringParameters.put(key, convertToString(value));
+ else
+ stringParameters.put(key, convertToObject(value));
}
@Given("the traversal of")
public void theTraversalOf(final String docString) {
try {
- final String gremlin = tryUpdateDataFilePath(docString);
- traversal = parseGremlin(applyParameters(gremlin));
+ final String rawGremlin = tryUpdateDataFilePath(docString);
+
+ // when parameters are used literally, they are converted to string representations that can be recognized by
+ // the grammar and parsed inline. when they are used as variables, they are converted to objects that can be
+ // applied to the script as variables.
+ final String gremlin = world.useParametersLiterally() ? applyParameters(rawGremlin) : rawGremlin;
+
+ traversal = parseGremlin(gremlin);
} catch (Exception ex) {
ex.printStackTrace();
error = ex;
@@ -375,10 +384,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());
+ final String gremlin = world.useParametersLiterally() ? applyParameters(rawGremlin) : rawGremlin;
+ assertEquals(count.longValue(), ((GraphTraversal) parseGremlin(gremlin)).count().next());
}
@Then("the result should be empty")
@@ -450,7 +460,14 @@ public final class StepDefinition {
final GremlinLexer lexer = new GremlinLexer(CharStreams.fromString(normalizedGremlin));
final GremlinParser parser = new GremlinParser(new CommonTokenStream(lexer));
final GremlinParser.QueryContext ctx = parser.query();
- return (Traversal) new GremlinAntlrToJava(g).visitQuery(ctx);
+
+ // when parameters are used literally, they are converted to string representations that can be recognized by
+ // the grammar and parsed inline. when they are used as variables, they are converted to objects that can be
+ // applied to the script as variables.
+ if (world.useParametersLiterally())
+ return (Traversal) new GremlinAntlrToJava(g).visitQuery(ctx);
+ else
+ return (Traversal) new GremlinAntlrToJava(g, new VariableResolver.DefaultVariableResolver(this.stringParameters)).visitQuery(ctx);
}
private List<Object> translateResultsToActual() {
@@ -574,7 +591,7 @@ public final class StepDefinition {
final List<String> paramNames = new ArrayList<>(stringParameters.keySet());
paramNames.sort((a,b) -> b.length() - a.length());
for (String k : paramNames) {
- replaced = replaced.replace(k, stringParameters.get(k));
+ replaced = replaced.replace(k, stringParameters.get(k).toString());
}
return replaced;
}
@@ -587,6 +604,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}.
*/
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/World.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/World.java
index 52a977e614..726f72631a 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/World.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/World.java
@@ -82,6 +82,15 @@ public interface World {
return id.toString();
}
+ /**
+ * Determines if the test should use parameters literally or treat them as variables to be applied to the script.
+ * By default, they are treated literally.
+ */
+ public default boolean useParametersLiterally() {
+ return true;
+ }
+
+
/**
* Allows for some flexibility in error message assertion, where the provider can handle assertions themselves.
* Providers should use standard assertion logic as they would with tests. Note that if this method is called, then
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/Has.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/Has.feature
index c10757748d..8a1db09a05 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/Has.feature
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/Has.feature
@@ -206,6 +206,30 @@ Feature: Step - has()
| result |
| d[29].i |
+ Scenario: g_V_hasXperson_name_markovarX_age
+ Given the modern graph
+ And using the parameter xx1 defined as "marko"
+ And the traversal of
+ """
+ g.V().has("person", "name", xx1).values("age")
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | d[29].i |
+
+ Scenario: g_V_hasXpersonvar_name_markoX_age
+ Given the modern graph
+ And using the parameter xx1 defined as "person"
+ And the traversal of
+ """
+ g.V().has(xx1, "name", "marko").values("age")
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | d[29].i |
+
Scenario: g_VX1X_outE_hasXweight_inside_0_06X_inV
Given the modern graph
And using the parameter vid1 defined as "v[marko].id"
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/HasId.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/HasId.feature
index 8c20b41b72..cc85a5c4fe 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/HasId.feature
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/HasId.feature
@@ -32,10 +32,9 @@ Feature: Step - hasId()
Scenario: g_V_hasIdXwithinXemptyXX_count
Given the modern graph
- And using the parameter xx1 of P.within("l[]")
And the traversal of
"""
- g.V().hasId(xx1).count()
+ g.V().hasId(P.within([])).count()
"""
When iterated to list
Then the result should be unordered
@@ -44,10 +43,9 @@ Feature: Step - hasId()
Scenario: g_V_hasIdXwithoutXemptyXX_count
Given the modern graph
- And using the parameter xx1 of P.without("l[]")
And the traversal of
"""
- g.V().hasId(xx1).count()
+ g.V().hasId(P.without([])).count()
"""
When iterated to list
Then the result should be unordered
@@ -56,10 +54,9 @@ Feature: Step - hasId()
Scenario: g_V_notXhasIdXwithinXemptyXXX_count
Given the modern graph
- And using the parameter xx1 of P.within("l[]")
And the traversal of
"""
- g.V().not(__.hasId(xx1)).count()
+ g.V().not(__.hasId(P.within([]))).count()
"""
When iterated to list
Then the result should be unordered
@@ -147,10 +144,10 @@ Feature: Step - hasId()
Scenario: g_V_in_hasIdXneqX1XX
Given the modern graph
- And using the parameter xx1 of P.neq("v[marko].id")
+ And using the parameter xx1 defined as "v[marko].id"
And the traversal of
"""
- g.V().in().hasId(xx1)
+ g.V().in().hasId(P.neq(xx1))
"""
When iterated to list
Then the result should be unordered
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/HasLabel.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/HasLabel.feature
index 470019f36d..2da655e7e6 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/HasLabel.feature
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/HasLabel.feature
@@ -87,6 +87,34 @@ Feature: Step - hasLabel()
When iterated to list
Then the result should be empty
+ Scenario: g_V_hasLabelXpersonvarX_hasLabelXsoftwareX
+ Given the modern graph
+ And using the parameter xx1 defined as "person"
+ And the traversal of
+ """
+ g.V().hasLabel(xx1).hasLabel("software")
+ """
+ When iterated to list
+ Then the result should be empty
+
+ Scenario: g_V_hasLabelXpersonvar_softwarevarX
+ Given the modern graph
+ And using the parameter xx1 defined as "person"
+ And using the parameter xx2 defined as "software"
+ And the traversal of
+ """
+ g.V().hasLabel(xx1,xx2)
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | v[marko] |
+ | v[vadas] |
+ | v[josh] |
+ | v[peter] |
+ | v[lop] |
+ | v[ripple] |
+
Scenario: g_V_hasLabelXpersonX_hasXage_notXlteX10X_andXnotXbetweenX11_20XXXX_andXltX29X_orXeqX35XXXX_name
Given the modern graph
And the traversal of
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Conjoin.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Conjoin.feature
index 9d9d54547e..8f05f14f0d 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Conjoin.feature
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Conjoin.feature
@@ -59,7 +59,7 @@ Feature: Step - conjoin()
| result |
| josh_lop_marko_peter_ripple_vadas |
- Scenario: g_V_valuesXageX_order_fold_conjoinX_X
+ Scenario: g_V_valuesXageX_order_fold_conjoinXsemicolonX
Given the modern graph
And the traversal of
"""
@@ -70,6 +70,18 @@ Feature: Step - conjoin()
| result |
| 27;29;32;35 |
+ Scenario: g_V_valuesXageX_order_fold_conjoinXslashX
+ Given the modern graph
+ And using the parameter xx1 defined as "/"
+ And the traversal of
+ """
+ g.V().values("age").order().fold().conjoin(xx1)
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | 27/29/32/35 |
+
@GraphComputerVerificationReferenceOnly
Scenario: g_V_out_path_byXvaluesXnameX_toUpperX_conjoinXMARKOX
Given the modern graph
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Edge.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Edge.feature
index f3d92320d2..7d75a251af 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Edge.feature
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Edge.feature
@@ -16,7 +16,117 @@
# under the License.
@StepClassMap @StepE
-Feature: Step - E()
+Feature: Step - E(), inV(), outV(), bothV(), otherV()
+
+ Scenario: g_E
+ Given the modern graph
+ And the traversal of
+ """
+ g.E()
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | e[marko-created->lop] |
+ | e[marko-knows->josh] |
+ | e[marko-knows->vadas] |
+ | e[peter-created->lop] |
+ | e[josh-created->lop] |
+ | e[josh-created->ripple] |
+
+ Scenario: g_EX11X
+ Given the modern graph
+ And using the parameter eid11 defined as "e[josh-created->lop].id"
+ And the traversal of
+ """
+ g.E(eid11)
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | e[josh-created->lop] |
+
+ Scenario: g_EX11AsStringX
+ Given the modern graph
+ And using the parameter eid11 defined as "e[josh-created->lop].sid"
+ And the traversal of
+ """
+ g.E(eid11)
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | e[josh-created->lop] |
+
+ Scenario: g_EXe11X
+ Given the modern graph
+ And using the parameter e11 defined as "e[josh-created->lop]"
+ And the traversal of
+ """
+ g.E(e11)
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | e[josh-created->lop] |
+
+ Scenario: g_EXe7_e11X
+ Given the modern graph
+ And using the parameter e7 defined as "e[marko-knows->vadas]"
+ And using the parameter e11 defined as "e[josh-created->lop]"
+ And the traversal of
+ """
+ g.E(e7,e11)
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | e[marko-knows->vadas] |
+ | e[josh-created->lop] |
+
+ Scenario: g_EXlistXe7_e11XX
+ Given the modern graph
+ And using the parameter xx1 defined as "l[e[marko-knows->vadas],e[josh-created->lop]]"
+ And the traversal of
+ """
+ g.E(xx1)
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | e[marko-knows->vadas] |
+ | e[josh-created->lop] |
+
+ Scenario: g_EXnullX
+ Given the modern graph
+ And the traversal of
+ """
+ g.E(null)
+ """
+ When iterated to list
+ Then the result should be empty
+
+ Scenario: g_EXlistXnullXX
+ Given the modern graph
+ And using the parameter xx1 defined as "l[null]"
+ And the traversal of
+ """
+ g.E(xx1)
+ """
+ When iterated to list
+ Then the result should be empty
+
+ Scenario: g_EX11_nullX
+ Given the modern graph
+ And using the parameter eid11 defined as "e[josh-created->lop].id"
+ And the traversal of
+ """
+ g.E(eid11,null)
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | e[josh-created->lop] |
Scenario: g_V_EX11X
Given the modern graph
@@ -97,3 +207,152 @@ Feature: Step - E()
When iterated to list
Then the result should have a count of 1
And the graph should return 1 for count of "g.E().hasLabel(\"tests\")"
+
+ Scenario: g_VX1X_outE_inV
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V(vid1).outE().inV()
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | v[vadas] |
+ | v[josh] |
+ | v[lop] |
+
+ Scenario: g_VX2X_inE_outV
+ Given the modern graph
+ And using the parameter vid2 defined as "v[vadas].id"
+ And the traversal of
+ """
+ g.V(vid2).inE().outV()
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | v[marko] |
+
+ Scenario: g_V_outE_hasXweight_1X_outV
+ Given the modern graph
+ And the traversal of
+ """
+ g.V().outE().has("weight",1.0).outV()
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | v[marko] |
+ | v[josh] |
+
+ Scenario: g_VX1X_outE_otherV
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V(vid1).outE().otherV()
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | v[vadas] |
+ | v[josh] |
+ | v[lop] |
+
+ Scenario: g_VX4X_bothE_otherV
+ Given the modern graph
+ And using the parameter vid4 defined as "v[josh].id"
+ And the traversal of
+ """
+ g.V(vid4).bothE().otherV()
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | v[marko] |
+ | v[ripple] |
+ | v[lop] |
+
+ Scenario: g_VX4X_bothE_hasXweight_lt_1X_otherV
+ Given the modern graph
+ And using the parameter vid4 defined as "v[josh].id"
+ And the traversal of
+ """
+ g.V(vid4).bothE().has("weight", P.lt(1.0)).otherV()
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | v[lop] |
+
+ Scenario: get_g_VX1X_outE_otherV
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V(vid1).outE().otherV()
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | v[vadas] |
+ | v[josh] |
+ | v[lop] |
+
+ Scenario: g_VX1X_outEXknowsX_inV
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V(vid1).outE("knows").inV()
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | v[vadas] |
+ | v[josh] |
+
+ Scenario: g_VX1X_outEXknows_createdX_inV
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V(vid1).outE("knows","created").inV()
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | v[vadas] |
+ | v[josh] |
+ | v[lop] |
+
+ Scenario: g_VX1X_outEXknowsX_bothV
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V(vid1).outE("knows").bothV()
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | v[marko] |
+ | v[marko] |
+ | v[josh] |
+ | v[vadas] |
+
+ Scenario: g_VX1X_outEXknowsX_bothV_name
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V(vid1).outE("knows").bothV().values("name")
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | marko |
+ | marko |
+ | josh |
+ | vadas |
\ No newline at end of file
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Vertex.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Vertex.feature
index f0b3c95a93..3f8912211b 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Vertex.feature
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Vertex.feature
@@ -16,7 +16,7 @@
# under the License.
@StepClassMap @StepVertex
-Feature: Step - V(), E(), out(), in(), both(), inE(), outE(), bothE()
+Feature: Step - V(), out(), in(), both(), inE(), outE(), bothE()
Scenario: g_VXnullX
Given the modern graph
@@ -147,116 +147,6 @@ Feature: Step - V(), E(), out(), in(), both(), inE(), outE(), bothE()
| v[lop] |
| v[ripple] |
- Scenario: g_E
- Given the modern graph
- And the traversal of
- """
- g.E()
- """
- When iterated to list
- Then the result should be unordered
- | result |
- | e[marko-created->lop] |
- | e[marko-knows->josh] |
- | e[marko-knows->vadas] |
- | e[peter-created->lop] |
- | e[josh-created->lop] |
- | e[josh-created->ripple] |
-
- Scenario: g_EX11X
- Given the modern graph
- And using the parameter eid11 defined as "e[josh-created->lop].id"
- And the traversal of
- """
- g.E(eid11)
- """
- When iterated to list
- Then the result should be unordered
- | result |
- | e[josh-created->lop] |
-
- Scenario: g_EX11AsStringX
- Given the modern graph
- And using the parameter eid11 defined as "e[josh-created->lop].sid"
- And the traversal of
- """
- g.E(eid11)
- """
- When iterated to list
- Then the result should be unordered
- | result |
- | e[josh-created->lop] |
-
- Scenario: g_EXe11X
- Given the modern graph
- And using the parameter e11 defined as "e[josh-created->lop]"
- And the traversal of
- """
- g.E(e11)
- """
- When iterated to list
- Then the result should be unordered
- | result |
- | e[josh-created->lop] |
-
- Scenario: g_EXe7_e11X
- Given the modern graph
- And using the parameter e7 defined as "e[marko-knows->vadas]"
- And using the parameter e11 defined as "e[josh-created->lop]"
- And the traversal of
- """
- g.E(e7,e11)
- """
- When iterated to list
- Then the result should be unordered
- | result |
- | e[marko-knows->vadas] |
- | e[josh-created->lop] |
-
- Scenario: g_EXlistXe7_e11XX
- Given the modern graph
- And using the parameter xx1 defined as "l[e[marko-knows->vadas],e[josh-created->lop]]"
- And the traversal of
- """
- g.E(xx1)
- """
- When iterated to list
- Then the result should be unordered
- | result |
- | e[marko-knows->vadas] |
- | e[josh-created->lop] |
-
- Scenario: g_EXnullX
- Given the modern graph
- And the traversal of
- """
- g.E(null)
- """
- When iterated to list
- Then the result should be empty
-
- Scenario: g_EXlistXnullXX
- Given the modern graph
- And using the parameter xx1 defined as "l[null]"
- And the traversal of
- """
- g.E(xx1)
- """
- When iterated to list
- Then the result should be empty
-
- Scenario: g_EX11_nullX
- Given the modern graph
- And using the parameter eid11 defined as "e[josh-created->lop].id"
- And the traversal of
- """
- g.E(eid11,null)
- """
- When iterated to list
- Then the result should be unordered
- | result |
- | e[josh-created->lop] |
-
Scenario: g_VX1X_outE
Given the modern graph
And using the parameter vid1 defined as "v[marko].id"
@@ -310,44 +200,6 @@ Feature: Step - V(), E(), out(), in(), both(), inE(), outE(), bothE()
| e[josh-created->ripple] |
| e[marko-knows->josh] |
- Scenario: g_VX1X_outE_inV
- Given the modern graph
- And using the parameter vid1 defined as "v[marko].id"
- And the traversal of
- """
- g.V(vid1).both()
- """
- When iterated to list
- Then the result should be unordered
- | result |
- | v[vadas] |
- | v[josh] |
- | v[lop] |
-
- Scenario: g_VX2X_inE_outV
- Given the modern graph
- And using the parameter vid2 defined as "v[vadas].id"
- And the traversal of
- """
- g.V(vid2).inE().outV()
- """
- When iterated to list
- Then the result should be unordered
- | result |
- | v[marko] |
-
- Scenario: g_V_outE_hasXweight_1X_outV
- Given the modern graph
- And the traversal of
- """
- g.V().outE().has("weight",1.0).outV()
- """
- When iterated to list
- Then the result should be unordered
- | result |
- | v[marko] |
- | v[josh] |
-
Scenario: g_V_out_outE_inV_inE_inV_both_name
Given the modern graph
And the traversal of
@@ -368,61 +220,6 @@ Feature: Step - V(), E(), out(), in(), both(), inE(), outE(), bothE()
| peter |
| peter |
- Scenario: g_VX1X_outEXknowsX_bothV_name
- Given the modern graph
- And using the parameter vid1 defined as "v[marko].id"
- And the traversal of
- """
- g.V(vid1).outE("knows").bothV().values("name")
- """
- When iterated to list
- Then the result should be unordered
- | result |
- | marko |
- | marko |
- | josh |
- | vadas |
-
- Scenario: g_VX1X_outE_otherV
- Given the modern graph
- And using the parameter vid1 defined as "v[marko].id"
- And the traversal of
- """
- g.V(vid1).outE().otherV()
- """
- When iterated to list
- Then the result should be unordered
- | result |
- | v[vadas] |
- | v[josh] |
- | v[lop] |
-
- Scenario: g_VX4X_bothE_otherV
- Given the modern graph
- And using the parameter vid4 defined as "v[josh].id"
- And the traversal of
- """
- g.V(vid4).bothE().otherV()
- """
- When iterated to list
- Then the result should be unordered
- | result |
- | v[marko] |
- | v[ripple] |
- | v[lop] |
-
- Scenario: g_VX4X_bothE_hasXweight_lt_1X_otherV
- Given the modern graph
- And using the parameter vid4 defined as "v[josh].id"
- And the traversal of
- """
- g.V(vid4).bothE().has("weight", P.lt(1.0)).otherV()
- """
- When iterated to list
- Then the result should be unordered
- | result |
- | v[lop] |
-
Scenario: g_VX2X_inE
Given the modern graph
And using the parameter vid2 defined as "v[vadas].id"
@@ -435,20 +232,6 @@ Feature: Step - V(), E(), out(), in(), both(), inE(), outE(), bothE()
| result |
| e[marko-knows->vadas] |
- Scenario: get_g_VX1X_outE_otherV
- Given the modern graph
- And using the parameter vid1 defined as "v[marko].id"
- And the traversal of
- """
- g.V(vid1).outE().otherV()
- """
- When iterated to list
- Then the result should be unordered
- | result |
- | v[vadas] |
- | v[josh] |
- | v[lop] |
-
Scenario: g_VX1X_outXknowsX
Given the modern graph
And using the parameter vid1 defined as "v[marko].id"
@@ -489,33 +272,6 @@ Feature: Step - V(), E(), out(), in(), both(), inE(), outE(), bothE()
| v[josh] |
| v[lop] |
- Scenario: g_VX1X_outEXknowsX_inV
- Given the modern graph
- And using the parameter vid1 defined as "v[marko].id"
- And the traversal of
- """
- g.V(vid1).outE("knows").inV()
- """
- When iterated to list
- Then the result should be unordered
- | result |
- | v[vadas] |
- | v[josh] |
-
- Scenario: g_VX1X_outEXknows_createdX_inV
- Given the modern graph
- And using the parameter vid1 defined as "v[marko].id"
- And the traversal of
- """
- g.V(vid1).outE("knows","created").inV()
- """
- When iterated to list
- Then the result should be unordered
- | result |
- | v[vadas] |
- | v[josh] |
- | v[lop] |
-
Scenario: g_V_out_out
Given the modern graph
And the traversal of
@@ -565,8 +321,6 @@ Feature: Step - V(), E(), out(), in(), both(), inE(), outE(), bothE()
| v[vadas] |
| v[josh] |
-
-
# the point here is to test g.V() where an id is not present. to do this with the gherkin structure
# the test establishes the modern graph, does a drop() of "lop" and then tries to query the 4 vertices
# and we assert the count of 3
diff --git a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/process/traversal/step/sideEffect/Neo4jGraphStep.java b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/process/traversal/step/sideEffect/Neo4jGraphStep.java
index 7ab286543c..90d7327cc7 100644
--- a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/process/traversal/step/sideEffect/Neo4jGraphStep.java
+++ b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/process/traversal/step/sideEffect/Neo4jGraphStep.java
@@ -66,7 +66,7 @@ public final class Neo4jGraphStep<S, E extends Element> extends GraphStep<S, E>
private Iterator<? extends Edge> edges() {
if (null == this.ids)
return Collections.emptyIterator();
- return IteratorUtils.filter(this.getTraversal().getGraph().get().edges(this.ids), edge -> HasContainer.testAll(edge, this.hasContainers));
+ return IteratorUtils.filter(this.getTraversal().getGraph().get().edges(this.getIdsAsValues()), edge -> HasContainer.testAll(edge, this.hasContainers));
}
private Iterator<? extends Vertex> vertices() {
@@ -76,7 +76,7 @@ public final class Neo4jGraphStep<S, E extends Element> extends GraphStep<S, E>
// ids are present, filter on them first
if (ids.length > 0)
- return IteratorUtils.filter(graph.vertices(ids), vertex -> HasContainer.testAll(vertex, hasContainers));
+ return IteratorUtils.filter(graph.vertices(this.getIdsAsValues()), vertex -> HasContainer.testAll(vertex, hasContainers));
////// do index lookups //////
graph.tx().readWrite();
// get a label being search on
diff --git a/sparql-gremlin/src/main/java/org/apache/tinkerpop/gremlin/sparql/process/traversal/strategy/SparqlStrategy.java b/sparql-gremlin/src/main/java/org/apache/tinkerpop/gremlin/sparql/process/traversal/strategy/SparqlStrategy.java
index a4a95cc1c1..5f791b41d5 100644
--- a/sparql-gremlin/src/main/java/org/apache/tinkerpop/gremlin/sparql/process/traversal/strategy/SparqlStrategy.java
+++ b/sparql-gremlin/src/main/java/org/apache/tinkerpop/gremlin/sparql/process/traversal/strategy/SparqlStrategy.java
@@ -23,7 +23,6 @@ import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.InjectStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.util.EmptyStep;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
import org.apache.tinkerpop.gremlin.sparql.SparqlToGremlinCompiler;
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 6a3e965629..5a3d59e80b 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
@@ -71,11 +71,12 @@ public final class TinkerGraphStep<S, E extends Element> extends GraphStep<S, E>
final AbstractTinkerGraph graph = (AbstractTinkerGraph) this.getTraversal().getGraph().get();
final HasContainer indexedContainer = getIndexKey(Edge.class);
Iterator<Edge> iterator;
+ final Object[] resolvedIds = this.getIdsAsValues();
// ids are present, filter on them first
- if (null == this.ids)
+ if (null == resolvedIds)
iterator = Collections.emptyIterator();
- else if (this.ids.length > 0)
- iterator = this.iteratorList(graph.edges(this.ids));
+ else if (resolvedIds.length > 0)
+ iterator = this.iteratorList(graph.edges(resolvedIds));
else
iterator = null == indexedContainer ?
this.iteratorList(graph.edges()) :
@@ -93,11 +94,12 @@ public final class TinkerGraphStep<S, E extends Element> extends GraphStep<S, E>
final AbstractTinkerGraph graph = (AbstractTinkerGraph) this.getTraversal().getGraph().get();
final HasContainer indexedContainer = getIndexKey(Vertex.class);
Iterator<? extends Vertex> iterator;
+ final Object[] resolvedIds = this.getIdsAsValues();
// ids are present, filter on them first
- if (null == this.ids)
+ if (null == resolvedIds)
iterator = Collections.emptyIterator();
- else if (this.ids.length > 0)
- iterator = this.iteratorList(graph.vertices(this.ids));
+ else if (resolvedIds.length > 0)
+ iterator = this.iteratorList(graph.vertices(resolvedIds));
else
iterator = (null == indexedContainer ?
this.iteratorList(graph.vertices()) :
diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/TinkerWorld.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/TinkerWorld.java
index 329a07fbae..52fd414164 100644
--- a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/TinkerWorld.java
+++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/TinkerWorld.java
@@ -109,6 +109,11 @@ public abstract class TinkerWorld implements World {
public AbstractTinkerGraph open(final Configuration configuration) {
return TinkerGraph.open(configuration);
}
+
+ @Override
+ public boolean useParametersLiterally() {
+ return false;
+ }
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphPlayTest.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphPlayTest.java
index 80111709f5..e1d908045b 100644
--- a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphPlayTest.java
+++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphPlayTest.java
@@ -18,8 +18,12 @@
*/
package org.apache.tinkerpop.gremlin.tinkergraph.structure;
+import org.apache.tinkerpop.gremlin.jsr223.GremlinLangScriptEngine;
+import org.apache.tinkerpop.gremlin.jsr223.VariableResolverCustomizer;
+import org.apache.tinkerpop.gremlin.language.grammar.VariableResolver;
import org.apache.tinkerpop.gremlin.process.computer.Computer;
import org.apache.tinkerpop.gremlin.process.traversal.P;
+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.dsl.graph.GraphTraversalSource;
@@ -38,6 +42,7 @@ import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import javax.script.Bindings;
import java.util.Arrays;
import java.util.List;
import java.util.function.BiFunction;
@@ -270,17 +275,25 @@ public class TinkerGraphPlayTest {
}
@Test
- @Ignore
- public void testBugs() {
+ public void testBugs() throws Exception {
final GraphTraversalSource g = TinkerFactory.createModern().traversal();
- Object o1 = g.V().map(__.V(1));
- System.out.println(g.V().as("a").both().as("b").dedup("a", "b").by(T.label).select("a", "b").explain());
- System.out.println(g.V().as("a").both().as("b").dedup("a", "b").by(T.label).select("a", "b").toList());
-
- Traversal<?,?> t =
- g.V("3").
- union(__.repeat(out().simplePath()).times(2).count(),
- __.repeat(in().simplePath()).times(2).count());
+ final GremlinLangScriptEngine se = new GremlinLangScriptEngine(
+ new VariableResolverCustomizer(VariableResolver.DefaultVariableResolver::new));
+
+ final Bindings b = se.createBindings();
+ b.put("g", g);
+ System.out.println(((GraphTraversal) se.eval("g.V().coin(0.5).count()", b)).toList());
+
+ b.clear();
+ b.put("g", g);
+ b.put("x", 0.5d);
+ System.out.println(((GraphTraversal) se.eval("g.V().coin(x).count()", b)).toList());
+
+ b.clear();
+ b.put("g", g);
+ b.put("x", "josh");
+ b.put("y", 32);
+ System.out.println(((GraphTraversal) se.eval("g.V().has('name', x).has('age', y).count()", b)).toList());
}
@Test