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

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

commit 9fc263727a745aa9e3110343a58fcdb213115e3e
Author: Stephen Mallette <[email protected]>
AuthorDate: Thu Jul 6 13:19:48 2023 -0400

    TINKERPOP-2965 Fixed bug in FilterRankingStrategy
    
    This problem showed up in 3.5.6/3.6.3 after TINKERPOP-2919 which improved 
performance. The changes failed to properly propogate labels up from child 
traversals into the TraversalParent cache it created. As a result, labels 
started shifting around when they shouldn't have.
---
 CHANGELOG.asciidoc                                 |  3 +-
 .../optimization/FilterRankingStrategy.java        | 33 +++++++++----
 .../process/traversal/util/DepthComparator.java    | 54 ++++++++++++++++++++++
 .../process/traversal/util/TraversalHelper.java    | 35 ++++++++++++++
 .../traversal/util/TraversalHelperTest.java        | 43 ++++++++++++++++-
 .../Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs |  2 +
 gremlin-go/driver/cucumber/gremlin.go              |  2 +
 .../gremlin-javascript/test/cucumber/gremlin.js    |  2 +
 gremlin-python/src/main/python/radish/gremlin.py   |  2 +
 gremlin-test/features/filter/Where.feature         | 36 +++++++++++++++
 10 files changed, 200 insertions(+), 12 deletions(-)

diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 6225ef9b79..66d77bf20a 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -28,7 +28,8 @@ 
image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 * Added `gremlin.spark.dontDeleteNonEmptyOutput` to stop deleting the output 
folder if it is not empty in `spark-gremlin`.
 * Upgraded `gremlin-javascript` and `gremlint` to Node 16.20.0.
 * Upgraded `gremlin-go` to Go 1.20.
-* Improved the python Translator class
+* Improved the python Translator class.
+* Fixed bug in `FilterRankingStrategy` that was preventing certain traversals 
from recognizing labels in child traversals.
 * Added `gremlin-java8.bat` file as a workaround to allow loading the console 
using Java 8 on Windows.
 * Fixed a bug in `gremlin-server` where timeout tasks were not cancelled and 
could cause very large memory usage when timeout is large.
 * Removed `jcabi-manifests` dependency from `gremlin-core`, `gremlin-driver`, 
and `gremlin-server`.
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategy.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategy.java
index 65723a2894..9ebfeb7ed8 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategy.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategy.java
@@ -38,17 +38,15 @@ import 
org.apache.tinkerpop.gremlin.process.traversal.step.filter.WhereTraversal
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.OrderGlobalStep;
 import 
