You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by sp...@apache.org on 2023/04/20 21:48:37 UTC

[tinkerpop] 01/01: TINKERPOP-2928 Fixed bug in element() with edge properties CTR

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

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

commit c380f759e274143cf895888f45743906a933d19c
Author: Stephen Mallette <st...@amazon.com>
AuthorDate: Thu Apr 20 14:57:02 2023 -0400

    TINKERPOP-2928 Fixed bug in element() with edge properties CTR
---
 CHANGELOG.asciidoc                                 |  1 +
 docs/src/reference/the-traversal.asciidoc          |  2 +-
 .../process/traversal/step/map/ElementStep.java    |  2 +-
 .../strategy/optimization/LazyBarrierStrategy.java |  7 +-
 .../Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs | 10 ++-
 gremlin-go/driver/cucumber/gremlin.go              | 10 ++-
 .../gremlin-javascript/test/cucumber/gremlin.js    | 10 ++-
 gremlin-python/src/main/python/radish/gremlin.py   | 10 ++-
 .../gremlin/test/features/map/Element.feature      | 81 ++++++++++++++++++++--
 9 files changed, 110 insertions(+), 23 deletions(-)

diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 49df090a76..31e8cec8e7 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -25,6 +25,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 
 This release also includes changes from <<release-3-5-6, 3.5.6>>.
 
+* Fixed bug in `element()` when traversing from edges where bulking was enabled.
 * Refactored `PropertyMapStep` to improve extensibility by providers.
 * Fixed bug in grammar that prevented declaration of a `Map` key named `new` without quotes.
 * Fixed bug in grammar that prevented parsing of `Map` key surrounded by parenthesis which is allowable in Groovy.
diff --git a/docs/src/reference/the-traversal.asciidoc b/docs/src/reference/the-traversal.asciidoc
index 1450c944ca..b094418e94 100644
--- a/docs/src/reference/the-traversal.asciidoc
+++ b/docs/src/reference/the-traversal.asciidoc
@@ -1258,7 +1258,7 @@ link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gre
 
 The `element()` step is a no-argument step that traverses from a `Property` to the `Element` that owns it.
 
-[gremlin-groovy]
+[gremlin-groovy,theCrew]
 ----
 g.V().properties().element() <1>
 g.E().properties().element() <2>
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ElementStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ElementStep.java
index 092289c7a3..62b2bf33c2 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ElementStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ElementStep.java
@@ -28,7 +28,7 @@ import java.util.Collections;
 import java.util.Set;
 
 /**
- * Traverse from a Property to its Element.
+ * Traverse from a {@link Property} to its {@link Element}.
  *
  * @author Mike Personick (http://github.com/mikepersonick)
  */
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/LazyBarrierStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/LazyBarrierStrategy.java
index d7cf224baa..adb7b40460 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/LazyBarrierStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/LazyBarrierStrategy.java
@@ -26,13 +26,13 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.PathProcessor;
 import org.apache.tinkerpop.gremlin.process.traversal.step.filter.DropStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.filter.HasStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.filter.NoneStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.ElementStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.FlatMapStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.GraphStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.NoOpBarrierStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.VertexStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.ProfileSideEffectStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.EmptyStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.util.ProfileStep;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
@@ -78,12 +78,13 @@ public final class LazyBarrierStrategy extends AbstractTraversalStrategy<Travers
 
     @Override
     public void apply(final Traversal.Admin<?, ?> traversal) {
-        // drop() is a problem for bulked edge/meta properties because of Property equality changes in TINKERPOP-2318
+        // drop()/element() is a problem for bulked edge/meta properties because of Property equality changes in TINKERPOP-2318
         // which made it so that a Property is equal if the key/value is equal. as a result, they bulk together which
         // is fine for almost all cases except when you wish to drop the property.
         if (TraversalHelper.onGraphComputer(traversal) ||
                 traversal.getTraverserRequirements().contains(TraverserRequirement.PATH) ||
-                TraversalHelper.hasStepOfAssignableClass(DropStep.class, traversal))
+                TraversalHelper.hasStepOfAssignableClass(DropStep.class, traversal)||
+                TraversalHelper.hasStepOfAssignableClass(ElementStep.class, traversal))
             return;
 
         boolean foundFlatMap = false;
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
index 7feb9ade10..1e2a08eabc 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
@@ -497,9 +497,13 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
                {"g_E_sampleX1X_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E().Sample(1).Count()}}, 
                {"g_V_sampleX1X_byXageX_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Sample(1).By("age").Count()}}, 
                {"g_V_order_byXnoX_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Order().By("no").Count()}}, 
-               {"g_V_properties_element", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["xx1"]).Properties<object>().Element().Limit<object>(1)}}, 
-               {"g_E_properties_element", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E(p["xx1"]).Properties<object>().Element().Limit<object>(1)}}, 
-               {"g_V_properties_properties_element_element", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["xx1"]).Properties<object>().Properties<object>().Element().Element().Limit<object>(1)}}, 
+               {"g_VX1X_properties_element", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V((Vertex) p["v2"]).Properties<object>().Element().Limit<object>(1)}}, 
+               {"g_V_properties_element", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Properties<object>().Element()}}, 
+               {"g_V_propertiesXageX_element", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Properties<object>("age").Element()}}, 
+               {"g_EX_properties_element", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E(p["eid11"]).Properties<object>().Element().Limit<object>(1)}}, 
+               {"g_E_properties_element", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E().Properties<object>().Element()}}, 
+               {"g_VXv7_properties_properties_element_element", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V((Vertex) p["v7"]).Properties<object>().Properties<object>().Element().Element().Limit<object>(1)}}, 
+               {"g_V_properties_properties_element_element", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V((Vertex) p["v7"]).Properties<object>().Properties<object>().Element().Element()}}, 
                {"g_V_elementMap", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ElementMap<object>()}}, 
                {"g_V_elementMapXname_ageX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ElementMap<object>("name","age")}}, 
                {"g_EX11X_elementMap", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E(p["eid11"]).ElementMap<object>()}}, 
