This is an automated email from the ASF dual-hosted git repository.

spmallette pushed a commit to branch TINKERPOP-1682
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit 12a6ef0b9b071518fa4419cbbdbd7a34849fd8de
Author: Stephen Mallette <sp...@genoprime.com>
AuthorDate: Thu May 7 08:53:23 2020 -0400

    TINKERPOP-1682 Support by(T) on Property
---
 CHANGELOG.asciidoc                                 |  1 +
 docs/src/upgrade/release-3.5.x.asciidoc            | 29 ++++++++
 .../process/traversal/lambda/TokenTraversal.java   | 19 +++++-
 .../process/traversal/step/sideEffect/IoStep.java  |  2 +-
 .../ByModulatorOptimizationStrategy.java           |  8 +--
 .../structure/io/graphml/GraphMLWriter.java        |  1 -
 .../traversal/lambda/TokenTraversalTest.java       | 78 ++++++++++++++++++++++
 .../ByModulatorOptimizationStrategyTest.java       | 12 ++--
 gremlin-test/features/map/Select.feature           | 24 +++++++
 .../process/traversal/step/map/SelectTest.java     | 32 ++++++++-
 10 files changed, 191 insertions(+), 15 deletions(-)

diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index a80aac5..9f4bf28 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -30,6 +30,7 @@ This release also includes changes from <<release-3-4-3, 
3.4.3>>.
 * Ensured better consistency of the use of `null` as arguments to mutation 
steps.
 * Allowed `property(T.label,Object)` to be used if no value was supplied to 
`addV(String)`.
 * Added a `Graph.Feature` for `supportsNullPropertyValues`.
+* Modified `TokenTraversal` to support `Property` thus `by(key)` and 
`by(value)` can now apply to `Edge` and meta-properties.
 * Added `Grouping` step interface.
 * Added `TraversalParent.replaceTraversal()` which can replace a direct child 
traversal.
 * Added `ByModulatorOptimizationStrategy` which replaces certain standard 
traversals w/ optimized traversals (e.g. `TokenTraversal`).
diff --git a/docs/src/upgrade/release-3.5.x.asciidoc 
b/docs/src/upgrade/release-3.5.x.asciidoc
index 50180dd..f1b2ee3 100644
--- a/docs/src/upgrade/release-3.5.x.asciidoc
+++ b/docs/src/upgrade/release-3.5.x.asciidoc
@@ -209,6 +209,35 @@ be replaced by `by(id)`, thus replacing a step-based 
traversal with a token-base
 
 See: link:https://issues.apache.org/jira/browse/TINKERPOP-1682[TINKERPOP-1682]
 
+==== by(T) for Property
+
+The `Property` interface is not included in the hierarchy of `Element`. This 
means that an edge property or a
+meta-property are not considered elements the way that a `VertexProperty` is. 
As a result, some usages of `T` in
+relation to properties do not work consistently. One such example is `by(T)`, 
a token-based traversal, where the
+following works for a `VertexProperty` but will not for edge properties or 
meta-properties:
+
+[source,text]
+----
+gremlin> g.V(1).properties().as('a').select('a').by(key)
+==>name
+==>age
+----
+
+For a `Property` you would need to use `key()`-step:
+
+[source,text]
+----
+gremlin> g.E(11).properties().as('a').select(last,'a').by(key())
+==>weight
+----
+
+Aside from the inconsistency, this issue also presents a situation where 
performance is impacted as token-based
+traversals are inherently faster than step-based ones. In 3.5.0, this issue 
has been resolved in conjunction with the
+introduction of `ByModulatorOptimizationStrategy` which will optimize 
`by(key())` and `by(value())` to their
+appropriate token versions automatically.
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-1682[TINKERPOP-1682]
+
 ==== Python 2.x Support
 
 The gremlinpython module no longer supports Python 2.x. Users must use Python 
3 going forward. For the most part, from
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/TokenTraversal.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/TokenTraversal.java
index d41c402..e272ccf 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/TokenTraversal.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/TokenTraversal.java
@@ -20,6 +20,7 @@ package org.apache.tinkerpop.gremlin.process.traversal.lambda;
 
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
 import org.apache.tinkerpop.gremlin.structure.Element;
+import org.apache.tinkerpop.gremlin.structure.Property;
 import org.apache.tinkerpop.gremlin.structure.T;
 
 import java.util.Objects;