org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
-import org.apache.tinkerpop.gremlin.structure.Graph;
 import org.javatuples.Pair;
 
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
 import java.util.stream.Collectors;
 
 /**
@@ -83,20 +81,37 @@ public final class FilterRankingStrategy extends 
AbstractTraversalStrategy<Trave
             // traversals. This little cache keeps the effective data of that 
function which is if there is a
             // lambda in the children and the set of scope keys. note that the 
lambda sorta trumps the labels in
             // that if there is a lambda there's no real point to doing any 
sort of eval of the labels.
+            //
+            // this cache holds the parent and a pair. the first item in the 
pair is a boolean which is true if
+            // lambda is present and false otherwise. the second item in the 
pair is a set of labels from any
+            // Scoping steps
             final Map<TraversalParent, Pair<Boolean, Set<String>>> 
traversalParentCache = new HashMap<>();
             final Map<Step, Integer> stepRanking = new HashMap<>();
 
-            // build up the little cache
+            // gather the parents and their Scoping/LambdaHolder steps to 
build up the cache. since the traversal is
+            // processed in depth first manner, the entries gathered to m are 
deepest child first and held in order,
+            // so that the cache can be constructed with parent's knowing 
their children were processed first
             final Map<TraversalParent, List<Step<?,?>>> m =
-                    
TraversalHelper.getStepsOfAssignableClassRecursively(traversal, Scoping.class, 
LambdaHolder.class).stream().
-                    collect(Collectors.groupingBy(step -> ((Step) 
step).getTraversal().getParent()));
+                    
TraversalHelper.getStepsOfAssignableClassRecursivelyFromDepth(traversal, 
TraversalParent.class).stream().
+                    collect(Collectors.groupingBy(step -> ((Step) 
step).getTraversal().getParent(), LinkedHashMap::new, Collectors.toList()));
+
+            // build the cache and use it to detect if any children impact the 
Pair in any way. in the case of a
+            // child with a lambda, the parent would simply inherit that true. 
in the case of additional labels they
+            // would just be appended to the list for the parent.
             m.forEach((k, v) -> {
-                final boolean hasLambda = v.stream().anyMatch(s -> s 
instanceof LambdaHolder);
+                final boolean hasLambda = v.stream().anyMatch(s -> s 
instanceof LambdaHolder ||
+                        (traversalParentCache.containsKey(s) && 
traversalParentCache.get(s).getValue0()));
                 if (hasLambda) {
                     traversalParentCache.put(k, Pair.with(true, 
Collections.emptySet()));
                 } else {
-                    traversalParentCache.put(k, Pair.with(false, 
v.stream().filter(s -> s instanceof Scoping).
-                            flatMap(s -> ((Scoping) 
s).getScopeKeys().stream()).collect(Collectors.toSet())));
+                    final Set<String> currentEntryScopeLabels = 
v.stream().filter(s -> s instanceof Scoping).
+                            flatMap(s -> ((Scoping) 
s).getScopeKeys().stream()).collect(Collectors.toSet());
+                    final Set<String> allScopeLabels = new 
HashSet<>(currentEntryScopeLabels);
+                    
v.stream().filter(traversalParentCache::containsKey).forEach(s -> {
+                        final TraversalParent parent = (TraversalParent) s;
+                        
allScopeLabels.addAll(traversalParentCache.get(parent).getValue1());
+                    });
+                    traversalParentCache.put(k, Pair.with(false, 
allScopeLabels));
                 }
             });
 
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/DepthComparator.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/DepthComparator.java
new file mode 100644
index 0000000000..915379c9d3
--- /dev/null
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/DepthComparator.java
@@ -0,0 +1,54 @@
+/*
+ * 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.util;
+
+import org.apache.tinkerpop.gremlin.process.traversal.Step;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.EmptyStep;
+
+import java.util.Comparator;
+
+/**
+ * A {@code Comparator} that compares steps on the depth of the traversal that 
they are in.
+ */
+public final class DepthComparator implements Comparator<Step<?,?>> {
+
+    private static final DepthComparator instance = new DepthComparator();
+
+    private DepthComparator() {}
+
+    public static DepthComparator instance() {
+        return instance;
+    }
+
+    @Override
+    public int compare(final Step<?, ?> step1, final Step<?, ?> step2) {
+        return getDepth(step2) - getDepth(step1);
+    }
+
+    private int getDepth(final Step<?,?> step) {
+        if (step == null)
+            return 0;
+        int depth = 0;
+        if (!(step instanceof EmptyStep)) {
+            final Step<?,?> parent = (Step) step.getTraversal().getParent();
+            depth = Math.max(depth, getDepth(parent) + 1);
+        }
+        return depth;
+    }
+}
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java
index 9625a56174..19117d6e9a 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java
@@ -54,14 +54,17 @@ import 
org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Comparator;
 import java.util.EnumSet;
 import java.util.HashSet;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Optional;
 import java.util.Set;
+import java.util.Stack;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
+import java.util.stream.Collectors;
 
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
@@ -313,6 +316,38 @@ public final class TraversalHelper {
         return list;
     }
 
