[
https://issues.apache.org/jira/browse/TINKERPOP-2959?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17901257#comment-17901257
]
ASF GitHub Bot commented on TINKERPOP-2959:
-------------------------------------------
vkagamlyk commented on code in PR #2919:
URL: https://github.com/apache/tinkerpop/pull/2919#discussion_r1858920184
##########
gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/GValue.java:
##########
@@ -0,0 +1,446 @@
+/*
+ * 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) {
+ if (name != null && name.startsWith("_")) {
+ throw new IllegalArgumentException(String.format("Invalid GValue
name [%s]. Should not start with _.", name));
+ }
+ 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
+ */
+ 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.
+ */
+ 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.
+ */
+ 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.
+ */
+ 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.
+ */
+ 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.
+ */
+ 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.
+ */
+ 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.
+ */
+ 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.
+ */
+ 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.
+ */
+ 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.
+ */
+ 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.
+ */
+ 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.
+ */
+ 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.
+ */
+ 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.
+ */
+ 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 mapping 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) {
Review Comment:
inconsistency with `GType.isNumeric()`
`Float` GValue is number, but not `isNumeric()`
> Allow the grammar to support parameters
> ---------------------------------------
>
> Key: TINKERPOP-2959
> URL: https://issues.apache.org/jira/browse/TINKERPOP-2959
> Project: TinkerPop
> Issue Type: Improvement
> Components: language
> Affects Versions: 3.6.4
> Reporter: Stephen Mallette
> Assignee: Stephen Mallette
> Priority: Major
> Fix For: 3.7.0
>
>
> Allow the grammar to support parameters similar to how the groovy engine does
> like, {{g.inject(x,y,z)}}. Doing this will make it easier for a transition
> away from the groovy engine as a lot of Gremlin in the world today uses
> parameters. The grammar may have to come with some limitations though as
> groovy is wide open in terms of what can be treated as a variable. Probably
> going to keep parameters tied to primitives, collections and tokens/enums
> like {{Order}} and {{Scope}}. Collections themselves will not contain
> parameters and things like a {{Traversal}} or {{P}} cannot be treated as one.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)