This is an automated email from the ASF dual-hosted git repository.
spmallette pushed a commit to branch gvalue-3.7
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
The following commit(s) were added to refs/heads/gvalue-3.7 by this push:
new 2b64618ba3 backported hasLabel() improvements, additional GValue/GType
features, fixed validations in addE
2b64618ba3 is described below
commit 2b64618ba3030daa9044060642f3b6f1a81ed57d
Author: Stephen Mallette <[email protected]>
AuthorDate: Thu Aug 22 10:43:30 2024 -0400
backported hasLabel() improvements, additional GValue/GType features, fixed
validations in addE
---
.../language/grammar/GenericLiteralVisitor.java | 14 +++++++
.../language/grammar/TraversalMethodVisitor.java | 27 ++++++++++--
.../traversal/dsl/graph/GraphTraversal.java | 2 +-
.../gremlin/process/traversal/step/GType.java | 40 +++++++++++-------
.../gremlin/process/traversal/step/GValue.java | 49 ++++++++++++++++++++++
.../process/traversal/step/map/AddEdgeStep.java | 5 ++-
6 files changed, 115 insertions(+), 22 deletions(-)
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 7b841de87c..493b247aa8 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
@@ -643,4 +643,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 d9b256dccb..81b0ccd750 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,6 +27,7 @@ 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.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
@@ -721,10 +722,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 =
Arrays.stream(literalOrVars).map(GValue::of).toArray();
+ }
+
+ // 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,
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);
+ }
}
}
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 c49eadaf7d..2135a9cdf8 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
@@ -445,7 +445,7 @@ public interface GraphTraversal<S, E> extends Traversal<S,
E> {
* @see <a
href="http://tinkerpop.apache.org/docs/${project.version}/reference/#has-step"
target="_blank">Reference Documentation - Has Step</a>
* @since 3.2.2
*/
- public default GraphTraversal<S, E> hasLabel(final Object label, final
Object... otherLabels) {
+ public default GraphTraversal<S, E> hasLabel(final GValue<String>
label, final GValue<String>... otherLabels) {
this.asAdmin().getBytecode().addStep(GraphTraversal.Symbols.hasLabel, label,
otherLabels);
// groovy evaluation seems to do strange things with varargs given
hasLabel(null, null). odd someone would
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
index 23dd8be5f2..efaafac3be 100644
---
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
@@ -33,23 +33,31 @@ import java.util.Set;
* An enum that describes types that are used in the Gremlin language.
*/
public enum GType {
- BIG_DECIMAL,
- BIG_INTEGER,
- BOOLEAN,
- DOUBLE,
- EDGE,
- INTEGER,
- LIST,
- LONG,
- MAP,
- PATH,
- PROPERTY,
- SET,
- STRING,
- UNKNOWN,
- VERTEX;
+ 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);
- GType() {}
+ 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.
diff --git
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/GValue.java
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/GValue.java
index a7271c3ad9..5af5109ac6 100644
---
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/GValue.java
+++
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/GValue.java
@@ -21,12 +21,14 @@ 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;
@@ -118,6 +120,7 @@ public class GValue<V> implements Cloneable, Serializable {
* @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);
}
@@ -128,6 +131,7 @@ public class GValue<V> implements Cloneable, Serializable {
* @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);
}
@@ -326,4 +330,49 @@ public class GValue<V> implements Cloneable, Serializable {
public static GValue<Property> ofProperty(final String name, final
Property value) {
return new GValue<>(name, GType.PROPERTY, value);
}
+
+
+ /**
+ * 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;
+ }
+
+ /**
+ * 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) {
+ // todo: is this right for null?
+ if (null == o)
+ return false;
+ else if (o instanceof GValue)
+ return ((GValue) o).getType() == type;
+ else
+ return o.getClass().isAssignableFrom(type.getJavaType());
+ }
+
+ /**
+ * 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());
+ }
}
\ No newline at end of file
diff --git
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStep.java
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStep.java
index 9dfa4ce754..c456073509 100644
---
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStep.java
+++
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStep.java
@@ -21,6 +21,7 @@ package
org.apache.tinkerpop.gremlin.process.traversal.step.map;
import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
import org.apache.tinkerpop.gremlin.process.traversal.step.FromToModulating;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GType;
import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
import org.apache.tinkerpop.gremlin.process.traversal.step.Scoping;
import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
@@ -113,7 +114,7 @@ public class AddEdgeStep<S> extends ScalarMapStep<S, Edge>
edgeLabel, e.getMessage()));
}
- if (!(theTo instanceof Vertex))
+ if (!(theTo instanceof Vertex) || (theTo instanceof GValue &&
((GValue) theTo).getType() != GType.VERTEX))
throw new IllegalStateException(String.format(
"The value given to addE(%s).to() must resolve to a Vertex
but %s was specified instead", edgeLabel,
null == theTo ? "null" :
theTo.getClass().getSimpleName()));
@@ -127,7 +128,7 @@ public class AddEdgeStep<S> extends ScalarMapStep<S, Edge>
edgeLabel, e.getMessage()));
}
- if (!(theFrom instanceof Vertex))
+ if (!(theFrom instanceof Vertex) || (theFrom instanceof GValue &&
((GValue) theTo).getType() != GType.VERTEX))
throw new IllegalStateException(String.format(
"The value given to addE(%s).to() must resolve to a Vertex
but %s was specified instead", edgeLabel,
null == theFrom ? "null" :
theFrom.getClass().getSimpleName()));