diff --git a/gremlin-go/driver/cucumber/gremlin.go b/gremlin-go/driver/cucumber/gremlin.go
index 036d4b50a2..63f255b3fd 100644
--- a/gremlin-go/driver/cucumber/gremlin.go
+++ b/gremlin-go/driver/cucumber/gremlin.go
@@ -468,9 +468,13 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[
     "g_E_sampleX1X_count": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E().Sample(1).Count()}}, 
     "g_V_sampleX1X_byXageX_count": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Sample(1).By("age").Count()}}, 
     "g_V_order_byXnoX_count": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Order().By("no").Count()}}, 
-    "g_V_properties_element": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["xx1"]).Properties().Element().Limit(1)}}, 
-    "g_E_properties_element": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E(p["xx1"]).Properties().Element().Limit(1)}}, 
-    "g_V_properties_properties_element_element": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["xx1"]).Properties().Properties().Element().Element().Limit(1)}}, 
+    "g_VX1X_properties_element": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["v2"]).Properties().Element().Limit(1)}}, 
+    "g_V_properties_element": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Properties().Element()}}, 
+    "g_V_propertiesXageX_element": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Properties("age").Element()}}, 
+    "g_EX_properties_element": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E(p["eid11"]).Properties().Element().Limit(1)}}, 
+    "g_E_properties_element": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E().Properties().Element()}}, 
+    "g_VXv7_properties_properties_element_element": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["v7"]).Properties().Properties().Element().Element().Limit(1)}}, 
+    "g_V_properties_properties_element_element": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["v7"]).Properties().Properties().Element().Element()}}, 
     "g_V_elementMap": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().ElementMap()}}, 
     "g_V_elementMapXname_ageX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().ElementMap("name", "age")}}, 
     "g_EX11X_elementMap": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E(p["eid11"]).ElementMap()}}, 
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
index 93d0ad4e55..e01cd30e54 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
@@ -487,9 +487,13 @@ const gremlins = {
     g_E_sampleX1X_count: [function({g}) { return g.E().sample(1).count() }], 
     g_V_sampleX1X_byXageX_count: [function({g}) { return g.V().sample(1).by("age").count() }], 
     g_V_order_byXnoX_count: [function({g}) { return g.V().order().by("no").count() }], 
-    g_V_properties_element: [function({g, xx1}) { return g.V(xx1).properties().element().limit(1) }], 
-    g_E_properties_element: [function({g, xx1}) { return g.E(xx1).properties().element().limit(1) }], 
-    g_V_properties_properties_element_element: [function({g, xx1}) { return g.V(xx1).properties().properties().element().element().limit(1) }], 
+    g_VX1X_properties_element: [function({g, v2}) { return g.V(v2).properties().element().limit(1) }], 
+    g_V_properties_element: [function({g}) { return g.V().properties().element() }], 
+    g_V_propertiesXageX_element: [function({g}) { return g.V().properties("age").element() }], 
+    g_EX_properties_element: [function({g, eid11}) { return g.E(eid11).properties().element().limit(1) }], 
+    g_E_properties_element: [function({g}) { return g.E().properties().element() }], 
+    g_VXv7_properties_properties_element_element: [function({g, v7}) { return g.V(v7).properties().properties().element().element().limit(1) }], 
+    g_V_properties_properties_element_element: [function({g, v7}) { return g.V(v7).properties().properties().element().element() }], 
     g_V_elementMap: [function({g}) { return g.V().elementMap() }], 
     g_V_elementMapXname_ageX: [function({g}) { return g.V().elementMap("name","age") }], 
     g_EX11X_elementMap: [function({g, eid11}) { return g.E(eid11).elementMap() }], 
diff --git a/gremlin-python/src/main/python/radish/gremlin.py b/gremlin-python/src/main/python/radish/gremlin.py
index 9b0deb0710..6aeddf7f47 100644
--- a/gremlin-python/src/main/python/radish/gremlin.py
+++ b/gremlin-python/src/main/python/radish/gremlin.py
@@ -469,9 +469,13 @@ world.gremlins = {
     'g_E_sampleX1X_count': [(lambda g:g.E().sample(1).count())], 
     'g_V_sampleX1X_byXageX_count': [(lambda g:g.V().sample(1).by('age').count())], 
     'g_V_order_byXnoX_count': [(lambda g:g.V().order().by('no').count())], 
-    'g_V_properties_element': [(lambda g, xx1=None:g.V(xx1).properties().element()[0:1])], 
-    'g_E_properties_element': [(lambda g, xx1=None:g.E(xx1).properties().element()[0:1])], 
-    'g_V_properties_properties_element_element': [(lambda g, xx1=None:g.V(xx1).properties().properties().element().element()[0:1])], 
+    'g_VX1X_properties_element': [(lambda g, v2=None:g.V(v2).properties().element()[0:1])], 
+    'g_V_properties_element': [(lambda g:g.V().properties().element())], 
+    'g_V_propertiesXageX_element': [(lambda g:g.V().properties('age').element())], 
+    'g_EX_properties_element': [(lambda g, eid11=None:g.E(eid11).properties().element()[0:1])], 
+    'g_E_properties_element': [(lambda g:g.E().properties().element())], 
+    'g_VXv7_properties_properties_element_element': [(lambda g, v7=None:g.V(v7).properties().properties().element().element()[0:1])], 
+    'g_V_properties_properties_element_element': [(lambda g, v7=None:g.V(v7).properties().properties().element().element())], 
     'g_V_elementMap': [(lambda g:g.V().elementMap())], 
     'g_V_elementMapXname_ageX': [(lambda g:g.V().elementMap('name','age'))], 
     'g_EX11X_elementMap': [(lambda g, eid11=None:g.E(eid11).elementMap())], 
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Element.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Element.feature
index a94e4bde31..6f5556d939 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Element.feature
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Element.feature
@@ -19,41 +19,110 @@
 Feature: Step - element()
 
   # VertexProperty -> Vertex
+  Scenario: g_VX1X_properties_element
+    Given the modern graph
+    And using the parameter v2 defined as "v[josh]"
+    And the traversal of
+      """
+      g.V(v2).properties().element().limit(1)
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | v[josh] |
+
   Scenario: g_V_properties_element
     Given the modern graph
-    And using the parameter xx1 defined as "v[josh]"
     And the traversal of
       """
-      g.V(xx1).properties().element().limit(1)
+      g.V().properties().element()
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | v[marko] |
+      | v[marko] |
+      | v[vadas] |
+      | v[vadas] |
+      | v[lop] |
+      | v[lop] |
+      | v[josh] |
+      | v[josh] |
+      | v[ripple] |
+      | v[ripple] |
+      | v[peter] |
+      | v[peter] |
+
+  Scenario: g_V_propertiesXageX_element
+    Given the modern graph
+    And the traversal of
+      """
+      g.V().properties("age").element()
       """
     When iterated to list
     Then the result should be unordered
       | result |
+      | v[marko] |
+      | v[vadas] |
       | v[josh] |
+      | v[peter] |
 
   # EdgeProperty -> Edge
+  Scenario: g_EX_properties_element
+    Given the modern graph
+    And using the parameter eid11 defined as "e[josh-created->lop].id"
+    And the traversal of
+      """
+      g.E(eid11).properties().element().limit(1)
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | e[josh-created->lop] |
+
   Scenario: g_E_properties_element
     Given the modern graph
-    And using the parameter xx1 defined as "e[josh-created->lop].id"
     And the traversal of
       """
-      g.E(xx1).properties().element().limit(1)
+      g.E().properties().element()
       """
     When iterated to list
     Then the result should be unordered
       | result |
+      | e[marko-created->lop] |
+      | e[marko-knows->josh] |
+      | e[marko-knows->vadas] |
+      | e[peter-created->lop] |
       | e[josh-created->lop] |
+      | e[josh-created->ripple] |
 
   # MetaProperty -> VertexProperty
+  @MultiMetaProperties
+  Scenario: g_VXv7_properties_properties_element_element
+    Given the crew graph
+    And using the parameter v7 defined as "v[stephen]"
+    And the traversal of
+      """
+      g.V(v7).properties().properties().element().element().limit(1)
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | v[stephen] |
+
   @MultiMetaProperties
   Scenario: g_V_properties_properties_element_element
     Given the crew graph
-    And using the parameter xx1 defined as "v[stephen]"
+    And using the parameter v7 defined as "v[stephen]"
     And the traversal of
       """
-      g.V(xx1).properties().properties().element().element().limit(1)
+      g.V(v7).properties().properties().element().element()
       """
     When iterated to list
     Then the result should be unordered
       | result |
+      | v[stephen] |
+      | v[stephen] |
+      | v[stephen] |
+      | v[stephen] |
       | v[stephen] |
\ No newline at end of file