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()));

Reply via email to