+    /**
+     * Get steps of the specified classes throughout the traversal, collecting 
them in a fashion that orders them
+     * from the deepest steps first.
+     */
+    public static List<Step<?,?>> 
getStepsOfAssignableClassRecursivelyFromDepth(final Traversal.Admin<?, ?> 
traversal, final Class<?>... stepClasses) {
+        final List<Step<?,?>> list = new ArrayList<>();
+        final Stack<Step<?,?>> stack = new Stack<>();
+
+        traversal.getSteps().forEach(stack::push);
+
+        while (!stack.isEmpty()) {
+            final Step<?,?> current = stack.pop();
+            list.add(current);
+
+            if (current instanceof TraversalParent) {
+                ((TraversalParent) 
current).getLocalChildren().forEach(localChild -> 
localChild.getSteps().forEach(stack::push));
+                ((TraversalParent) 
current).getGlobalChildren().forEach(globalChild -> 
globalChild.getSteps().forEach(stack::push));
+            }
+        }
+
+        // sort by depth
+        list.sort(DepthComparator.instance());
+
+        return list.stream().filter(s -> {
+            for (Class<?> stepClass : stepClasses) {
+                if (stepClass.isAssignableFrom(s.getClass()))
+                    return true;
+            }
+            return false;
+        }).collect(Collectors.toList());
+    }
+
     public static boolean isGlobalChild(Traversal.Admin<?, ?> traversal) {
         while (!(traversal.isRoot())) {
             if (traversal.getParent().getLocalChildren().contains(traversal))
diff --git 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelperTest.java
 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelperTest.java
index 5e277ad3cf..c7884451ac 100644
--- 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelperTest.java
+++ 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelperTest.java
@@ -41,8 +41,6 @@ import 
org.apache.tinkerpop.gremlin.process.traversal.step.map.TraversalMapStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.VertexStep;
 import 
org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.IdentityStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.EmptyStep;
-import org.apache.tinkerpop.gremlin.process.traversal.util.DefaultTraversal;
-import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
 import org.apache.tinkerpop.gremlin.structure.PropertyType;
 import org.apache.tinkerpop.gremlin.structure.T;
 import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph;
@@ -446,4 +444,45 @@ public class TraversalHelperTest {
         assertEquals(3, steps.stream().filter(s -> s instanceof 
VertexStep).count());
         assertEquals(1, steps.stream().filter(s -> s instanceof 
FoldStep).count());
     }
+
+    @Test
+    public void shouldGetStepsOfAssignableClassRecursivelyFromDepthNoTypes() {
+        final Traversal.Admin<?,?> traversal = 
__.V().repeat(__.out()).project("x").by(out().in().fold()).asAdmin();
+        final List<Step<?,?>> steps = 
TraversalHelper.getStepsOfAssignableClassRecursivelyFromDepth(traversal);
+        assertEquals(0, steps.size());
+    }
+
+    @Test
+    public void shouldGetStepsOfAssignableClassRecursivelyFromDepthOneType() {
+        final Traversal.Admin<?,?> traversal = 
__.V().repeat(__.out()).project("x").by(out().in().fold()).asAdmin();
+        final List<Step<?,?>> steps = 
TraversalHelper.getStepsOfAssignableClassRecursivelyFromDepth(traversal, 
VertexStep.class);
+        assertEquals(3, steps.size());
+        assertThat(steps.stream().allMatch(s -> s instanceof VertexStep), 
is(true));
+    }
+
+    @Test
+    public void 
shouldGetStepsOfAssignableClassRecursivelyFromDepthMultipleTypes() {
+        final Traversal.Admin<?,?> traversal = 
__.V().repeat(__.out()).project("x").by(out().in().fold()).asAdmin();
+        final List<Step<?,?>> steps = 
TraversalHelper.getStepsOfAssignableClassRecursivelyFromDepth(traversal, 
VertexStep.class, FoldStep.class);
+        assertEquals(4, steps.size());
+        assertEquals(3, steps.stream().filter(s -> s instanceof 
VertexStep).count());
+        assertEquals(1, steps.stream().filter(s -> s instanceof 
FoldStep).count());
+    }
+
+    @Test
+    public void 
shouldGetStepsOfAssignableClassRecursivelyFromDepthEnsureOrder() {
+        final Traversal.Admin<?,?> traversal = __.V().union(
+                __.union(__.values("a"),
+                         __.union(__.values("b"), __.union(__.values("c"))),
+                         __.values("d")),
+                __.values("e")).values("f").asAdmin();
+        final List<Step<?,?>> steps = 
TraversalHelper.getStepsOfAssignableClassRecursivelyFromDepth(traversal, 
PropertiesStep.class);
+        assertEquals(6, steps.size());
+        assertEquals("c", ((PropertiesStep) 
steps.get(0)).getPropertyKeys()[0]);
+        assertEquals("b", ((PropertiesStep) 
steps.get(1)).getPropertyKeys()[0]);
+        assertEquals("d", ((PropertiesStep) 
steps.get(2)).getPropertyKeys()[0]);
+        assertEquals("a", ((PropertiesStep) 
steps.get(3)).getPropertyKeys()[0]);
+        assertEquals("e", ((PropertiesStep) 
steps.get(4)).getPropertyKeys()[0]);
+        assertEquals("f", ((PropertiesStep) 
steps.get(5)).getPropertyKeys()[0]);
+    }
 }
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs 
b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
index 5929439eb7..030deae2a4 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
@@ -333,6 +333,8 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
                
{"g_V_asXaX_outEXcreatedX_asXbX_inV_asXcX_inXcreatedX_asXdX_whereXa_ltXbX_orXgtXcXX_andXneqXdXXX_byXageX_byXweightX_byXinXcreatedX_valuesXageX_minX_selectXa_c_dX",
 new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) 
=>g.V().As("a").OutE("created").As("b").InV().As("c").In("created").As("d").Where("a",P.Lt("b").Or(P.Gt("c")).And(P.Neq("d"))).By("age").By("weight").By(__.In("created").Values<object>("age").Min<object>()).Select<object>("a","c
 [...]
                {"g_VX1X_asXaX_out_hasXageX_whereXgtXaXX_byXageX_name", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) 
=>g.V(p["vid1"]).As("a").Out().Has("age").Where(P.Gt("a")).By("age").Values<object>("name")}},
 
                {"g_VX3X_asXaX_in_out_asXbX_whereXa_eqXbXX_byXageX_name", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) 
