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 |
