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 3f9b30f452b09cec4c80e33f67ff724cfc5a1963 Author: Stephen Mallette <[email protected]> AuthorDate: Wed Jul 10 15:49:35 2024 -0400 wip - parameters --- .../language/grammar/TraversalMethodVisitor.java | 11 +- .../gremlin/language/grammar/VariableResolver.java | 37 +++++- .../tinkerpop/gremlin/process/traversal/P.java | 6 +- .../traversal/dsl/graph/GraphTraversal.java | 42 +++++++ .../gremlin/process/traversal/step/GType.java | 59 +++++++++ .../gremlin/process/traversal/step/GValue.java | 138 +++++++++++++++++++++ .../process/traversal/step/filter/CoinStep.java | 26 +++- .../gremlin/structure/VertexProperty.java | 3 - .../language/grammar/ArgumentVisitorTest.java | 116 ++++++++--------- .../language/grammar/GremlinQueryParserTest.java | 8 +- .../tinkergraph/structure/TinkerGraphPlayTest.java | 30 +++-- 11 files changed, 388 insertions(+), 88 deletions(-) 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 440bd502c8..d183445b9a 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 @@ -23,6 +23,8 @@ import org.apache.tinkerpop.gremlin.process.traversal.Order; import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions; 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.VertexProperty.Cardinality; import java.util.Map; @@ -441,7 +443,14 @@ 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 (literalOrVar instanceof Number) + return graphTraversal.coin(((Number) literalOrVar).doubleValue()); + else if (literalOrVar instanceof GValue && ((GValue) literalOrVar).getType() == GType.DOUBLE) + return graphTraversal.asAdmin().coin((GValue<Double>) literalOrVar); + else + throw new IllegalArgumentException("coin() argument must be a double"); + } /** 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/process/traversal/P.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java index 917a13891d..56e1946368 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,6 +18,7 @@ */ package org.apache.tinkerpop.gremlin.process.traversal; +import org.apache.tinkerpop.gremlin.process.traversal.step.GValue; import org.apache.tinkerpop.gremlin.process.traversal.util.AndP; import org.apache.tinkerpop.gremlin.process.traversal.util.OrP; @@ -74,7 +75,10 @@ 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 + return this.biPredicate.test(testValue, this.value); } @Override 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 aa364e4fc4..496ba1a473 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 @@ -47,6 +47,8 @@ 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.GType; +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; @@ -230,8 +232,48 @@ 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()}. + * <p/> + * Note that step overloads allowing use of {@link GValue} objects do not construct bytecode with that object. + * Bytecode does not make use of parameterization in that fashion so it there isn't a need to really preserve that + * functionality there (doing so would require changes to serializers). + */ public interface Admin<S, E> extends Traversal.Admin<S, E>, GraphTraversal<S, E> { + /** + * Filter the <code>E</code> object given a biased coin toss. + * + * @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 3.7.3 + */ + public default GraphTraversal<S, E> coin(final GValue<Double> probability) { + this.asAdmin().getBytecode().addStep(GraphTraversal.Symbols.coin, probability.get()); + return this.asAdmin().addStep(new CoinStep<>(this.asAdmin(), probability)); + } + + /** + * Filter the <code>E</code> object given a biased coin toss where the argument can be either a {@link GValue} + * object or a double. + * + * @param probability the probability that the object will pass through and must be a {@link GValue} object or a double. + * @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 3.7.3 + */ + public default GraphTraversal<S, E> coin(final Object probability) { + if (probability instanceof Number) + return this.coin(((Number) probability).doubleValue()); + else if (probability instanceof GValue && ((GValue) probability).getType() == GType.DOUBLE) + return this.coin(probability); + else + throw new IllegalArgumentException("The probability must be a GValue<Double> or a double"); + } + @Override public default <E2> GraphTraversal.Admin<S, E2> addStep(final Step<?, E2> step) { return (GraphTraversal.Admin<S, E2>) Traversal.Admin.super.addStep((Step) step); 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..cd12d7e191 --- /dev/null +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/GType.java @@ -0,0 +1,59 @@ +/* + * 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; + +/** + * An enum that describes types that are used in the Gremlin language. + */ +public enum GType { + INTEGER, + STRING, + BOOLEAN, + DOUBLE, + LONG, + MAP, + LIST, + SET, + VERTEX, + EDGE, + PATH, + PROPERTY, + UNKNOWN; + + GType() {} + + /** + * 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 Integer) return INTEGER; + else if (object instanceof String) return STRING; + 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 java.util.Map) return MAP; + else if (object instanceof java.util.List) return LIST; + else if (object instanceof java.util.Set) return SET; + else if (object instanceof org.apache.tinkerpop.gremlin.structure.Vertex) return VERTEX; + else if (object instanceof org.apache.tinkerpop.gremlin.structure.Edge) return EDGE; + else if (object instanceof org.apache.tinkerpop.gremlin.process.traversal.Path) return PATH; + else if (object instanceof org.apache.tinkerpop.gremlin.structure.Property) return PROPERTY; + 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..b9f0c8d23b --- /dev/null +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/GValue.java @@ -0,0 +1,138 @@ +/* + * 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.Property; +import org.apache.tinkerpop.gremlin.structure.Vertex; + +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; + +/** + * 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> { + 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; + } + + public boolean isVariable() { + return this.name != null; + } + + public Optional<String> getName() { + return Optional.ofNullable(this.name); + } + + public GType getType() { + return this.type; + } + + public V get() { + return this.value; + } + + @Override + public String toString() { + return isVariable() ? + String.format("%s&%s", name, value) : Objects.toString(value); + } + + /** + * Create a new {@code Var} with the specified name and value. + * + * @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) { + return new GValue<>(name, GType.getType(value), value); + } + + public static GValue<String> ofString(final String name, final String value) { + return new GValue<>(name, GType.STRING, value); + } + + public static GValue<Integer> ofInteger(final String name, final Integer value) { + return new GValue<>(name, GType.INTEGER, value); + } + + public static GValue<Boolean> ofBoolean(final String name, final Boolean value) { + return new GValue<>(name, GType.BOOLEAN, value); + } + + public static GValue<Double> ofDouble(final String name, final Double value) { + return new GValue<>(name, GType.DOUBLE, value); + } + + public static GValue<Double> ofDouble(final Double value) { + return new GValue<>(GType.DOUBLE, value); + } + + public static GValue<Long> ofLong(final String name, final Long value) { + return new GValue<>(name, GType.LONG, value); + } + + public static GValue<Map> ofMap(final String name, final java.util.Map value) { + return new GValue<>(name, GType.MAP, value); + } + + public static GValue<List> ofList(final String name, final java.util.List value) { + return new GValue<>(name, GType.LIST, value); + } + + public static GValue<Set> ofSet(final String name, final java.util.Set value) { + return new GValue<>(name, GType.SET, value); + } + + public static GValue<Vertex> ofVertex(final String name, final org.apache.tinkerpop.gremlin.structure.Vertex value) { + return new GValue<>(name, GType.VERTEX, value); + } + + public static GValue<Edge> ofEdge(final String name, final org.apache.tinkerpop.gremlin.structure.Edge value) { + return new GValue<>(name, GType.EDGE, value); + } + + public static GValue<Path> ofPath(final String name, final org.apache.tinkerpop.gremlin.process.traversal.Path value) { + return new GValue<>(name, GType.PATH, value); + } + + public static GValue<Property> ofProperty(final String name, final org.apache.tinkerpop.gremlin.structure.Property value) { + return new GValue<>(name, GType.PROPERTY, value); + } +} 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..7395dd8544 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,14 +30,25 @@ 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; + /** + * @deprecated As of release 3.7.3, replaced by {@link #CoinStep(Traversal.Admin, GValue)} + */ + @Deprecated public CoinStep(final Traversal.Admin traversal, final double probability) { + super(traversal); + this.probability = GValue.ofDouble(probability); + } + + public CoinStep(final Traversal.Admin traversal, final GValue<Double> probability) { super(traversal); this.probability = probability; } @@ -46,8 +58,12 @@ public final class CoinStep<S> extends FilterStep<S> implements Seedable { random.setSeed(seed); } + public GValue<Double> getProbabilityGValue() { + return probability; + } + public double getProbability() { - return this.probability; + return this.probability.get(); } @Override @@ -55,11 +71,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 +89,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/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/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 43f33054b5..e9c98cd2c3 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,81 +84,81 @@ 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))))}, + {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, "x", new VariableResolverException("x"), createAntlr(VariableResolver.NoVariableResolver.instance())}, - {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")))}, - {Direction.class, "x", Direction.OUT, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", Direction.OUT)))}, - {Direction.class, "x", Direction.from, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", Direction.from)))}, + {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")))}, + {Direction.class, "x", Direction.OUT, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", Direction.OUT)))}, + {Direction.class, "x", Direction.from, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", Direction.from)))}, {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"))))}, + {Vertex.class, "new Vertex(1i,'person')", new ReferenceVertex(1, "person"), createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", Direction.from)))}, + {Vertex.class, "x", new ReferenceVertex(1, "person"), createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", new ReferenceVertex(1, "person"))))}, {Order.class, "x", new VariableResolverException("x"), createAntlr(VariableResolver.NoVariableResolver.instance())}, - {Order.class, "Order.desc", Order.desc, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))}, - {Order.class, "x", Order.desc, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", Order.desc)))}, + {Order.class, "Order.desc", Order.desc, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))}, + {Order.class, "x", Order.desc, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", Order.desc)))}, {Scope.class, "x", new VariableResolverException("x"), createAntlr(VariableResolver.NoVariableResolver.instance())}, - {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")))}, - {Scope.class, "x", Scope.local, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", Scope.local)))}, + {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")))}, + {Scope.class, "x", Scope.local, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", Scope.local)))}, {T.class, "x", new VariableResolverException("x"), createAntlr(VariableResolver.NoVariableResolver.instance())}, - {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")))}, - {T.class, "x", T.label, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", T.label)))}, + {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")))}, + {T.class, "x", T.label, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", T.label)))}, {VertexProperty.Cardinality.class, "x", new VariableResolverException("x"), createAntlr(VariableResolver.NoVariableResolver.instance())}, - {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")))}, - {VertexProperty.Cardinality.class, "x", VertexProperty.Cardinality.list, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", VertexProperty.Cardinality.list)))}, + {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")))}, + {VertexProperty.Cardinality.class, "x", VertexProperty.Cardinality.list, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", VertexProperty.Cardinality.list)))}, {DT.class, "x", new VariableResolverException("x"), createAntlr(VariableResolver.NoVariableResolver.instance())}, - {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")))}, - {DT.class, "x", DT.hour, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", DT.hour)))}, + {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")))}, + {DT.class, "x", DT.hour, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", DT.hour)))}, {Merge.class, "x", new VariableResolverException("x"), createAntlr(VariableResolver.NoVariableResolver.instance())}, - {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")))}, - {Merge.class, "x", Merge.onMatch, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", Merge.onMatch)))}, + {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")))}, + {Merge.class, "x", Merge.onMatch, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", Merge.onMatch)))}, {Pop.class, "x", new VariableResolverException("x"), createAntlr(VariableResolver.NoVariableResolver.instance())}, - {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")))}, - {Pop.class, "x", Pop.last, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", Pop.last)))}, + {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")))}, + {Pop.class, "x", Pop.last, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", Pop.last)))}, {Operator.class, "x", new VariableResolverException("x"), createAntlr(VariableResolver.NoVariableResolver.instance())}, - {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")))}, - {Operator.class, "x", Operator.sum, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", Operator.sum)))}, + {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")))}, + {Operator.class, "x", Operator.sum, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", Operator.sum)))}, {Column.class, "x", new VariableResolverException("x"), createAntlr(VariableResolver.NoVariableResolver.instance())}, - {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")))}, - {Column.class, "x", Column.keys, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", Column.keys)))}, + {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")))}, + {Column.class, "x", Column.keys, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", Column.keys)))}, {SackFunctions.Barrier.class, "x", new VariableResolverException("x"), createAntlr(VariableResolver.NoVariableResolver.instance())}, - {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")))}, - {SackFunctions.Barrier.class, "x", SackFunctions.Barrier.normSack, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", SackFunctions.Barrier.normSack)))}, + {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")))}, + {SackFunctions.Barrier.class, "x", SackFunctions.Barrier.normSack, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", SackFunctions.Barrier.normSack)))}, }); } 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 9b67393e66..8439e56878 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().getBytecode(), @@ -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/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 3560027d2f..e419553ba9 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,10 @@ */ package org.apache.tinkerpop.gremlin.tinkergraph.structure; +import org.apache.tinkerpop.gremlin.jsr223.GremlinLangScriptEngine; 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; @@ -39,6 +41,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; @@ -273,17 +276,24 @@ 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(); + + 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