=>g.V(p["vid3"]).As("a").In().Out().As("b").Where("a",P.Eq("b")).By("age").Values<object>("name")}},
 
+               
{"g_V_asXnX_whereXorXhasLabelXsoftwareX_hasLabelXpersonXXX_selectXnX_byXnameX", 
new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) 
=>g.V().As("n").Where(__.Or(__.HasLabel("software"),__.HasLabel("person"))).Select<object>("n").By("name")}},
 
+               
{"g_V_asXnX_whereXorXselectXnX_hasLabelXsoftwareX_selectXnX_hasLabelXpersonXXX_selectXnX_byXnameX",
 new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) 
=>g.V().As("n").Where(__.Or(__.Select<object>("n").HasLabel("software"),__.Select<object>("n").HasLabel("person"))).Select<object>("n").By("name")}},
 
                {"g_VX1X_asXaX_outXcreatedX_addEXcreatedByX_toXaX", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) 
=>g.AddV("person").Property(T.Id,1).Property("name","marko").Property("age",29).As("marko").AddV("person").Property(T.Id,2).Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property(T.Id,3).Property("name","lop").Property("lang","java").As("lop").AddV("person").Property(T.Id,4).Property("name","josh").Property("age
 [...]
                
{"g_VX1X_asXaX_outXcreatedX_addEXcreatedByX_toXaX_propertyXweight_2X", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) 
=>g.AddV("person").Property(T.Id,1).Property("name","marko").Property("age",29).As("marko").AddV("person").Property(T.Id,2).Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property(T.Id,3).Property("name","lop").Property("lang","java").As("lop").AddV("person").Property(T.Id,4).Property("name","j
 [...]
                {"g_V_outE_propertyXweight_nullX", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) 
=>g.AddV("person").Property(T.Id,1).Property("name","marko").Property("age",29).As("marko").AddV("person").Property(T.Id,2).Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property(T.Id,3).Property("name","lop").Property("lang","java").As("lop").AddV("person").Property(T.Id,4).Property("name","josh").Property("age",32).As("josh").
 [...]
diff --git a/gremlin-go/driver/cucumber/gremlin.go 
b/gremlin-go/driver/cucumber/gremlin.go
index 24877ae13f..a6ddf27eca 100644
--- a/gremlin-go/driver/cucumber/gremlin.go
+++ b/gremlin-go/driver/cucumber/gremlin.go
@@ -304,6 +304,8 @@ var translationMap = map[string][]func(g 
*gremlingo.GraphTraversalSource, p map[
     
"g_V_asXaX_outEXcreatedX_asXbX_inV_asXcX_inXcreatedX_asXdX_whereXa_ltXbX_orXgtXcXX_andXneqXdXXX_byXageX_byXweightX_byXinXcreatedX_valuesXageX_minX_selectXa_c_dX":
 {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.V().As("a").OutE("created").As("b").InV().As("c").In("created").As("d").Where("a",
 
gremlingo.P.Lt("b").Or(gremlingo.P.Gt("c")).And(gremlingo.P.Neq("d"))).By("age").By("weight").By(gremlingo.T__.In("created").Values("age").
 [...]
     "g_VX1X_asXaX_out_hasXageX_whereXgtXaXX_byXageX_name": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.V(p["vid1"]).As("a").Out().Has("age").Where(gremlingo.P.Gt("a")).By("age").Values("name")}},
 
     "g_VX3X_asXaX_in_out_asXbX_whereXa_eqXbXX_byXageX_name": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.V(p["vid3"]).As("a").In().Out().As("b").Where("a", 
gremlingo.P.Eq("b")).By("age").Values("name")}}, 
+    
"g_V_asXnX_whereXorXhasLabelXsoftwareX_hasLabelXpersonXXX_selectXnX_byXnameX": 
{func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.V().As("n").Where(gremlingo.T__.Or(gremlingo.T__.HasLabel("software"), 
gremlingo.T__.HasLabel("person"))).Select("n").By("name")}}, 
+    
"g_V_asXnX_whereXorXselectXnX_hasLabelXsoftwareX_selectXnX_hasLabelXpersonXXX_selectXnX_byXnameX":
 {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.V().As("n").Where(gremlingo.T__.Or(gremlingo.T__.Select("n").HasLabel("software"),
 gremlingo.T__.Select("n").HasLabel("person"))).Select("n").By("name")}}, 
     "g_VX1X_asXaX_outXcreatedX_addEXcreatedByX_toXaX": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.AddV("person").Property(gremlingo.T.Id, 
1).Property("name", "marko").Property("age", 
29).As("marko").AddV("person").Property(gremlingo.T.Id, 2).Property("name", 
"vadas").Property("age", 
27).As("vadas").AddV("software").Property(gremlingo.T.Id, 3).Property("name", 
"lop").Property("lang", "java").As("lop").AddV("person").Property(grem [...]
     "g_VX1X_asXaX_outXcreatedX_addEXcreatedByX_toXaX_propertyXweight_2X": 
{func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.AddV("person").Property(gremlingo.T.Id, 
1).Property("name", "marko").Property("age", 
29).As("marko").AddV("person").Property(gremlingo.T.Id, 2).Property("name", 
"vadas").Property("age", 
27).As("vadas").AddV("software").Property(gremlingo.T.Id, 3).Property("name", 
"lop").Property("lang", "java").As("lop").AddV("per [...]
     "g_V_outE_propertyXweight_nullX": {func(g *gremlingo.GraphTraversalSource, 
p map[string]interface{}) *gremlingo.GraphTraversal {return 
g.AddV("person").Property(gremlingo.T.Id, 1).Property("name", 
"marko").Property("age", 
29).As("marko").AddV("person").Property(gremlingo.T.Id, 2).Property("name", 
"vadas").Property("age", 
27).As("vadas").AddV("software").Property(gremlingo.T.Id, 3).Property("name", 
"lop").Property("lang", 
"java").As("lop").AddV("person").Property(gremlingo.T.Id, 4).Pr [...]
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 680ce38e25..2dd768ef17 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
@@ -321,6 +321,8 @@ const gremlins = {
     
g_V_asXaX_outEXcreatedX_asXbX_inV_asXcX_inXcreatedX_asXdX_whereXa_ltXbX_orXgtXcXX_andXneqXdXXX_byXageX_byXweightX_byXinXcreatedX_valuesXageX_minX_selectXa_c_dX:
 [function({g}) { return 
g.V().as("a").outE("created").as("b").inV().as("c").in_("created").as("d").where("a",P.lt("b").or(P.gt("c")).and(P.neq("d"))).by("age").by("weight").by(__.in_("created").values("age").min()).select("a","c","d").by("name")
 }], 
     g_VX1X_asXaX_out_hasXageX_whereXgtXaXX_byXageX_name: [function({g, vid1}) 
{ return 
g.V(vid1).as("a").out().has("age").where(P.gt("a")).by("age").values("name") 
}], 
     g_VX3X_asXaX_in_out_asXbX_whereXa_eqXbXX_byXageX_name: [function({g, 
vid3}) { return 
g.V(vid3).as("a").in_().out().as("b").where("a",P.eq("b")).by("age").values("name")
 }], 
+    
g_V_asXnX_whereXorXhasLabelXsoftwareX_hasLabelXpersonXXX_selectXnX_byXnameX: 
[function({g}) { return 
g.V().as("n").where(__.or(__.hasLabel("software"),__.hasLabel("person"))).select("n").by("name")
 }], 
+    
g_V_asXnX_whereXorXselectXnX_hasLabelXsoftwareX_selectXnX_hasLabelXpersonXXX_selectXnX_byXnameX:
 [function({g}) { return 
g.V().as("n").where(__.or(__.select("n").hasLabel("software"),__.select("n").hasLabel("person"))).select("n").by("name")
 }], 
     g_VX1X_asXaX_outXcreatedX_addEXcreatedByX_toXaX: [function({g, vid1}) { 
return 
g.addV("person").property(T.id,1).property("name","marko").property("age",29).as("marko").addV("person").property(T.id,2).property("name","vadas").property("age",27).as("vadas").addV("software").property(T.id,3).property("name","lop").property("lang","java").as("lop").addV("person").property(T.id,4).property("name","josh").property("age",32).as("josh").addV("software").property(T.id,5).property("name","rip
 [...]
     g_VX1X_asXaX_outXcreatedX_addEXcreatedByX_toXaX_propertyXweight_2X: 
[function({g, vid1}) { return 
g.addV("person").property(T.id,1).property("name","marko").property("age",29).as("marko").addV("person").property(T.id,2).property("name","vadas").property("age",27).as("vadas").addV("software").property(T.id,3).property("name","lop").property("lang","java").as("lop").addV("person").property(T.id,4).property("name","josh").property("age",32).as("josh").addV("software").property(T.id,5).p
 [...]
     g_V_outE_propertyXweight_nullX: [function({g}) { return 
g.addV("person").property(T.id,1).property("name","marko").property("age",29).as("marko").addV("person").property(T.id,2).property("name","vadas").property("age",27).as("vadas").addV("software").property(T.id,3).property("name","lop").property("lang","java").as("lop").addV("person").property(T.id,4).property("name","josh").property("age",32).as("josh").addV("software").property(T.id,5).property("name","ripple").property("lang","
 [...]
diff --git a/gremlin-python/src/main/python/radish/gremlin.py 
b/gremlin-python/src/main/python/radish/gremlin.py
index 6397b767ab..a57daf0582 100644
--- a/gremlin-python/src/main/python/radish/gremlin.py
+++ b/gremlin-python/src/main/python/radish/gremlin.py
@@ -306,6 +306,8 @@ world.gremlins = {
     
'g_V_asXaX_outEXcreatedX_asXbX_inV_asXcX_inXcreatedX_asXdX_whereXa_ltXbX_orXgtXcXX_andXneqXdXXX_byXageX_byXweightX_byXinXcreatedX_valuesXageX_minX_selectXa_c_dX':
 [(lambda 
g:g.V().as_('a').outE('created').as_('b').inV().as_('c').in_('created').as_('d').where('a',P.lt('b').or_(P.gt('c')).and_(P.neq('d'))).by('age').by('weight').by(__.in_('created').age.min_()).select('a','c','d').by('name'))],
 
     'g_VX1X_asXaX_out_hasXageX_whereXgtXaXX_byXageX_name': [(lambda g, 
vid1=None:g.V(vid1).as_('a').out().has('age').where(P.gt('a')).by('age').name)],
 
     'g_VX3X_asXaX_in_out_asXbX_whereXa_eqXbXX_byXageX_name': [(lambda g, 
vid3=None:g.V(vid3).as_('a').in_().out().as_('b').where('a',P.eq('b')).by('age').name)],
 
+    
'g_V_asXnX_whereXorXhasLabelXsoftwareX_hasLabelXpersonXXX_selectXnX_byXnameX': 
[(lambda 
g:g.V().as_('n').where(__.or_(__.hasLabel('software'),__.hasLabel('person'))).select('n').by('name'))],
 
+    
'g_V_asXnX_whereXorXselectXnX_hasLabelXsoftwareX_selectXnX_hasLabelXpersonXXX_selectXnX_byXnameX':
 [(lambda 
g:g.V().as_('n').where(__.or_(__.select('n').hasLabel('software'),__.select('n').hasLabel('person'))).select('n').by('name'))],
 
     'g_VX1X_asXaX_outXcreatedX_addEXcreatedByX_toXaX': [(lambda g, 
vid1=None:g.addV('person').property(T.id_,1).property('name','marko').property('age',29).as_('marko').addV('person').property(T.id_,2).property('name','vadas').property('age',27).as_('vadas').addV('software').property(T.id_,3).property('name','lop').property('lang','java').as_('lop').addV('person').property(T.id_,4).property('name','josh').property('age',32).as_('josh').addV('software').property(T.id_,5).property('name','
 [...]
     'g_VX1X_asXaX_outXcreatedX_addEXcreatedByX_toXaX_propertyXweight_2X': 
[(lambda g, 
vid1=None:g.addV('person').property(T.id_,1).property('name','marko').property('age',29).as_('marko').addV('person').property(T.id_,2).property('name','vadas').property('age',27).as_('vadas').addV('software').property(T.id_,3).property('name','lop').property('lang','java').as_('lop').addV('person').property(T.id_,4).property('name','josh').property('age',32).as_('josh').addV('software').property(T.id_,5
 [...]
     'g_V_outE_propertyXweight_nullX': [(lambda 
g:g.addV('person').property(T.id_,1).property('name','marko').property('age',29).as_('marko').addV('person').property(T.id_,2).property('name','vadas').property('age',27).as_('vadas').addV('software').property(T.id_,3).property('name','lop').property('lang','java').as_('lop').addV('person').property(T.id_,4).property('name','josh').property('age',32).as_('josh').addV('software').property(T.id_,5).property('name','ripple').property('lang','ja
 [...]
diff --git a/gremlin-test/features/filter/Where.feature 
b/gremlin-test/features/filter/Where.feature
index f4e8f9be82..4a68b5a873 100644
--- a/gremlin-test/features/filter/Where.feature
+++ b/gremlin-test/features/filter/Where.feature
@@ -338,4 +338,40 @@ Feature: Step - where()
       | lop |
       | lop |
       | lop |
+      | ripple |
+
+  Scenario: 
g_V_asXnX_whereXorXhasLabelXsoftwareX_hasLabelXpersonXXX_selectXnX_byXnameX
+    Given the modern graph
+    And the traversal of
+      """
+      g.V().as("n").where(
+        __.or(__.hasLabel("software"), __.hasLabel("person"))
+      ).select("n").by("name")
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | marko |
+      | vadas |
+      | josh |
+      | peter |
+      | lop |
+      | ripple |
+
+  Scenario: 
g_V_asXnX_whereXorXselectXnX_hasLabelXsoftwareX_selectXnX_hasLabelXpersonXXX_selectXnX_byXnameX
+    Given the modern graph
+    And the traversal of
+      """
+      g.V().as("n").
+        where(__.or(__.select("n").hasLabel("software"), 
__.select("n").hasLabel("person"))).
+        select("n").by("name")
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | marko |
+      | vadas |
+      | josh |
+      | peter |
+      | lop |
       | ripple |
\ No newline at end of file

Reply via email to