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

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

commit c0848a2cb3365703570b86da232da02c4a102753
Author: Stephen Mallette <[email protected]>
AuthorDate: Wed Jul 23 15:46:20 2025 -0400

    TINKERPOP-3178 Match on a single case in choose step
---
 .../process/traversal/step/branch/BranchStep.java  |  6 ++--
 .../process/traversal/step/branch/ChooseStep.java  | 13 ++++++++
 .../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/branch/Choose.feature    | 35 ++++++++++++++++++++++
 7 files changed, 59 insertions(+), 3 deletions(-)

diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/BranchStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/BranchStep.java
index fa5956d1b9..c743e0b028 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/BranchStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/BranchStep.java
@@ -53,7 +53,7 @@ public class BranchStep<S, E, M> extends ComputerAwareStep<S, 
E> implements Trav
     protected List<Pair<Traversal.Admin<M, ?>, Traversal.Admin<S, E>>> 
traversalOptions = new ArrayList<>();
 
     private boolean first = true;
-    private boolean hasBarrier;
+    protected boolean hasBarrier;
 
     public BranchStep(final Traversal.Admin traversal) {
         super(traversal);
@@ -142,7 +142,7 @@ public class BranchStep<S, E, M> extends 
ComputerAwareStep<S, E> implements Trav
     /**
      * Choose the right traversal option to apply and seed those options with 
this traverser.
      */
-    private void applyCurrentTraverser(final Traverser.Admin<S> start) {
+    protected void applyCurrentTraverser(final Traverser.Admin<S> start) {
         // first get the value of the choice based on the current traverser 
and use that to select the right traversal
         // option to which that traverser should be routed
         final M choice = TraversalUtil.apply(start, this.branchTraversal);
@@ -188,7 +188,7 @@ public class BranchStep<S, E, M> extends 
ComputerAwareStep<S, E> implements Trav
         return ends.iterator();
     }
 
-    private List<Traversal.Admin<S, E>> pickBranches(final M choice) {
+    protected List<Traversal.Admin<S, E>> pickBranches(final M choice) {
         final List<Traversal.Admin<S, E>> branches = new ArrayList<>();
         if (choice instanceof Pick) {
             if (this.traversalPickOptions.containsKey(choice)) {
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/ChooseStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/ChooseStep.java
index 86ec39e145..e8c44153f5 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/ChooseStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/ChooseStep.java
@@ -20,7 +20,14 @@ package 
org.apache.tinkerpop.gremlin.process.traversal.step.branch;
 
 import org.apache.tinkerpop.gremlin.process.traversal.Pick;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.HasNextStep;
+import 
org.apache.tinkerpop.gremlin.process.traversal.util.FastNoSuchElementException;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
 
 /**
  * A step which offers a choice of two or more Traversals to take.
@@ -51,4 +58,10 @@ public final class ChooseStep<S, E, M> extends BranchStep<S, 
E, M> {
         }
         super.addChildOption(pickToken, traversalOption);
     }
+
+    @Override
+    protected List<Traversal.Admin<S, E>> pickBranches(final M choice) {
+        final List<Traversal.Admin<S, E>> branches = 
super.pickBranches(choice);
+        return branches != null ? branches.subList(0, 1) : null;
+    }
 }
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs 
b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
index 5908c0d966..a2b97772c0 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
@@ -75,6 +75,8 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
                
{"g_V_hasLabelXpersonX_chooseXageX__optionX27L__constantXyoungXX_optionXnone__constantXoldXX_groupCount",
 new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) 
=>g.V().HasLabel("person").Choose<object>(__.Values<object>("age")).Option(p["xx1"],
 __.Constant<object>("young")).Option(Pick.None, 
__.Constant<object>("old")).GroupCount<object>()}}, 
                {"g_injectX1X_chooseXisX1X__constantX10Xfold__foldX", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.Inject<object>(p["xx2"]).Choose<object>(__.Is(p["xx2"]), 
__.Constant<object>(p["xx1"]).Fold(), __.Fold<object>())}}, 
                {"g_injectX2X_chooseXisX1X__constantX10Xfold__foldX", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.Inject<object>(p["xx3"]).Choose<object>(__.Is(p["xx2"]), 
__.Constant<object>(p["xx1"]).Fold(), __.Fold<object>())}}, 
+               
{"g_V_chooseXhasLabelXpersonX_chooseXageX_optionXbetweenX26_30X_constantXxXX_optionXbetweenX20_30X_constantXzXX_optionXnone_constantXzXX",
 new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) 
=>g.V().HasLabel("person").Choose<object>(__.Values<object>("age")).Option(P.Between(26,
 30), __.Constant<object>("x")).Option(P.Between(20, 30), 
__.Constant<object>("y")).Option(Pick.None, __.Constant<object>("z"))}}, 
+               
{"g_V_chooseXhasLabelXpersonX_chooseXageX_optionXbetweenX26_30X_nameX_optionXnone_nameX",
 new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) 
=>g.V().HasLabel("person").Choose<object>(__.Values<object>("age")).Option(P.Between(26,
 30), __.Values<object>("name")).Option(Pick.None, 
__.Values<object>("name"))}}, 
                
{"g_V_localXpropertiesXlocationX_order_byXvalueX_limitX2XX_value", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) 
=>g.V().Local<object>(__.Properties<object>("location").Order().By(T.Value, 
Order.Asc).Range<object>(0, 2)).Value<object>()}}, 
                
{"g_V_hasXlabel_personX_asXaX_localXoutXcreatedX_asXbXX_selectXa_bX_byXnameX_byXidX",
 new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.V().Has(T.Label, 
"person").As("a").Local<object>(__.Out("created").As("b")).Select<object>("a", 
"b").By("name").By(T.Id)}}, 
                {"g_V_localXoutE_countX", new List<Func<GraphTraversalSource, 
IDictionary<string, object>, ITraversal>> {(g,p) 
=>g.V().Local<object>(__.OutE().Count())}}, 
diff --git a/gremlin-go/driver/cucumber/gremlin.go 
b/gremlin-go/driver/cucumber/gremlin.go
index 1574cb18df..07b3f64f7e 100644
--- a/gremlin-go/driver/cucumber/gremlin.go
+++ b/gremlin-go/driver/cucumber/gremlin.go
@@ -45,6 +45,8 @@ var translationMap = map[string][]func(g 
*gremlingo.GraphTraversalSource, p map[
     
"g_V_hasLabelXpersonX_chooseXageX__optionX27L__constantXyoungXX_optionXnone__constantXoldXX_groupCount":
 {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.V().HasLabel("person").Choose(gremlingo.T__.Values("age")).Option(p["xx1"], 
gremlingo.T__.Constant("young")).Option(gremlingo.Pick.None, 
gremlingo.T__.Constant("old")).GroupCount()}}, 
     "g_injectX1X_chooseXisX1X__constantX10Xfold__foldX": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.Inject(p["xx2"]).Choose(gremlingo.T__.Is(p["xx2"]), 
gremlingo.T__.Constant(p["xx1"]).Fold(), gremlingo.T__.Fold())}}, 
     "g_injectX2X_chooseXisX1X__constantX10Xfold__foldX": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.Inject(p["xx3"]).Choose(gremlingo.T__.Is(p["xx2"]), 
gremlingo.T__.Constant(p["xx1"]).Fold(), gremlingo.T__.Fold())}}, 
+    
"g_V_chooseXhasLabelXpersonX_chooseXageX_optionXbetweenX26_30X_constantXxXX_optionXbetweenX20_30X_constantXzXX_optionXnone_constantXzXX":
 {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.V().HasLabel("person").Choose(gremlingo.T__.Values("age")).Option(gremlingo.P.Between(26,
 30), gremlingo.T__.Constant("x")).Option(gremlingo.P.Between(20, 30), 
gremlingo.T__.Constant("y")).Option(gremlingo.Pick.None, 
gremlingo.T__.Constant("z"))}}, 
+    
"g_V_chooseXhasLabelXpersonX_chooseXageX_optionXbetweenX26_30X_nameX_optionXnone_nameX":
 {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.V().HasLabel("person").Choose(gremlingo.T__.Values("age")).Option(gremlingo.P.Between(26,
 30), gremlingo.T__.Values("name")).Option(gremlingo.Pick.None, 
gremlingo.T__.Values("name"))}}, 
     "g_V_localXpropertiesXlocationX_order_byXvalueX_limitX2XX_value": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.V().Local(gremlingo.T__.Properties("location").Order().By(gremlingo.T.Value, 
gremlingo.Order.Asc).Range(0, 2)).Value()}}, 
     
"g_V_hasXlabel_personX_asXaX_localXoutXcreatedX_asXbXX_selectXa_bX_byXnameX_byXidX":
 {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.V().Has(gremlingo.T.Label, 
"person").As("a").Local(gremlingo.T__.Out("created").As("b")).Select("a", 
"b").By("name").By(gremlingo.T.Id)}}, 
     "g_V_localXoutE_countX": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return 
g.V().Local(gremlingo.T__.OutE().Count())}}, 
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 aab974e253..bb99c73e56 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
@@ -75,6 +75,8 @@ const gremlins = {
     
g_V_hasLabelXpersonX_chooseXageX__optionX27L__constantXyoungXX_optionXnone__constantXoldXX_groupCount:
 [function({g, xx1}) { return 
g.V().hasLabel("person").choose(__.values("age")).option(xx1, 
__.constant("young")).option(Pick.none, __.constant("old")).groupCount() }], 
     g_injectX1X_chooseXisX1X__constantX10Xfold__foldX: [function({g, xx1, 
xx2}) { return g.inject(xx2).choose(__.is(xx2), __.constant(xx1).fold(), 
__.fold()) }], 
     g_injectX2X_chooseXisX1X__constantX10Xfold__foldX: [function({g, xx1, xx3, 
xx2}) { return g.inject(xx3).choose(__.is(xx2), __.constant(xx1).fold(), 
__.fold()) }], 
+    
g_V_chooseXhasLabelXpersonX_chooseXageX_optionXbetweenX26_30X_constantXxXX_optionXbetweenX20_30X_constantXzXX_optionXnone_constantXzXX:
 [function({g}) { return 
g.V().hasLabel("person").choose(__.values("age")).option(P.between(26, 30), 
__.constant("x")).option(P.between(20, 30), __.constant("y")).option(Pick.none, 
__.constant("z")) }], 
+    
g_V_chooseXhasLabelXpersonX_chooseXageX_optionXbetweenX26_30X_nameX_optionXnone_nameX:
 [function({g}) { return 
g.V().hasLabel("person").choose(__.values("age")).option(P.between(26, 30), 
__.values("name")).option(Pick.none, __.values("name")) }], 
     g_V_localXpropertiesXlocationX_order_byXvalueX_limitX2XX_value: 
[function({g}) { return 
g.V().local(__.properties("location").order().by(T.value, Order.asc).range(0, 
2)).value() }], 
     
g_V_hasXlabel_personX_asXaX_localXoutXcreatedX_asXbXX_selectXa_bX_byXnameX_byXidX:
 [function({g}) { return g.V().has(T.label, 
"person").as("a").local(__.out("created").as("b")).select("a", 
"b").by("name").by(T.id) }], 
     g_V_localXoutE_countX: [function({g}) { return 
g.V().local(__.outE().count()) }], 
diff --git a/gremlin-python/src/main/python/radish/gremlin.py 
b/gremlin-python/src/main/python/radish/gremlin.py
index 27a45da568..3616d5a8e6 100644
--- a/gremlin-python/src/main/python/radish/gremlin.py
+++ b/gremlin-python/src/main/python/radish/gremlin.py
@@ -48,6 +48,8 @@ world.gremlins = {
     
'g_V_hasLabelXpersonX_chooseXageX__optionX27L__constantXyoungXX_optionXnone__constantXoldXX_groupCount':
 [(lambda g, 
xx1=None:g.V().has_label('person').choose(__.values('age')).option(xx1, 
__.constant('young')).option(Pick.none, __.constant('old')).group_count())], 
     'g_injectX1X_chooseXisX1X__constantX10Xfold__foldX': [(lambda g, 
xx1=None,xx2=None:g.inject(xx2).choose(__.is_(xx2), __.constant(xx1).fold(), 
__.fold()))], 
     'g_injectX2X_chooseXisX1X__constantX10Xfold__foldX': [(lambda g, 
xx1=None,xx3=None,xx2=None:g.inject(xx3).choose(__.is_(xx2), 
__.constant(xx1).fold(), __.fold()))], 
+    
'g_V_chooseXhasLabelXpersonX_chooseXageX_optionXbetweenX26_30X_constantXxXX_optionXbetweenX20_30X_constantXzXX_optionXnone_constantXzXX':
 [(lambda 
g:g.V().has_label('person').choose(__.values('age')).option(P.between(26, 30), 
__.constant('x')).option(P.between(20, 30), __.constant('y')).option(Pick.none, 
__.constant('z')))], 
+    
'g_V_chooseXhasLabelXpersonX_chooseXageX_optionXbetweenX26_30X_nameX_optionXnone_nameX':
 [(lambda 
g:g.V().has_label('person').choose(__.values('age')).option(P.between(26, 30), 
__.values('name')).option(Pick.none, __.values('name')))], 
     'g_V_localXpropertiesXlocationX_order_byXvalueX_limitX2XX_value': [(lambda 
g:g.V().local(__.properties('location').order().by(T.value, 
Order.asc).range_(0, 2)).value())], 
     
'g_V_hasXlabel_personX_asXaX_localXoutXcreatedX_asXbXX_selectXa_bX_byXnameX_byXidX':
 [(lambda g:g.V().has(T.label, 
'person').as_('a').local(__.out('created').as_('b')).select('a', 
'b').by('name').by(T.id_))], 
     'g_V_localXoutE_countX': [(lambda g:g.V().local(__.out_e().count()))], 
diff --git 
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/branch/Choose.feature
 
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/branch/Choose.feature
index 9067922b23..6f810d6563 100644
--- 
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/branch/Choose.feature
+++ 
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/branch/Choose.feature
@@ -152,3 +152,38 @@ Feature: Step - choose()
     Then the result should be unordered
       | result |
       | l[d[2].i] |
+
+  Scenario: 
g_V_chooseXhasLabelXpersonX_chooseXageX_optionXbetweenX26_30X_constantXxXX_optionXbetweenX20_30X_constantXzXX_optionXnone_constantXzXX
+    Given the modern graph
+    And the traversal of
+      """
+      g.V().hasLabel("person").
+        choose(__.values("age")).
+          option(P.between(26, 30), __.constant("x")).
+          option(P.between(20, 30), __.constant("y")).
+          option(Pick.none, __.constant("z"))
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | x |
+      | x |
+      | z |
+      | z |
+
+  Scenario: 
g_V_chooseXhasLabelXpersonX_chooseXageX_optionXbetweenX26_30X_nameX_optionXnone_nameX
+    Given the modern graph
+    And the traversal of
+      """
+      g.V().hasLabel("person").
+        choose(__.values("age")).
+          option(P.between(26, 30), __.values("name")).
+          option(Pick.none, __.values("name"))
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | marko |
+      | vadas |
+      | josh |
+      | peter |

Reply via email to