@@ -27,7 +28,7 @@ import java.util.Objects;
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public final class TokenTraversal<S extends Element, E> extends 
AbstractLambdaTraversal<S, E> {
+public final class TokenTraversal<S, E> extends AbstractLambdaTraversal<S, E> {
 
     private E e;
     private final T t;
@@ -43,7 +44,21 @@ public final class TokenTraversal<S extends Element, E> 
extends AbstractLambdaTr
 
     @Override
     public void addStart(final Traverser.Admin<S> start) {
-        this.e = (E) this.t.apply(start.get());
+        final S s = start.get();
+        if (s instanceof Element)
+            this.e = (E) this.t.apply((Element) start.get());
+        else if (s instanceof Property) {
+            // T.apply() doesn't work on Property because the inheritance 
hierarchy doesn't make it an Element. have
+            // to special case it here. only T.key/value make any sense for it.
+            if (t == T.key)
+                this.e = (E) ((Property) s).key();
+            else if (t == T.value)
+                this.e = ((Property<E>) s).value();
+            else
+                throw new IllegalStateException(String.format("TokenTraversal 
support of Property does not allow selection by %s", t));
+        } else
+            throw new IllegalStateException(String.format("TokenTraversal 
support of %s does not allow selection by %s", s.getClass().getName(), t));
+
     }
 
     @Override
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/IoStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/IoStep.java
index 861b318..0ca02ee 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/IoStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/IoStep.java
@@ -188,7 +188,7 @@ public class IoStep<S> extends AbstractStep<S,S> implements 
ReadWriting {
                 final GryoMapper.Builder builder = GryoMapper.build();
                 detectRegistries().forEach(builder::addRegistry);
                 return GryoWriter.build().mapper(builder.create()).create();
-            }else if (objectOrClass.equals(IO.graphml))
+            } else if (objectOrClass.equals(IO.graphml))
                 return GraphMLWriter.build().create();
             else {
                 try {
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/ByModulatorOptimizationStrategy.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/ByModulatorOptimizationStrategy.java
index 579dcf4..0faaef9 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/ByModulatorOptimizationStrategy.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/ByModulatorOptimizationStrategy.java
@@ -32,6 +32,8 @@ import 
org.apache.tinkerpop.gremlin.process.traversal.step.map.GroupStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.IdStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.LabelStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.PropertiesStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.PropertyKeyStep;
+import 
org.apache.tinkerpop.gremlin.process.traversal.step.map.PropertyValueStep;
 import 
org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.GroupSideEffectStep;
 import 
org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.IdentityStep;
 import 
org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy;
@@ -95,12 +97,10 @@ public final class ByModulatorOptimizationStrategy extends 
AbstractTraversalStra
             step.replaceLocalChild(traversal, new TokenTraversal<>(T.id));
         } else if (singleStep instanceof LabelStep) {
             step.replaceLocalChild(traversal, new TokenTraversal<>(T.label));
-/* todo: this fails for `Property`s (e.g. 
outE().property().as("a").select("a").by(key/value))
         } else if (singleStep instanceof PropertyKeyStep) {
-            step.setModulateByTraversal(n, new TokenTraversal<>(T.key));
+            step.replaceLocalChild(traversal, new TokenTraversal<>(T.key));
         } else if (singleStep instanceof PropertyValueStep) {
-            step.setModulateByTraversal(n, new TokenTraversal<>(T.value));
-*/
+            step.replaceLocalChild(traversal, new TokenTraversal<>(T.value));
         } else if (singleStep instanceof IdentityStep) {
             step.replaceLocalChild(traversal, new IdentityTraversal<>());
         }
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLWriter.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLWriter.java
index 3991e4e..5c70e99 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLWriter.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLWriter.java
@@ -24,7 +24,6 @@ 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.List;
 import java.util.Map;
diff --git 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/TokenTraversalTest.java
 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/TokenTraversalTest.java
new file mode 100644
index 0000000..7d1ad54
--- /dev/null
+++ 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/TokenTraversalTest.java
@@ -0,0 +1,78 @@
+/*
+ * 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.lambda;
+
+import org.apache.tinkerpop.gremlin.process.traversal.traverser.B_O_Traverser;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Property;
+import org.apache.tinkerpop.gremlin.structure.T;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class TokenTraversalTest {
+    @Test
+    public void shouldWorkOnVertex() {
+        final TokenTraversal<Vertex, Integer> t = new TokenTraversal<>(T.id);
+        final Vertex v = mock(Vertex.class);
+        when(v.id()).thenReturn(100);
+        t.addStart(new B_O_Traverser<>(v, 1).asAdmin());
+        assertEquals(100, t.next().intValue());
+    }
+
+    @Test
+    public void shouldWorkOnVertexProperty() {
+        final TokenTraversal<VertexProperty, Integer> t = new 
TokenTraversal<>(T.id);
+        final VertexProperty vo = mock(VertexProperty.class);
+        when(vo.id()).thenReturn(100);
+        t.addStart(new B_O_Traverser<>(vo, 1).asAdmin());
+        assertEquals(100, t.next().intValue());
+    }
+
+    @Test
+    public void shouldWorkOnEdge() {
+        final TokenTraversal<Edge, Integer> t = new TokenTraversal<>(T.id);
+        final Edge e = mock(Edge.class);
+        when(e.id()).thenReturn(100);
+        t.addStart(new B_O_Traverser<>(e, 1).asAdmin());
+        assertEquals(100, t.next().intValue());
+    }
+
+    @Test
+    public void shouldWorkOnPropertyKey() {
+        final TokenTraversal<Property<String>, String> t = new 
TokenTraversal<>(T.key);
+        final Property<String> p = mock(Property.class);
+        when(p.key()).thenReturn("name");
+        t.addStart(new B_O_Traverser<>(p, 1).asAdmin());
+        assertEquals("name", t.next());
+    }
+
+    @Test
+    public void shouldWorkOnPropertyValue() {
+        final TokenTraversal<Property<String>, String> t = new 
TokenTraversal<>(T.value);
+        final Property<String> p = mock(Property.class);
+        when(p.value()).thenReturn("marko");
+        t.addStart(new B_O_Traverser<>(p, 1).asAdmin());
+        assertEquals("marko", t.next());
+    }
+}
diff --git 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/ByModulatorOptimizationStrategyTest.java
 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/ByModulatorOptimizationStrategyTest.java
index 23c4576..a3a0044 100644
--- 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/ByModulatorOptimizationStrategyTest.java
+++ 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/ByModulatorOptimizationStrategyTest.java
@@ -90,14 +90,14 @@ public class ByModulatorOptimizationStrategyTest {
                     ((GraphTraversal<?, ?>) 
traversal.asAdmin().clone()).by(__.label()),
                     ((GraphTraversal) traversal.asAdmin().clone()).by(T.label),
             });
-            /*result.add(new Traversal[]{
+            originalAndOptimized.add(new Traversal[]{
                     ((GraphTraversal<?, ?>) 
traversal.asAdmin().clone()).by(__.key()),
                     ((GraphTraversal) traversal.asAdmin().clone()).by(T.key),
             });
-            result.add(new Traversal[]{
+            originalAndOptimized.add(new Traversal[]{
                     ((GraphTraversal<?, ?>) 
traversal.asAdmin().clone()).by(__.value()),
                     ((GraphTraversal) traversal.asAdmin().clone()).by(T.value),
-            });*/
+            });
             originalAndOptimized.add(new Traversal[]{
                     ((GraphTraversal<?, ?>) 
traversal.asAdmin().clone()).by(__.identity()),
                     ((GraphTraversal) traversal.asAdmin().clone()).by(),
@@ -137,14 +137,14 @@ public class ByModulatorOptimizationStrategyTest {
                     ((GraphTraversal<?, ?>) 
traversal.asAdmin().clone()).by(__.label().fold()),
                     ((GraphTraversal) traversal.asAdmin().clone()).by(T.label),
             });
-            /*result.add(new Traversal[]{
+            originalAndOptimized.add(new Traversal[]{
                     ((GraphTraversal<?, ?>) 
traversal.asAdmin().clone()).by(__.key().fold()),
                     ((GraphTraversal) traversal.asAdmin().clone()).by(T.key),
             });
-            result.add(new Traversal[]{
+            originalAndOptimized.add(new Traversal[]{
                     ((GraphTraversal<?, ?>) 
traversal.asAdmin().clone()).by(__.value().fold()),
                     ((GraphTraversal) traversal.asAdmin().clone()).by(T.value),
-            });*/
+            });
             originalAndOptimized.add(new Traversal[]{
                     ((GraphTraversal<?, ?>) 
traversal.asAdmin().clone()).by(__.identity()),
                     ((GraphTraversal) traversal.asAdmin().clone()).by(),
diff --git a/gremlin-test/features/map/Select.feature 
b/gremlin-test/features/map/Select.feature
index 0d4913a..8c759d6 100644
--- a/gremlin-test/features/map/Select.feature
+++ b/gremlin-test/features/map/Select.feature
@@ -744,3 +744,27 @@ Feature: Step - select()
       | s[a,b] |
       | s[c]   |
     And the graph should return 6 for count of "g.V().as(\"a\", 
\"b\").out().as(\"c\").path().select(Column.keys)"
+
+  Scenario: g_EX11X_propertiesXweightX_asXaX_selectXaX_byXkeyX
+    Given the modern graph
+    And using the parameter e11Id defined as "e[josh-created->lop].id"
+    And the traversal of
+      """
+      g.E(e11Id).properties("weight").as("a").select("a").by(T.key)
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | weight |
+
+  Scenario: g_EX11X_propertiesXweightX_asXaX_selectXaX_byXvalueX
+    Given the modern graph
+    And using the parameter e11Id defined as "e[josh-created->lop].id"
+    And the traversal of
+      """
+      g.E(e11Id).properties("weight").as("a").select("a").by(T.value)
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | d[0.4].d |
\ No newline at end of file
diff --git 
a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SelectTest.java
 
b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SelectTest.java
index 0f5afbd..4e5d4a0 100644
--- 
a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SelectTest.java
+++ 
b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SelectTest.java
@@ -26,6 +26,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.Pop;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
 import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.T;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -38,7 +39,6 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.stream.Stream;
 
 import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.CREW;
 import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.MODERN;
@@ -155,6 +155,10 @@ public abstract class SelectTest extends 
AbstractGremlinProcessTest {
 
     public abstract Traversal<Vertex, Vertex> 
get_g_VX1X_asXaX_repeatXout_asXaXX_timesX2X_selectXlast_aX(final Object v1Id);
 
+    public abstract Traversal<Edge, Object> 
get_g_EX11X_propertiesXweightX_asXaX_selectXaX_byXkeyX(final Object e11Id);
+
+    public abstract Traversal<Edge, Object> 
get_g_EX11X_propertiesXweightX_asXaX_selectXaX_byXvalueX(final Object e11Id);
+
     // when labels don't exist
 
     public abstract Traversal<Vertex, String> 
get_g_V_untilXout_outX_repeatXin_asXaXX_selectXaX_byXtailXlocalX_nameX();
@@ -703,6 +707,22 @@ public abstract class SelectTest extends 
AbstractGremlinProcessTest {
         assertEquals(Collections.emptyList(), traversal.toList());
     }
 
+    @Test
+    @LoadGraphWith(MODERN)
+    public void g_EX11X_propertiesXweightX_asXaX_selectXaX_byXkeyX() {
+        final Traversal<Edge, Object> traversal = 
get_g_EX11X_propertiesXweightX_asXaX_selectXaX_byXkeyX(convertToEdgeId("josh", 
"created", "lop"));
+        printTraversalForm(traversal);
+        assertEquals("weight", traversal.next());
+    }
+
+    @Test
+    @LoadGraphWith(MODERN)
+    public void g_EX11X_propertiesXweightX_asXaX_selectXaX_byXvalueX() {
+        final Traversal<Edge, Object> traversal = 
get_g_EX11X_propertiesXweightX_asXaX_selectXaX_byXvalueX(convertToEdgeId("josh",
 "created", "lop"));
+        printTraversalForm(traversal);
+        assertEquals(0.4d, (double) traversal.next(), 0.0001d);
+    }
+
     // when labels don't exist
 
     @Test
@@ -1074,6 +1094,16 @@ public abstract class SelectTest extends 
AbstractGremlinProcessTest {
             return g.V().as("a").where(__.out("knows")).<Vertex>select("a");
         }
 
+        @Override
+        public Traversal<Edge, Object> 
get_g_EX11X_propertiesXweightX_asXaX_selectXaX_byXkeyX(final Object e11Id) {
+            return 
g.E(e11Id).properties("weight").as("a").select("a").by(T.key);
+        }
+
+        @Override
+        public Traversal<Edge, Object> 
get_g_EX11X_propertiesXweightX_asXaX_selectXaX_byXvalueX(final Object e11Id) {
+            return 
g.E(e11Id).properties("weight").as("a").select("a").by(T.value);
+        }
+
         // select columns test
 
         @Override

Reply via email to