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 ce8cf122ee09df6b31078ed9326309ea84ac6d1e Author: Stephen Mallette <stepm...@amazon.com> AuthorDate: Wed Jul 23 15:46:20 2025 -0400 TINKERPOP-3178 choose semantics consistency improvements Only match on first option for switch semantics. Introduced Pick.unproductive when the choice ends up being unproductive. Pass through unproductive choices for switch semantics so that they are like if-else. Introduce ChooseSemantics enum to inform on whether the step is in if-else or switch form. Lots of documentation improvements. --- CHANGELOG.asciidoc | 5 + docs/src/dev/provider/gremlin-semantics.asciidoc | 132 ++++-- docs/src/reference/the-traversal.asciidoc | 105 ++++- docs/src/upgrade/release-3.8.x.asciidoc | 111 +++++ .../tinkerpop/gremlin/process/traversal/Pick.java | 15 +- .../traversal/dsl/graph/GraphTraversal.java | 55 +++ .../gremlin/process/traversal/dsl/graph/__.java | 21 + .../traversal/lambda/PredicateTraversal.java | 4 + .../process/traversal/step/branch/BranchStep.java | 34 +- .../process/traversal/step/branch/ChooseStep.java | 82 +++- .../grammar/TraversalMethodVisitorTest.java | 8 +- .../src/Gremlin.Net/Process/Traversal/Pick.cs | 3 + .../Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs | 28 +- gremlin-go/driver/cucumber/gremlin.go | 28 +- gremlin-go/driver/traversal.go | 10 +- .../gremlin-javascript/lib/process/traversal.js | 2 +- .../gremlin-javascript/test/cucumber/gremlin.js | 28 +- gremlin-language/src/main/antlr4/Gremlin.g4 | 3 + .../python/gremlin_python/process/traversal.py | 3 +- gremlin-python/src/main/python/radish/gremlin.py | 28 +- .../gremlin/test/features/branch/Choose.feature | 465 ++++++++++++++++++++- 21 files changed, 1096 insertions(+), 74 deletions(-) diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index 4947b39a17..4f60f397ff 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -58,6 +58,11 @@ This release also includes changes from <<release-3-7-XXX, 3.7.XXX>>. * Added integer overflow checks. * Added missing strategies to the `TraversalStrategies` global cache as well as `CoreImports` in `gremlin-groovy`. * Added missing strategies to `strategies.py` in `gremlin-python`. +* Preferred use of `TokenTraversal` when using `T` with `choose` instead of `LambdaMapTraversal` which treats `T` more abstractly as a `Function`. +* Preferred use of `is()` when using `P` with `choose` instead of a `PredicateTraverser` which allows `P` to be used more concretely rather than as a `Function`. +* Changed `choose` to only use the first `option` matched. +* Added `Pick.unproductive` to allow for matches on unproductive predicates. +* Changed `choose` to pass through traversers of unproductive predicates.` * Updated `OptionsStrategy` in `gremlin-python` to take options directly as keyword arguments. * Added static `instance()` method to `ElementIdStrategy` to an instance with the default configuration. * Updated `ElementIdStrategy.getConfiguration()` to help with serialization. diff --git a/docs/src/dev/provider/gremlin-semantics.asciidoc b/docs/src/dev/provider/gremlin-semantics.asciidoc index 6fe0d2c68e..0db6625bba 100644 --- a/docs/src/dev/provider/gremlin-semantics.asciidoc +++ b/docs/src/dev/provider/gremlin-semantics.asciidoc @@ -827,6 +827,37 @@ Incoming date remains unchanged. See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsDateStep.java[source], link:https://tinkerpop.apache.org/docs/x.y.z/reference/#asDate-step[reference] +[[asString-step]] +=== asString() + +*Description:* Returns the value of incoming traverser as strings, or if `Scope.local` is specified, returns each element inside +incoming list traverser as string. + +*Syntax:* `asString()` | `asString(Scope scope)` + +[width="100%",options="header"] +|========================================================= +|Start Step |Mid Step |Modulated |Domain |Range +|N |Y |N |`any` |`String`/`List` +|========================================================= + +*Arguments:* + +* `scope` - Determines the type of traverser it operates on. Both scopes will operate on the level of individual traversers. +The `global` scope will operate on individual traverser, casting all (except `null`) to string. The `local` scope will behave like +`global` for everything except lists, where it will cast individual non-`null` elements inside the list into string and return a +list of string instead. + +Null values from the incoming traverser are not processed and remain as null when returned. + +*Exceptions* +None + +See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsStringGlobalStep.java[source], +link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsStringLocalStep.java[source (local)], +link:https://tinkerpop.apache.org/docs/x.y.z/reference/#asString-step[reference] + + [[barrier-step]] === barrier() @@ -1030,36 +1061,6 @@ None See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/SideEffectCapStep.java[source], link:https://tinkerpop.apache.org/docs/x.y.z/reference/#cap-step[reference] -[[asString-step]] -=== asString() - -*Description:* Returns the value of incoming traverser as strings, or if `Scope.local` is specified, returns each element inside -incoming list traverser as string. - -*Syntax:* `asString()` | `asString(Scope scope)` - -[width="100%",options="header"] -|========================================================= -|Start Step |Mid Step |Modulated |Domain |Range -|N |Y |N |`any` |`String`/`List` -|========================================================= - -*Arguments:* - -* `scope` - Determines the type of traverser it operates on. Both scopes will operate on the level of individual traversers. -The `global` scope will operate on individual traverser, casting all (except `null`) to string. The `local` scope will behave like -`global` for everything except lists, where it will cast individual non-`null` elements inside the list into string and return a -list of string instead. - -Null values from the incoming traverser are not processed and remain as null when returned. - -*Exceptions* -None - -See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsStringGlobalStep.java[source], -link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsStringLocalStep.java[source (local)], -link:https://tinkerpop.apache.org/docs/x.y.z/reference/#asString-step[reference] - [[call-step]] === call() @@ -1145,6 +1146,77 @@ link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/o link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/service/ServiceRegistry.java[ServiceRegistry], link:https://tinkerpop.apache.org/docs/x.y.z/reference/#call-step[reference] +[[choose-step]] +=== choose() + +*Description:* A branch step that routes the traverser to different paths based on a choice criterion. + +*Syntax:* `choose(Traversal|T choice)` | `choose(Traversal|P choice, Traversal trueChoice)` |`choose(Traversal|P choice, Traversal trueChoice, Traversal falseChoice)` + +[width="100%",options="header"] +|========================================================= +|Start Step |Mid Step |Modulated |Domain |Range +|N |Y |Y |`any` |`any` +|========================================================= + +*Arguments:* + +* `choice` - A `Traversal`, or `T` that produces a value used to determine which option to take. In the `if-then` forms, this value may be a `P` to determine `true` or `false`. +* `trueChoice` - The traversal to take if the predicate traversal returns a value (has a next element). +* `falseChoice` - The traversal to take if the predicate traversal returns no value (has no next element). + +*Modulation:* + +* `option(pickToken, traversalOption)` - Adds a traversal option to the `choose` step. The `pickToken` is matched +against the result of the choice traversal. The `pickToken` may be a literal value, a predicate `P`, a `Traversal` +(whose first returned value is used for matching) or a `Pick` enum value. If a match is found, the traverser is routed +to the corresponding `traversalOption`. + +*Considerations:* + +The `choose()` step is a branch step that routes the traverser to different paths based on a choice criterion. There are +two main forms of the `choose()` step: + +1. *if-then form*: `choose(predicate, trueChoice, falseChoice)` - If the predicate traversal or `P` returns a value +(has a next element), the traverser is routed to the trueChoice traversal. Otherwise, it is routed to the falseChoice +traversal. If the predicate is unproductive or if the falseChoice is not specified, then the traverser passes through. + +2. *switch form*: `choose(choice).option(pickValue, resultTraversal)` - The choice which may be a `Traversal` or +`T` produces a value that is matched against the pickValue of each option. If a match is found, the traverser is routed +to the corresponding resultTraversal and no further matches are attempted. If no match is found then the traverser is +filtered, but, for these cases, the `Pick.none` option can be provided to match those cases. If the choiceTraversal is +unproductive, then the traverser passes through by default or can be matched on `Pick.unproductive`. + +The `choose()` step can be used with the following special `Pick` tokens: + +* `Pick.none` - Used to specify a default option when no other options match. +* `Pick.unproductive` - Used when the choice traversal produces no value. + +`choose` does not allow more than one traversal to be assigned to a single `Pick`. The last `Pick` assigned via `option` +is the one that will be used. + +The `choose()` step ensures that only one option is selected for each traverser, unlike other branch steps like +`union()` that can route a traverser to multiple paths. As it is like `union()`, note that each `option` stream will +behave like one: + +[source,text] +---- +gremlin> g.V().union(__.has("name", "vadas").values('age').fold(), __.has('name',neq('vadas')).values('name').fold()) +==>[27] +==>[marko,lop,josh,ripple,peter] +gremlin> g.V().choose(__.has("name", "vadas"), __.values('age').fold(), __.values('name').fold()) +==>[27] +==>[marko,lop,josh,ripple,peter] +---- + +*Exceptions* + +* `IllegalArgumentException` - If `Pick.any` is used as an option token, as only one option per traverser is allowed. +* `IllegalArgumentException` - If the same pick token is used more than once. + +See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/ChooseStep.java[source], +link:https://tinkerpop.apache.org/docs/x.y.z/reference/#choose-step[reference] + [[combine-step]] === combine() diff --git a/docs/src/reference/the-traversal.asciidoc b/docs/src/reference/the-traversal.asciidoc index bbc2f106f3..44aa4b0e14 100644 --- a/docs/src/reference/the-traversal.asciidoc +++ b/docs/src/reference/the-traversal.asciidoc @@ -1077,24 +1077,33 @@ link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gre image::choose-step.png[width=700] The `choose()`-step (*branch*) routes the current traverser to a particular traversal branch option. With `choose()`, -it is possible to implement if/then/else-semantics as well as more complicated selections. +it is possible to implement two different types of semantics: if-then-else (conditional branching) and switch +(value-based selection). + +==== If-Then-Else + +The if-the-else semantics of `choose()` evaluate a predicate traversal and route the traverser to either the "true" +branch or the "false" branch based on the result. [gremlin-groovy,modern] ---- g.V().hasLabel('person'). choose(values('age').is(lte(30)), - __.in(), - __.out()).values('name') <1> + __.in(), + __.out()).values('name') <1> g.V().hasLabel('person'). - choose(values('age')). - option(27, __.in()). - option(32, __.out()).values('name') <2> + choose(outE('knows').count().is(gt(0)), + __.out('knows'), + __.identity()).values('name') <2> ---- -<1> If the traversal yields an element, then do `in`, else do `out` (i.e. true/false-based option selection). -<2> Use the result of the traversal as a key to the map of traversal options (i.e. value-based option selection). +<1> If the person's age is less than or equal to 30, then traverse to incoming vertices, else traverse to outgoing +vertices. +<2> If the person has outgoing "knows" edges, then traverse to those known vertices, else return the person vertex +itself. -If the "false"-branch is not provided, then if/then-semantics are implemented. +If the "false"-branch is not provided, then simple if-then-semantics are implemented, where traversers that don't match +the condition are passed through unchanged. [gremlin-groovy,modern] ---- @@ -1103,30 +1112,94 @@ g.V().choose(hasLabel('person'), out('created'), identity()).values('name') <2> ---- <1> If the vertex is a person, emit the vertices they created, else emit the vertex. -<2> If/then/else with an `identity()` on the false-branch is equivalent to if/then with no false-branch. +<2> if-the-else with an `identity()` on the false-branch is equivalent to if-then with no false-branch. + +==== Switch -Note that `choose()` can have an arbitrary number of options and moreover, can take an anonymous traversal as its choice function. +The switch semantics of `choose()` use the result of a traversal as a key to select from multiple traversal options. +This allows for more complex branching logic beyond simple true/false conditions. [gremlin-groovy,modern] ---- +g.V().hasLabel('person'). + choose(values('age')). + option(27, __.in()). + option(32, __.out()).values('name') <1> g.V().hasLabel('person'). choose(values('name')). option('marko', values('age')). option('josh', values('name')). option('vadas', elementMap()). - option('peter', label()) + option('peter', label()) <2> ---- -The `choose()`-step can leverage the `Pick.none` option match. For anything that does not match a specified option, the `none`-option is taken. +<1> Use the person's age value to select which traversal to apply. +<2> Use the person's name to select which property or operation to return. + +The `choose()`-step can use predicates with options to match ranges of values or other conditions. [gremlin-groovy,modern] ---- g.V().hasLabel('person'). - choose(values('name')). - option('marko', values('age')). - option(none, values('name')) + choose(values('age')). + option(P.between(26, 30), constant('younger')). + option(P.gt(30), constant('older')). + option(Pick.none, constant('unknown')) <1> +---- + +<1> If the person's age is between 26 and 30, classify them as 'younger', if greater than 30, classify as 'older', +otherwise 'unknown'. + +The token `T.label` can be used as a shorthand for `__.label()` when selecting options based on element labels. + +[gremlin-groovy,modern] +---- +g.V().choose(T.label). + option('person', out('created')). + option('software', in('created')). + values('name') <1> ---- +<1> For person vertices, traverse to the software they created; for software vertices, traverse to the people who +created them. + +Use the `Pick` enum to handle non-matching scenarios: + +* `Pick.none` - Matches when no other options match +* `Pick.unproductive` - Matches when the choice traversal produces no results + +[gremlin-groovy,modern] +---- +g.V().choose(values('age')). + option(P.between(26, 30), values('name')). + option(Pick.none, values('name')). + option(Pick.unproductive, label()) <1> +g.V().hasLabel('person'). + choose(out('knows').count()). + option(0, constant('noFriends')). + option(Pick.none, constant('hasFriends')) <2> +---- + +<1> For vertices with age between 26-30, return the name. For vertices with age outside that range, return the name. +For vertices without an age property, return the label. +<2> For people with no outgoing "knows" edges, return 'noFriends', otherwise return 'hasFriends'. + +IMPORTANT: It is important to think of `choose()` as a branching step and not a filter. The if-then semantics can +intuitively lead to thinking the latter, where no match would mean to remove the traverser from the stream. As shown in +the examples, this is not what happens. + +The `choose()`-step can be used within a `map()` step to apply the branching logic to each element in a collection. + +[gremlin-groovy,modern] +---- +g.V().hasLabel('person'). + map(choose(values('age')). + option(P.between(26, 30), values('name').fold()). + option(Pick.none, values('name').fold())) <1> +---- + +<1> For each person, create a list containing their name, using the same traversal regardless of age. + *Additional References* link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#choose(java.util.function.Function)++[`choose(Function)`], diff --git a/docs/src/upgrade/release-3.8.x.asciidoc b/docs/src/upgrade/release-3.8.x.asciidoc index 4d996ad3bb..c1d7375e2b 100644 --- a/docs/src/upgrade/release-3.8.x.asciidoc +++ b/docs/src/upgrade/release-3.8.x.asciidoc @@ -382,6 +382,94 @@ g.with_strategies(OptionsStrategy(options=myOptions)) g.with_strategies(OptionsStrategy(**myOptions)) ---- +==== choose() Semantics + +Several enhancements and clarifications have been made to the `choose()` step in TinkerPop 3.8.0 to improve its behavior +and make it more consistent: + +*First Matched Option Only* + +The `choose()` step now only executes the first matching option traversal. In previous versions, if multiple options +could match, all matching options would be executed. This change provides more predictable behavior and better aligns +with common switch/case semantics in programming languages. + +[source,text] +---- +// In 3.7.x and earlier, if multiple options matched, all would be executed +gremlin> g.V().hasLabel("person"). +......1> choose(__.values("age")). +......2> option(P.between(26, 30), __.constant("young")). +......3> option(P.between(20, 30), __.constant("also young")) +==>young +==>also young +==>young +==>also young + + +// In 3.8.x, only the first matching option is executed +gremlin> g.V().hasLabel("person"). +......1> choose(__.values("age")). +......2> option(P.between(26, 30), __.constant("young")). +......3> option(P.between(20, 30), __.constant("never reached for ages 26-30")) +==>young +==>young +---- + +*Automatic Pass-through for Unproductive Predicates* + +The `choose()` step now automatically passes through traversers when the choice traversal is unproductive. This means +that elements that don't have the properties being evaluated will continue through the traversal unchanged, rather than +being filtered out. + +[source,text] +---- +gremlin> g.V().choose(__.values("age")). +......1> option(P.between(26, 30), __.values("name")). +......2> option(Pick.none, __.values("name")) +==>marko +==>vadas +==>v[3] +==>josh +==>v[5] +==>peter +---- + +This change makes the switch semantics for `choose()` consistent with those of the if-then-else semantics for +`choose()`. + +*Pick.unproductive for Unproductive Predicates* + +A new special option token `Pick.unproductive` has been added to handle cases where the choice traversal produces no +results. This is particularly useful for handling elements that don't have the properties being evaluated. + +[source,text] +---- +// In 3.7.x, vertices without an age property would pass through unchanged +gremlin> g.V().choose(__.values("age")). +......1> option(P.between(26, 30), __.values("name")). +......2> option(Pick.none, __.values("name")) +==>marko +==>vadas +The provided traverser does not map to a value: v[3][TinkerVertex]->[PropertiesStep([age],value)][DefaultGraphTraversal] parent[[TinkerGraphStep(vertex,[]), ChooseStep([PropertiesStep([age],value)],[[none, [[PropertiesStep([name],value), EndStep]]], [(and(gte(26), lt(30))), [PropertiesStep([name],value), EndStep]]])]] +Type ':help' or ':h' for help. +Display stack trace? [yN] + +// In 3.8.x, you can specifically handle vertices where the choice traversal is unproductive +gremlin> g.V().choose(__.values("age")). +......1> option(P.between(26, 30), __.values("name")). +......2> option(Pick.none, __.values("name")). +......3> option(Pick.unproductive, __.label()) +==>marko +==>vadas +==>software +==>josh +==>software +==>peter +---- + +See: link:https://issues.apache.org/jira/browse/TINKERPOP-3178[TINKERPOP-3178], +link:https://tinkerpop.apache.org/docs/3.8.0/reference/#choose-step[Reference Documentation - choose()] + ==== Float Defaults to Double The `GremlinLangScriptEngine` has been modified to treat float literals without explicit type suffixes (like 'm', 'f', @@ -481,6 +569,29 @@ would return a `short` overflow exception or wrap to `-1` depending on language, See link:https://issues.apache.org/jira/browse/TINKERPOP-3115[TINKERPOP-3115] +===== choose() Semantics + +The semantics for the `choose()` step where adjusted a bit for consistency and clarity. The current semantics can be +found in the link:https://tinkerpop.apache.org/docs/3.8.0/dev/provider/#choose-step[Provider Documentation]. In +addition the following points could be important for providers when upgrading. + +*T.label Usage* + +When using `T.label` with `choose()`, the implementation now uses a more efficient `TokenTraversal` instead of a +`LambdaMapTraversal`. + +*Predicate Usage* + +When using predicates (`P`) with `choose()`, the implementation now prefers the use of `is()` for more concrete +predicate handling rather than using a more abstract `PredicateTraverser`. + +*ChooseSemantics enum* + +The `ChooseStep` now provides a `ChooseSemantics` enum which helps indicate if the step is configured to work with +`IF_THEN` or `SWITCH` semantics which might be helpful in trying to optimize the step. + +See: link:https://issues.apache.org/jira/browse/TINKERPOP-3178[TINKERPOP-3178] + ===== Prefer OffsetDateTime The default implementation for date type in Gremlin is now changed from the deprecated `java.util.Date` to the more diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Pick.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Pick.java index 980c7dd566..b6c56e91d9 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Pick.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Pick.java @@ -22,5 +22,18 @@ package org.apache.tinkerpop.gremlin.process.traversal; * A token used with {@code option()}. */ public enum Pick { - any, none + /** + * Acceptable option for any match. + */ + any, + + /** + * The option to take when no match is found. + */ + none, + + /** + * If the incoming traverser is unproductive then match on this option. + */ + unproductive } diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java index 8470cb289a..1a7c17dd5c 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java @@ -43,6 +43,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.lambda.ConstantTraversal; import org.apache.tinkerpop.gremlin.process.traversal.lambda.FunctionTraverser; import org.apache.tinkerpop.gremlin.process.traversal.lambda.LoopTraversal; import org.apache.tinkerpop.gremlin.process.traversal.lambda.PredicateTraverser; +import org.apache.tinkerpop.gremlin.process.traversal.lambda.TokenTraversal; import org.apache.tinkerpop.gremlin.process.traversal.lambda.TrueTraversal; import org.apache.tinkerpop.gremlin.process.traversal.step.ByModulating; import org.apache.tinkerpop.gremlin.process.traversal.step.Configuring; @@ -3339,6 +3340,21 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> { return this.asAdmin().addStep(new ChooseStep<E, E2, Boolean>(this.asAdmin(), (Traversal.Admin<E, ?>) traversalPredicate, (Traversal.Admin<E, E2>) trueChoice, (Traversal.Admin<E, E2>) __.identity())); } + /** + * Routes the current traverser to a particular traversal branch option which allows the creation of if-then-else + * like semantics within a traversal. A {@code choose} is modified by {@link #option} which provides the various + * branch choices. + * + * @param t extracts this value from an incoming element to match against an option + * @return the traversal with the appended {@link ChooseStep} + * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#choose-step" target="_blank">Reference Documentation - Choose Step</a> + * @since 3.8.0 + */ + public default <E2> GraphTraversal<S, E2> choose(final T t) { + this.asAdmin().getBytecode().addStep(Symbols.choose, t); + return this.asAdmin().addStep(new ChooseStep<>(this.asAdmin(), new TokenTraversal<>(t))); + } + /** * Routes the current traverser to a particular traversal branch option which allows the creation of if-then-else * like semantics within a traversal. A {@code choose} is modified by {@link #option} which provides the various @@ -3350,6 +3366,8 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> { * @since 3.0.0-incubating */ public default <M, E2> GraphTraversal<S, E2> choose(final Function<E, M> choiceFunction) { + if (choiceFunction instanceof T) return choose((T) choiceFunction); + this.asAdmin().getBytecode().addStep(Symbols.choose, choiceFunction); return this.asAdmin().addStep(new ChooseStep<>(this.asAdmin(), (Traversal.Admin<E, M>) __.map(new FunctionTraverser<>(choiceFunction)))); } @@ -3367,10 +3385,29 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> { */ public default <E2> GraphTraversal<S, E2> choose(final Predicate<E> choosePredicate, final Traversal<?, E2> trueChoice, final Traversal<?, E2> falseChoice) { + if (choosePredicate instanceof P) return choose((P) choosePredicate, trueChoice, falseChoice); + this.asAdmin().getBytecode().addStep(Symbols.choose, choosePredicate, trueChoice, falseChoice); return this.asAdmin().addStep(new ChooseStep<E, E2, Boolean>(this.asAdmin(), (Traversal.Admin<E, ?>) __.filter(new PredicateTraverser<>(choosePredicate)), (Traversal.Admin<E, E2>) trueChoice, (Traversal.Admin<E, E2>) falseChoice)); } + /** + * Routes the current traverser to a particular traversal branch option which allows the creation of if-then-else + * like semantics within a traversal. + * + * @param choosePredicate the {@link P} used to determine the "if" portion of the if-then-else + * @param trueChoice the traversal to execute in the event the {@code traversalPredicate} returns true + * @param falseChoice the traversal to execute in the event the {@code traversalPredicate} returns false + * @return the traversal with the appended {@link ChooseStep} + * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#choose-step" target="_blank">Reference Documentation - Choose Step</a> + * @since 3.8.0 + */ + public default <E2> GraphTraversal<S, E2> choose(final P<E> choosePredicate, + final Traversal<?, E2> trueChoice, final Traversal<?, E2> falseChoice) { + this.asAdmin().getBytecode().addStep(Symbols.choose, choosePredicate, trueChoice, falseChoice); + return this.asAdmin().addStep(new ChooseStep<E, E2, Boolean>(this.asAdmin(), (Traversal.Admin<E, ?>) __.is(choosePredicate), (Traversal.Admin<E, E2>) trueChoice, (Traversal.Admin<E, E2>) falseChoice)); + } + /** * Routes the current traverser to a particular traversal branch option which allows the creation of if-then * like semantics within a traversal. @@ -3383,10 +3420,28 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> { */ public default <E2> GraphTraversal<S, E2> choose(final Predicate<E> choosePredicate, final Traversal<?, E2> trueChoice) { + if (choosePredicate instanceof P) return choose((P) choosePredicate, trueChoice); + this.asAdmin().getBytecode().addStep(Symbols.choose, choosePredicate, trueChoice); return this.asAdmin().addStep(new ChooseStep<E, E2, Boolean>(this.asAdmin(), (Traversal.Admin<E, ?>) __.filter(new PredicateTraverser<>(choosePredicate)), (Traversal.Admin<E, E2>) trueChoice, (Traversal.Admin<E, E2>) __.identity())); } + /** + * Routes the current traverser to a particular traversal branch option which allows the creation of if-then + * like semantics within a traversal. + * + * @param choosePredicate the {@link P} used to determine the "if" portion of the if-then-else + * @param trueChoice the traversal to execute in the event the {@code traversalPredicate} returns true + * @return the traversal with the appended {@link ChooseStep} + * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#choose-step" target="_blank">Reference Documentation - Choose Step</a> + * @since 3.8.0 + */ + public default <E2> GraphTraversal<S, E2> choose(final P<E> choosePredicate, + final Traversal<?, E2> trueChoice) { + this.asAdmin().getBytecode().addStep(Symbols.choose, choosePredicate, trueChoice); + return this.asAdmin().addStep(new ChooseStep<E, E2, Boolean>(this.asAdmin(), (Traversal.Admin<E, ?>) __.is(choosePredicate), (Traversal.Admin<E, E2>) trueChoice, (Traversal.Admin<E, E2>) __.identity())); + } + /** * Returns the result of the specified traversal if it yields a result, otherwise it returns the calling element. * diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java index 22bb3b1be0..1f3933f6d1 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java @@ -1359,6 +1359,13 @@ public class __ { return __.<A>start().choose(choosePredicate, trueChoice, falseChoice); } + /** + * @see GraphTraversal#choose(P, Traversal, Traversal) + */ + public static <A, B> GraphTraversal<A, B> choose(final P<A> choosePredicate, final Traversal<?, B> trueChoice, final Traversal<?, B> falseChoice) { + return __.<A>start().choose(choosePredicate, trueChoice, falseChoice); + } + /** * @see GraphTraversal#choose(Predicate, Traversal) */ @@ -1366,6 +1373,13 @@ public class __ { return __.<A>start().choose(choosePredicate, trueChoice); } + /** + * @see GraphTraversal#choose(P, Traversal) + */ + public static <A, B> GraphTraversal<A, B> choose(final P<A> choosePredicate, final Traversal<?, B> trueChoice) { + return __.<A>start().choose(choosePredicate, trueChoice); + } + /** * @see GraphTraversal#choose(Function) */ @@ -1373,6 +1387,13 @@ public class __ { return __.<A>start().choose(choiceFunction); } + /** + * @see GraphTraversal#choose(T) + */ + public static <A, B> GraphTraversal<A, B> choose(final T t) { + return __.<A>start().choose(t); + } + /** * @see GraphTraversal#choose(Traversal) */ diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/PredicateTraversal.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/PredicateTraversal.java index 603ac500ad..3c422087ad 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/PredicateTraversal.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/PredicateTraversal.java @@ -37,6 +37,10 @@ public final class PredicateTraversal<S> extends AbstractLambdaTraversal<S, S> { this.predicate = value instanceof Predicate ? (Predicate) value : P.eq(value); } + public Predicate getPredicate() { + return predicate; + } + @Override public S next() { if (this.pass) 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..a252f28ba1 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 @@ -28,6 +28,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.util.ComputerAwareSte import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement; import org.apache.tinkerpop.gremlin.process.traversal.util.FastNoSuchElementException; import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper; +import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalProduct; import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil; import org.apache.tinkerpop.gremlin.structure.util.StringFactory; import org.javatuples.Pair; @@ -53,7 +54,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); @@ -88,6 +89,18 @@ public class BranchStep<S, E, M> extends ComputerAwareStep<S, E> implements Trav this.integrateChild(traversalOption); } + public List<Pair<Traversal.Admin<M, ?>, Traversal.Admin<S, E>>> getTraversalOptions() { + return traversalOptions; + } + + public Map<Pick, List<Traversal.Admin<S, E>>> getTraversalPickOptions() { + return traversalPickOptions; + } + + public Traversal.Admin<S, M> getBranchTraversal() { + return branchTraversal; + } + @Override public Set<TraverserRequirement> getRequirements() { return this.getSelfAndChildRequirements(); @@ -142,10 +155,11 @@ 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); + final TraversalProduct product = TraversalUtil.produce(start, this.branchTraversal); + final M choice = (M) (product.isProductive() ? product.get() : Pick.unproductive); final List<Traversal.Admin<S, E>> branches = pickBranches(choice); // if a branch is identified, then split the traverser and add it to the start of the option so that when @@ -164,7 +178,8 @@ public class BranchStep<S, E, M> extends ComputerAwareStep<S, E> implements Trav protected Iterator<Traverser.Admin<E>> computerAlgorithm() { final List<Traverser.Admin<E>> ends = new ArrayList<>(); final Traverser.Admin<S> start = this.starts.next(); - final M choice = TraversalUtil.apply(start, this.branchTraversal); + final TraversalProduct product = TraversalUtil.produce(start, this.branchTraversal); + final M choice = (M) (product.isProductive() ? product.get() : Pick.unproductive); final List<Traversal.Admin<S, E>> branches = pickBranches(choice); if (null != branches) { branches.forEach(traversal -> { @@ -188,16 +203,17 @@ 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)) { branches.addAll(this.traversalPickOptions.get(choice)); } - } - for (final Pair<Traversal.Admin<M, ?>, Traversal.Admin<S, E>> p : this.traversalOptions) { - if (TraversalUtil.test(choice, p.getValue0())) { - branches.add(p.getValue1()); + } else { + for (final Pair<Traversal.Admin<M, ?>, Traversal.Admin<S, E>> p : this.traversalOptions) { + if (TraversalUtil.test(choice, p.getValue0())) { + branches.add(p.getValue1()); + } } } return branches.isEmpty() ? this.traversalPickOptions.get(Pick.none) : branches; 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..f02e0e5e87 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,11 @@ 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.dsl.graph.DefaultGraphTraversal; import org.apache.tinkerpop.gremlin.process.traversal.step.map.HasNextStep; +import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.IdentityStep; + +import java.util.List; /** * A step which offers a choice of two or more Traversals to take. @@ -30,25 +34,91 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.map.HasNextStep; */ public final class ChooseStep<S, E, M> extends BranchStep<S, E, M> { - public ChooseStep(final Traversal.Admin traversal, final Traversal.Admin<S, M> choiceTraversal) { + /** + * Defines the manner in which the {@code ChooseStep} is configured to work. + */ + public enum ChooseSemantics { + /** + * Choose is using if-then-else semantics. + */ + IF_THEN, + + /** + * Choose is using switch semantics. + */ + SWITCH + } + + private final ChooseSemantics chooseSemantics; + + /** + * Determines if the default identity traversal is being used for the unproductive match. + */ + private boolean hasDefaultUnproductive = true; + + private ChooseStep(final Traversal.Admin traversal, final Traversal.Admin<S, M> choiceTraversal, + final ChooseSemantics chooseSemantics) { super(traversal); + this.chooseSemantics = chooseSemantics; this.setBranchTraversal(choiceTraversal); + + // Add a default Pick.unproductive option that returns the identity. + final Traversal.Admin<S,E> identityPassthrough = new DefaultGraphTraversal<>(); + identityPassthrough.addStep(new IdentityStep<>(traversal)); + + // calling super here to prevent hitting the Pick branch of code + super.addChildOption((M) Pick.unproductive, identityPassthrough); } - public ChooseStep(final Traversal.Admin traversal, final Traversal.Admin<S, ?> predicateTraversal, final Traversal.Admin<S, E> trueChoice, final Traversal.Admin<S, E> falseChoice) { - this(traversal, (Traversal.Admin<S, M>) predicateTraversal.addStep(new HasNextStep<>(predicateTraversal))); + public ChooseStep(final Traversal.Admin traversal, final Traversal.Admin<S, M> choiceTraversal) { + this(traversal, choiceTraversal, ChooseSemantics.SWITCH); + } + + public ChooseStep(final Traversal.Admin traversal, final Traversal.Admin<S, ?> predicateTraversal, + final Traversal.Admin<S, E> trueChoice, final Traversal.Admin<S, E> falseChoice) { + this(traversal, (Traversal.Admin<S, M>) predicateTraversal.addStep(new HasNextStep<>(predicateTraversal)), ChooseSemantics.IF_THEN); this.addChildOption((M) Boolean.TRUE, trueChoice); this.addChildOption((M) Boolean.FALSE, falseChoice); } + /** + * Step metadata that informs on how {@code choose()} is configured to work. + */ + public ChooseSemantics getChooseSemantics() { + return chooseSemantics; + } + + /** + * Adds a child option to this ChooseStep.This method overrides the parent implementation to provide special + * handling for {@link Pick} tokens. + */ @Override public void addChildOption(final M pickToken, final Traversal.Admin<S, E> traversalOption) { if (pickToken instanceof Pick) { if (Pick.any.equals(pickToken)) throw new IllegalArgumentException("Choose step can not have an any-option as only one option per traverser is allowed"); - if (this.traversalPickOptions.containsKey(pickToken)) - throw new IllegalArgumentException("Choose step can only have one traversal per pick token: " + pickToken); + + // trying to maintain semantics where the first match wins. for unproductive, that means, we + // have to get rid of the default one added in the constructor, but not add future ones. for + // none that means we only add the first but not the future ones. + if (Pick.unproductive.equals(pickToken) && hasDefaultUnproductive) { + this.hasDefaultUnproductive = false; + this.traversalPickOptions.remove(pickToken); + super.addChildOption(pickToken, traversalOption); + } else if (pickToken == Pick.none && !this.traversalPickOptions.containsKey(Pick.none)) { + super.addChildOption(pickToken, traversalOption); + } + } else { + super.addChildOption(pickToken, traversalOption); } - super.addChildOption(pickToken, traversalOption); + } + + /** + * Selects which branches to execute based on the choice value. + */ + @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-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitorTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitorTest.java index 6e4a26f5ab..6e7bfa69d8 100644 --- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitorTest.java +++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitorTest.java @@ -25,6 +25,7 @@ import org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.PeerPres import org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.ShortestPath; import org.apache.tinkerpop.gremlin.process.traversal.Operator; import org.apache.tinkerpop.gremlin.process.traversal.Order; +import org.apache.tinkerpop.gremlin.process.traversal.P; import org.apache.tinkerpop.gremlin.process.traversal.Pop; import org.apache.tinkerpop.gremlin.process.traversal.Scope; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.DefaultGraphTraversal; @@ -238,7 +239,12 @@ public class TraversalMethodVisitorTest { @Test public void shouldParseTraversalMethod_choose_Function() throws Exception { - compare(g.V().choose((Function) label), eval("g.V().choose(label)")); + compare(g.V().choose(label), eval("g.V().choose(label)")); + } + + @Test + public void shouldParseTraversalMethod_choose_P_Traversal() throws Exception { + compare(g.V().values("age").choose(P.eq(12), constant("matched")), eval("g.V().values(\"age\").choose(P.eq(12), constant(\"matched\"))")); } @Test diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Pick.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Pick.cs index f0312a3a2f..bdff5cac23 100644 --- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Pick.cs +++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Pick.cs @@ -39,10 +39,13 @@ namespace Gremlin.Net.Process.Traversal public static Pick None => new Pick("none"); + public static Pick Unproductive => new Pick("unproductive"); + private static readonly IDictionary<string, Pick> Properties = new Dictionary<string, Pick> { { "any", Any }, { "none", None }, + { "unproductive", Unproductive }, }; /// <summary> diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs index df5ac0d3cb..474ef0a88d 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs @@ -68,13 +68,39 @@ namespace Gremlin.Net.IntegrationTest.Gherkin {"g_V_branchXageX_optionXltX30X__youngX_optionXgtX30X__oldX_optionXnone__on_the_edgeX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Branch<object>(__.Values<object>("age")).Option(P.Lt(30), __.Constant<object>("young")).Option(P.Gt(30), __.Constant<object>("old")).Option(Pick.None, __.Constant<object>("on the edge"))}}, {"g_V_branchXidentityX_optionXhasLabelXsoftwareX__inXcreatedX_name_order_foldX_optionXhasXname_vadasX__ageX_optionXneqX123X__bothE_countX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Branch<object>(__.Identity()).Option(__.HasLabel("software"), __.In("created").Values<object>("name").Order().Fold()).Option(__.Has("name", "vadas"), __.Values<object>("age")).Option(P.Neq(123), __.BothE().Count())}}, {"g_V_chooseXout_countX_optionX2L_nameX_optionX3L_ageX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Choose<object>(__.Out().Count()).Option(p["xx1"], __.Values<object>("name")).Option(p["xx2"], __.Values<object>("age"))}}, - {"g_V_chooseXhasLabelXpersonX_and_outXcreatedX__outXknowsX__identityX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Choose<object>(__.HasLabel("person").And().Out("created"), __.Out("knows"), __.Identity()).Values<object>("name")}}, + {"g_V_chooseXhasLabelXpersonX_and_outXcreatedX__outXknowsX_identityX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Choose<object>(__.HasLabel("person").And().Out("created"), __.Out("knows"), __.Identity()).Values<object>("name")}}, + {"g_V_chooseXhasLabelXpersonX_and_outXcreatedX_outXknowsX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Choose<object>(__.HasLabel("person").And().Out("created"), __.Out("knows")).Values<object>("name")}}, {"g_V_chooseXlabelX_optionXblah__outXknowsXX_optionXbleep__outXcreatedXX_optionXnone__identityX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Choose<object>(__.Label()).Option("blah", __.Out("knows")).Option("bleep", __.Out("created")).Option(Pick.None, __.Identity()).Values<object>("name")}}, + {"g_V_chooseXTlabelX_optionXblah__outXknowsXX_optionXbleep__outXcreatedXX_optionXnone__identityX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Choose<object>(T.Label).Option("blah", __.Out("knows")).Option("bleep", __.Out("created")).Option(Pick.None, __.Identity()).Values<object>("name")}}, + {"g_V_chooseXTlabelX_optionXblah__outXknowsXX_optionXbleep__outXcreatedXX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Choose<object>(T.Label).Option("blah", __.Out("knows")).Option("bleep", __.Out("created")).Values<object>("name")}}, {"g_V_chooseXoutXknowsX_count_isXgtX0XX__outXknowsXX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Choose<object>(__.Out("knows").Count().Is(P.Gt(0)), __.Out("knows")).Values<object>("name")}}, {"g_V_hasLabelXpersonX_asXp1X_chooseXoutEXknowsX__outXknowsXX_asXp2X_selectXp1_p2X_byXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").As("p1").Choose<object>(__.OutE("knows"), __.Out("knows")).As("p2").Select<object>("p1", "p2").By("name")}}, {"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_constantXyXX_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_orXgtX34XX_constantXxXX_optionXgtX34X_constantXyXX_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).Or(P.Gt(34)), __.Constant<object>("x")).Option(P.Gt(34), __.Constant<object>("y")).Option(Pick.None, __.Constant<object>("z"))}}, + {"g_V_hasLabelXpersonX_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_chooseXhasLabelXpersonX_localXchooseXageX_optionXbetweenX26_30X_name_foldX_optionXnone_name_foldXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Local<object>(__.Choose<object>(__.Values<object>("age")).Option(P.Between(26, 30), __.Values<object>("name").Fold()).Option(Pick.None, __.Values<object>("name").Fold()))}}, + {"g_V_chooseXhasLabelXpersonX_mapXchooseXageX_optionXbetweenX26_30X_name_foldX_optionXnone_name_foldXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Map<object>(__.Choose<object>(__.Values<object>("age")).Option(P.Between(26, 30), __.Values<object>("name").Fold()).Option(Pick.None, __.Values<object>("name").Fold()))}}, + {"g_unionXV_VXhasLabelXpersonX_barrier_localXchooseXageX_optionXbetweenX26_30X_name_foldX_optionXnone_name_foldXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Union<object>(__.V(), __.V()).HasLabel("person").Barrier().Local<object>(__.Choose<object>(__.Values<object>("age")).Option(P.Between(26, 30), __.Values<object>("name").Fold()).Option(Pick.None, __.Values<object>("name").Fold()))}}, + {"g_unionXV_VXhasLabelXpersonX_barrier_mapXchooseXageX_optionXbetweenX26_30X_name_foldX_optionXnone_name_foldXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Union<object>(__.V(), __.V()).HasLabel("person").Barrier().Map<object>(__.Choose<object>(__.Values<object>("age")).Option(P.Between(26, 30), __.Values<object>("name").Fold()).Option(Pick.None, __.Values<object>("name").Fold()))}}, + {"g_V_chooseXageX_optionXbetweenX26_30X_nameX_optionXnone_nameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Choose<object>(__.Values<object>("age")).Option(P.Between(26, 30), __.Values<object>("name")).Option(Pick.None, __.Values<object>("name"))}}, + {"g_V_chooseXageX_optionXbetweenX26_30X_nameX_optionXnone_nameX_optionXunproductive_labelX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Choose<object>(__.Values<object>("age")).Option(P.Between(26, 30), __.Values<object>("name")).Option(Pick.None, __.Values<object>("name")).Option(Pick.Unproductive, __.Label())}}, + {"g_V_chooseXageX_optionXbetweenX26_30X_nameX_optionXnone_nameX_optionXnone_identityX_optionXnone_failX_optionXunproductive_identityX_optionXunproductive_labelX_optionXnone_failX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Choose<object>(__.Values<object>("age")).Option(P.Between(26, 30), __.Values<object>("name")).Option(Pick.None, __.Values<object>("name")).Option(Pick.None, __.Identity()).Option(Pick.None, __.Fail()).Op [...] + {"g_V_chooseXage_nameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Choose<object>(__.Values<object>("age"), __.Values<object>("name"))}}, + {"g_V_chooseXageX_optionXbetweenX26_30X_nameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Choose<object>(__.Values<object>("age")).Option(P.Between(26, 30), __.Values<object>("name"))}}, + {"g_V_hasLabelXpersonX_chooseXoutXcreatedX_count_isXeqX0XX__constantXdidnt_createX__constantXcreatedXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Choose<object>(__.Out("created").Count().Is(P.Eq(0)), __.Constant<object>("didnt_create"), __.Constant<object>("created"))}}, + {"g_V_hasLabelXpersonX_chooseXvaluesXageX_isXgtX30XX__valuesXageX__constantX30XX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Choose<object>(__.Values<object>("age").Is(P.Gt(30)), __.Values<object>("age"), __.Constant<object>(30))}}, + {"g_V_hasLabelXpersonX_chooseXvaluesXageX_isXgtX29XX_and_valuesXageX_isXltX35XX__valuesXnameX__constantXotherXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Choose<object>(__.Values<object>("age").Is(P.Gt(29)).And().Values<object>("age").Is(P.Lt(35)), __.Values<object>("name"), __.Constant<object>("other"))}}, + {"g_V_chooseXhasXname_vadasX__valuesXnameX__valuesXageXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Choose<object>(__.Has("name", "vadas"), __.Values<object>("name"), __.Values<object>("age"))}}, + {"g_V_hasLabelXpersonX_chooseXoutXcreatedX_countX_optionX0__constantXnoneXX_optionX1__constantXoneXX_optionX2__constantXmanyXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Choose<object>(__.Out("created").Count()).Option(p["xx0"], __.Constant<object>("none")).Option(p["xx1"], __.Constant<object>("one")).Option(p["xx2"], __.Constant<object>("many"))}}, + {"g_V_hasLabelXpersonX_chooseXlocalXoutXknowsX_countX__optionX0__constantXnoFriendsXX__optionXnone__constantXhasFriendsXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Choose<object>(__.Local<object>(__.Out("knows").Count())).Option(p["xx0"], __.Constant<object>("noFriends")).Option(Pick.None, __.Constant<object>("hasFriends"))}}, + {"g_V_chooseXoutE_countX_optionX0__constantXnoneXX_optionXnone__constantXsomeXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Choose<object>(__.OutE().Count()).Option(p["xx0"], __.Constant<object>("none")).Option(Pick.None, __.Constant<object>("some"))}}, + {"g_V_chooseXlabelX_optionXperson__chooseXageX_optionXP_lt_30__constantXyoungXX_optionXP_gte_30__constantXoldXXX_optionXsoftware__constantXprogramXX_optionXnone__constantXunknownXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Choose<object>(__.Label()).Option("person", __.Choose<object>(__.Values<object>("age")).Option(P.Lt(30), __.Constant<object>("young")).Option(P.Gte(30), __.Constant<object>("old"))).Option("software", [...] + {"g_V_chooseXhasXname_vadasX__valuesXnameXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Choose<object>(__.Has("name", "vadas"), __.Values<object>("name"))}}, + {"g_V_hasLabelXpersonX_age_chooseXP_eqX29X__valuesXnameX__constantXotherXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Values<object>("age").Choose<object>(P.Eq(29), __.Constant<object>("matched"), __.Constant<object>("other"))}}, + {"g_V_hasLabelXpersonX_age_chooseXP_eqX29X__valuesXnameXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Values<object>("age").Choose<object>(P.Eq(29), __.Constant<object>("matched"))}}, {"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 0aca8a216b..e31d3ac5be 100644 --- a/gremlin-go/driver/cucumber/gremlin.go +++ b/gremlin-go/driver/cucumber/gremlin.go @@ -38,13 +38,39 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[ "g_V_branchXageX_optionXltX30X__youngX_optionXgtX30X__oldX_optionXnone__on_the_edgeX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("person").Branch(gremlingo.T__.Values("age")).Option(gremlingo.P.Lt(30), gremlingo.T__.Constant("young")).Option(gremlingo.P.Gt(30), gremlingo.T__.Constant("old")).Option(gremlingo.Pick.None, gremlingo.T__.Constant("on the edge"))}}, "g_V_branchXidentityX_optionXhasLabelXsoftwareX__inXcreatedX_name_order_foldX_optionXhasXname_vadasX__ageX_optionXneqX123X__bothE_countX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Branch(gremlingo.T__.Identity()).Option(gremlingo.T__.HasLabel("software"), gremlingo.T__.In("created").Values("name").Order().Fold()).Option(gremlingo.T__.Has("name", "vadas"), gremlingo.T__.Values("age")).Option(gremlingo.P.Neq(123), gremli [...] "g_V_chooseXout_countX_optionX2L_nameX_optionX3L_ageX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Choose(gremlingo.T__.Out().Count()).Option(p["xx1"], gremlingo.T__.Values("name")).Option(p["xx2"], gremlingo.T__.Values("age"))}}, - "g_V_chooseXhasLabelXpersonX_and_outXcreatedX__outXknowsX__identityX_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Choose(gremlingo.T__.HasLabel("person").And().Out("created"), gremlingo.T__.Out("knows"), gremlingo.T__.Identity()).Values("name")}}, + "g_V_chooseXhasLabelXpersonX_and_outXcreatedX__outXknowsX_identityX_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Choose(gremlingo.T__.HasLabel("person").And().Out("created"), gremlingo.T__.Out("knows"), gremlingo.T__.Identity()).Values("name")}}, + "g_V_chooseXhasLabelXpersonX_and_outXcreatedX_outXknowsX_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Choose(gremlingo.T__.HasLabel("person").And().Out("created"), gremlingo.T__.Out("knows")).Values("name")}}, "g_V_chooseXlabelX_optionXblah__outXknowsXX_optionXbleep__outXcreatedXX_optionXnone__identityX_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Choose(gremlingo.T__.Label()).Option("blah", gremlingo.T__.Out("knows")).Option("bleep", gremlingo.T__.Out("created")).Option(gremlingo.Pick.None, gremlingo.T__.Identity()).Values("name")}}, + "g_V_chooseXTlabelX_optionXblah__outXknowsXX_optionXbleep__outXcreatedXX_optionXnone__identityX_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Choose(gremlingo.T.Label).Option("blah", gremlingo.T__.Out("knows")).Option("bleep", gremlingo.T__.Out("created")).Option(gremlingo.Pick.None, gremlingo.T__.Identity()).Values("name")}}, + "g_V_chooseXTlabelX_optionXblah__outXknowsXX_optionXbleep__outXcreatedXX_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Choose(gremlingo.T.Label).Option("blah", gremlingo.T__.Out("knows")).Option("bleep", gremlingo.T__.Out("created")).Values("name")}}, "g_V_chooseXoutXknowsX_count_isXgtX0XX__outXknowsXX_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Choose(gremlingo.T__.Out("knows").Count().Is(gremlingo.P.Gt(0)), gremlingo.T__.Out("knows")).Values("name")}}, "g_V_hasLabelXpersonX_asXp1X_chooseXoutEXknowsX__outXknowsXX_asXp2X_selectXp1_p2X_byXnameX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("person").As("p1").Choose(gremlingo.T__.OutE("knows"), gremlingo.T__.Out("knows")).As("p2").Select("p1", "p2").By("name")}}, "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_constantXyXX_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_orXgtX34XX_constantXxXX_optionXgtX34X_constantXyXX_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).Or(gremlingo.P.Gt(34)), gremlingo.T__.Constant("x")).Option(gremlingo.P.Gt(34), gremlingo.T__.Constant("y")).Option(gremlingo.Pick.None, gremlingo.T__ [...] + "g_V_hasLabelXpersonX_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_chooseXhasLabelXpersonX_localXchooseXageX_optionXbetweenX26_30X_name_foldX_optionXnone_name_foldXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("person").Local(gremlingo.T__.Choose(gremlingo.T__.Values("age")).Option(gremlingo.P.Between(26, 30), gremlingo.T__.Values("name").Fold()).Option(gremlingo.Pick.None, gremlingo.T__.Values("name").Fold()))}}, + "g_V_chooseXhasLabelXpersonX_mapXchooseXageX_optionXbetweenX26_30X_name_foldX_optionXnone_name_foldXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("person").Map(gremlingo.T__.Choose(gremlingo.T__.Values("age")).Option(gremlingo.P.Between(26, 30), gremlingo.T__.Values("name").Fold()).Option(gremlingo.Pick.None, gremlingo.T__.Values("name").Fold()))}}, + "g_unionXV_VXhasLabelXpersonX_barrier_localXchooseXageX_optionXbetweenX26_30X_name_foldX_optionXnone_name_foldXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Union(gremlingo.T__.V(), gremlingo.T__.V()).HasLabel("person").Barrier().Local(gremlingo.T__.Choose(gremlingo.T__.Values("age")).Option(gremlingo.P.Between(26, 30), gremlingo.T__.Values("name").Fold()).Option(gremlingo.Pick.None, gremlingo.T__.Values("name").Fold()))}}, + "g_unionXV_VXhasLabelXpersonX_barrier_mapXchooseXageX_optionXbetweenX26_30X_name_foldX_optionXnone_name_foldXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Union(gremlingo.T__.V(), gremlingo.T__.V()).HasLabel("person").Barrier().Map(gremlingo.T__.Choose(gremlingo.T__.Values("age")).Option(gremlingo.P.Between(26, 30), gremlingo.T__.Values("name").Fold()).Option(gremlingo.Pick.None, gremlingo.T__.Values("name").Fold()))}}, + "g_V_chooseXageX_optionXbetweenX26_30X_nameX_optionXnone_nameX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().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_chooseXageX_optionXbetweenX26_30X_nameX_optionXnone_nameX_optionXunproductive_labelX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Choose(gremlingo.T__.Values("age")).Option(gremlingo.P.Between(26, 30), gremlingo.T__.Values("name")).Option(gremlingo.Pick.None, gremlingo.T__.Values("name")).Option(gremlingo.Pick.Unproductive, gremlingo.T__.Label())}}, + "g_V_chooseXageX_optionXbetweenX26_30X_nameX_optionXnone_nameX_optionXnone_identityX_optionXnone_failX_optionXunproductive_identityX_optionXunproductive_labelX_optionXnone_failX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Choose(gremlingo.T__.Values("age")).Option(gremlingo.P.Between(26, 30), gremlingo.T__.Values("name")).Option(gremlingo.Pick.None, gremlingo.T__.Values("name")).Option(gremlingo.Pick.None, gremlingo.T__ [...] + "g_V_chooseXage_nameX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Choose(gremlingo.T__.Values("age"), gremlingo.T__.Values("name"))}}, + "g_V_chooseXageX_optionXbetweenX26_30X_nameX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Choose(gremlingo.T__.Values("age")).Option(gremlingo.P.Between(26, 30), gremlingo.T__.Values("name"))}}, + "g_V_hasLabelXpersonX_chooseXoutXcreatedX_count_isXeqX0XX__constantXdidnt_createX__constantXcreatedXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("person").Choose(gremlingo.T__.Out("created").Count().Is(gremlingo.P.Eq(0)), gremlingo.T__.Constant("didnt_create"), gremlingo.T__.Constant("created"))}}, + "g_V_hasLabelXpersonX_chooseXvaluesXageX_isXgtX30XX__valuesXageX__constantX30XX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("person").Choose(gremlingo.T__.Values("age").Is(gremlingo.P.Gt(30)), gremlingo.T__.Values("age"), gremlingo.T__.Constant(30))}}, + "g_V_hasLabelXpersonX_chooseXvaluesXageX_isXgtX29XX_and_valuesXageX_isXltX35XX__valuesXnameX__constantXotherXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("person").Choose(gremlingo.T__.Values("age").Is(gremlingo.P.Gt(29)).And().Values("age").Is(gremlingo.P.Lt(35)), gremlingo.T__.Values("name"), gremlingo.T__.Constant("other"))}}, + "g_V_chooseXhasXname_vadasX__valuesXnameX__valuesXageXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Choose(gremlingo.T__.Has("name", "vadas"), gremlingo.T__.Values("name"), gremlingo.T__.Values("age"))}}, + "g_V_hasLabelXpersonX_chooseXoutXcreatedX_countX_optionX0__constantXnoneXX_optionX1__constantXoneXX_optionX2__constantXmanyXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("person").Choose(gremlingo.T__.Out("created").Count()).Option(p["xx0"], gremlingo.T__.Constant("none")).Option(p["xx1"], gremlingo.T__.Constant("one")).Option(p["xx2"], gremlingo.T__.Constant("many"))}}, + "g_V_hasLabelXpersonX_chooseXlocalXoutXknowsX_countX__optionX0__constantXnoFriendsXX__optionXnone__constantXhasFriendsXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("person").Choose(gremlingo.T__.Local(gremlingo.T__.Out("knows").Count())).Option(p["xx0"], gremlingo.T__.Constant("noFriends")).Option(gremlingo.Pick.None, gremlingo.T__.Constant("hasFriends"))}}, + "g_V_chooseXoutE_countX_optionX0__constantXnoneXX_optionXnone__constantXsomeXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Choose(gremlingo.T__.OutE().Count()).Option(p["xx0"], gremlingo.T__.Constant("none")).Option(gremlingo.Pick.None, gremlingo.T__.Constant("some"))}}, + "g_V_chooseXlabelX_optionXperson__chooseXageX_optionXP_lt_30__constantXyoungXX_optionXP_gte_30__constantXoldXXX_optionXsoftware__constantXprogramXX_optionXnone__constantXunknownXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Choose(gremlingo.T__.Label()).Option("person", gremlingo.T__.Choose(gremlingo.T__.Values("age")).Option(gremlingo.P.Lt(30), gremlingo.T__.Constant("young")).Option(gremlingo.P.Gte(30), gremlingo.T__. [...] + "g_V_chooseXhasXname_vadasX__valuesXnameXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Choose(gremlingo.T__.Has("name", "vadas"), gremlingo.T__.Values("name"))}}, + "g_V_hasLabelXpersonX_age_chooseXP_eqX29X__valuesXnameX__constantXotherXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("person").Values("age").Choose(gremlingo.P.Eq(29), gremlingo.T__.Constant("matched"), gremlingo.T__.Constant("other"))}}, + "g_V_hasLabelXpersonX_age_chooseXP_eqX29X__valuesXnameXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("person").Values("age").Choose(gremlingo.P.Eq(29), gremlingo.T__.Constant("matched"))}}, "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-go/driver/traversal.go b/gremlin-go/driver/traversal.go index 6d82f6d0af..b891abb8ee 100644 --- a/gremlin-go/driver/traversal.go +++ b/gremlin-go/driver/traversal.go @@ -243,13 +243,15 @@ var Order = orders{ type pick string type picks struct { - Any pick - None pick + Any pick + None pick + Unproductive pick } var Pick = picks{ - Any: "any", - None: "none", + Any: "any", + None: "none", + Unproductive: "unproductive", } type pop string diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/traversal.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/traversal.js index a1ff9316dd..2c9ac1ded6 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/traversal.js +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/traversal.js @@ -517,7 +517,7 @@ module.exports = { merge: toEnum('Merge', 'onCreate onMatch outV inV'), operator: toEnum('Operator', 'addAll and assign div max min minus mult or sum sumLong'), order: toEnum('Order', 'asc desc shuffle'), - pick: toEnum('Pick', 'any none'), + pick: toEnum('Pick', 'any none unproductive'), pop: toEnum('Pop', 'all first last mixed'), scope: toEnum('Scope', 'global local'), t: toEnum('T', 'id key label value'), 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 e84bbbcaf9..92537804d3 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 @@ -68,13 +68,39 @@ const gremlins = { g_V_branchXageX_optionXltX30X__youngX_optionXgtX30X__oldX_optionXnone__on_the_edgeX: [function({g}) { return g.V().hasLabel("person").branch(__.values("age")).option(P.lt(30), __.constant("young")).option(P.gt(30), __.constant("old")).option(Pick.none, __.constant("on the edge")) }], g_V_branchXidentityX_optionXhasLabelXsoftwareX__inXcreatedX_name_order_foldX_optionXhasXname_vadasX__ageX_optionXneqX123X__bothE_countX: [function({g}) { return g.V().branch(__.identity()).option(__.hasLabel("software"), __.in_("created").values("name").order().fold()).option(__.has("name", "vadas"), __.values("age")).option(P.neq(123), __.bothE().count()) }], g_V_chooseXout_countX_optionX2L_nameX_optionX3L_ageX: [function({g, xx1, xx2}) { return g.V().choose(__.out().count()).option(xx1, __.values("name")).option(xx2, __.values("age")) }], - g_V_chooseXhasLabelXpersonX_and_outXcreatedX__outXknowsX__identityX_name: [function({g}) { return g.V().choose(__.hasLabel("person").and().out("created"), __.out("knows"), __.identity()).values("name") }], + g_V_chooseXhasLabelXpersonX_and_outXcreatedX__outXknowsX_identityX_name: [function({g}) { return g.V().choose(__.hasLabel("person").and().out("created"), __.out("knows"), __.identity()).values("name") }], + g_V_chooseXhasLabelXpersonX_and_outXcreatedX_outXknowsX_name: [function({g}) { return g.V().choose(__.hasLabel("person").and().out("created"), __.out("knows")).values("name") }], g_V_chooseXlabelX_optionXblah__outXknowsXX_optionXbleep__outXcreatedXX_optionXnone__identityX_name: [function({g}) { return g.V().choose(__.label()).option("blah", __.out("knows")).option("bleep", __.out("created")).option(Pick.none, __.identity()).values("name") }], + g_V_chooseXTlabelX_optionXblah__outXknowsXX_optionXbleep__outXcreatedXX_optionXnone__identityX_name: [function({g}) { return g.V().choose(T.label).option("blah", __.out("knows")).option("bleep", __.out("created")).option(Pick.none, __.identity()).values("name") }], + g_V_chooseXTlabelX_optionXblah__outXknowsXX_optionXbleep__outXcreatedXX_name: [function({g}) { return g.V().choose(T.label).option("blah", __.out("knows")).option("bleep", __.out("created")).values("name") }], g_V_chooseXoutXknowsX_count_isXgtX0XX__outXknowsXX_name: [function({g}) { return g.V().choose(__.out("knows").count().is(P.gt(0)), __.out("knows")).values("name") }], g_V_hasLabelXpersonX_asXp1X_chooseXoutEXknowsX__outXknowsXX_asXp2X_selectXp1_p2X_byXnameX: [function({g}) { return g.V().hasLabel("person").as("p1").choose(__.outE("knows"), __.out("knows")).as("p2").select("p1", "p2").by("name") }], 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_constantXyXX_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_orXgtX34XX_constantXxXX_optionXgtX34X_constantXyXX_optionXnone_constantXzXX: [function({g}) { return g.V().hasLabel("person").choose(__.values("age")).option(P.between(26, 30).or(P.gt(34)), __.constant("x")).option(P.gt(34), __.constant("y")).option(Pick.none, __.constant("z")) }], + g_V_hasLabelXpersonX_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_chooseXhasLabelXpersonX_localXchooseXageX_optionXbetweenX26_30X_name_foldX_optionXnone_name_foldXX: [function({g}) { return g.V().hasLabel("person").local(__.choose(__.values("age")).option(P.between(26, 30), __.values("name").fold()).option(Pick.none, __.values("name").fold())) }], + g_V_chooseXhasLabelXpersonX_mapXchooseXageX_optionXbetweenX26_30X_name_foldX_optionXnone_name_foldXX: [function({g}) { return g.V().hasLabel("person").map(__.choose(__.values("age")).option(P.between(26, 30), __.values("name").fold()).option(Pick.none, __.values("name").fold())) }], + g_unionXV_VXhasLabelXpersonX_barrier_localXchooseXageX_optionXbetweenX26_30X_name_foldX_optionXnone_name_foldXX: [function({g}) { return g.union(__.V(), __.V()).hasLabel("person").barrier().local(__.choose(__.values("age")).option(P.between(26, 30), __.values("name").fold()).option(Pick.none, __.values("name").fold())) }], + g_unionXV_VXhasLabelXpersonX_barrier_mapXchooseXageX_optionXbetweenX26_30X_name_foldX_optionXnone_name_foldXX: [function({g}) { return g.union(__.V(), __.V()).hasLabel("person").barrier().map(__.choose(__.values("age")).option(P.between(26, 30), __.values("name").fold()).option(Pick.none, __.values("name").fold())) }], + g_V_chooseXageX_optionXbetweenX26_30X_nameX_optionXnone_nameX: [function({g}) { return g.V().choose(__.values("age")).option(P.between(26, 30), __.values("name")).option(Pick.none, __.values("name")) }], + g_V_chooseXageX_optionXbetweenX26_30X_nameX_optionXnone_nameX_optionXunproductive_labelX: [function({g}) { return g.V().choose(__.values("age")).option(P.between(26, 30), __.values("name")).option(Pick.none, __.values("name")).option(Pick.unproductive, __.label()) }], + g_V_chooseXageX_optionXbetweenX26_30X_nameX_optionXnone_nameX_optionXnone_identityX_optionXnone_failX_optionXunproductive_identityX_optionXunproductive_labelX_optionXnone_failX: [function({g}) { return g.V().choose(__.values("age")).option(P.between(26, 30), __.values("name")).option(Pick.none, __.values("name")).option(Pick.none, __.identity()).option(Pick.none, __.fail()).option(Pick.unproductive, __.label()).option(Pick.unproductive, __.identity()).option(Pick.unproductive, __.fai [...] + g_V_chooseXage_nameX: [function({g}) { return g.V().choose(__.values("age"), __.values("name")) }], + g_V_chooseXageX_optionXbetweenX26_30X_nameX: [function({g}) { return g.V().choose(__.values("age")).option(P.between(26, 30), __.values("name")) }], + g_V_hasLabelXpersonX_chooseXoutXcreatedX_count_isXeqX0XX__constantXdidnt_createX__constantXcreatedXX: [function({g}) { return g.V().hasLabel("person").choose(__.out("created").count().is(P.eq(0)), __.constant("didnt_create"), __.constant("created")) }], + g_V_hasLabelXpersonX_chooseXvaluesXageX_isXgtX30XX__valuesXageX__constantX30XX: [function({g}) { return g.V().hasLabel("person").choose(__.values("age").is(P.gt(30)), __.values("age"), __.constant(30)) }], + g_V_hasLabelXpersonX_chooseXvaluesXageX_isXgtX29XX_and_valuesXageX_isXltX35XX__valuesXnameX__constantXotherXX: [function({g}) { return g.V().hasLabel("person").choose(__.values("age").is(P.gt(29)).and().values("age").is(P.lt(35)), __.values("name"), __.constant("other")) }], + g_V_chooseXhasXname_vadasX__valuesXnameX__valuesXageXX: [function({g}) { return g.V().choose(__.has("name", "vadas"), __.values("name"), __.values("age")) }], + g_V_hasLabelXpersonX_chooseXoutXcreatedX_countX_optionX0__constantXnoneXX_optionX1__constantXoneXX_optionX2__constantXmanyXX: [function({g, xx1, xx0, xx2}) { return g.V().hasLabel("person").choose(__.out("created").count()).option(xx0, __.constant("none")).option(xx1, __.constant("one")).option(xx2, __.constant("many")) }], + g_V_hasLabelXpersonX_chooseXlocalXoutXknowsX_countX__optionX0__constantXnoFriendsXX__optionXnone__constantXhasFriendsXXX: [function({g, xx0}) { return g.V().hasLabel("person").choose(__.local(__.out("knows").count())).option(xx0, __.constant("noFriends")).option(Pick.none, __.constant("hasFriends")) }], + g_V_chooseXoutE_countX_optionX0__constantXnoneXX_optionXnone__constantXsomeXX: [function({g, xx0}) { return g.V().choose(__.outE().count()).option(xx0, __.constant("none")).option(Pick.none, __.constant("some")) }], + g_V_chooseXlabelX_optionXperson__chooseXageX_optionXP_lt_30__constantXyoungXX_optionXP_gte_30__constantXoldXXX_optionXsoftware__constantXprogramXX_optionXnone__constantXunknownXX: [function({g}) { return g.V().choose(__.label()).option("person", __.choose(__.values("age")).option(P.lt(30), __.constant("young")).option(P.gte(30), __.constant("old"))).option("software", __.constant("program")).option(Pick.none, __.constant("unknown")) }], + g_V_chooseXhasXname_vadasX__valuesXnameXX: [function({g}) { return g.V().choose(__.has("name", "vadas"), __.values("name")) }], + g_V_hasLabelXpersonX_age_chooseXP_eqX29X__valuesXnameX__constantXotherXX: [function({g}) { return g.V().hasLabel("person").values("age").choose(P.eq(29), __.constant("matched"), __.constant("other")) }], + g_V_hasLabelXpersonX_age_chooseXP_eqX29X__valuesXnameXX: [function({g}) { return g.V().hasLabel("person").values("age").choose(P.eq(29), __.constant("matched")) }], 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-language/src/main/antlr4/Gremlin.g4 b/gremlin-language/src/main/antlr4/Gremlin.g4 index 0b60761f35..aae08bfa2d 100644 --- a/gremlin-language/src/main/antlr4/Gremlin.g4 +++ b/gremlin-language/src/main/antlr4/Gremlin.g4 @@ -1059,6 +1059,7 @@ traversalOperator traversalPick : K_ANY | K_PICK DOT K_ANY | K_NONE | K_PICK DOT K_NONE + | K_UNPRODUCTIVE | K_PICK DOT K_UNPRODUCTIVE ; traversalDT @@ -1893,6 +1894,7 @@ keyword | K_TX | K_UNFOLD | K_UNION + | K_UNPRODUCTIVE | K_UNTIL | K_UUID | K_V @@ -2153,6 +2155,7 @@ K_TRYNEXT: 'tryNext'; K_TX: 'tx'; K_UNFOLD: 'unfold'; K_UNION: 'union'; +K_UNPRODUCTIVE: 'unproductive'; K_UNTIL: 'until'; K_UUID: 'UUID'; K_V: 'V'; diff --git a/gremlin-python/src/main/python/gremlin_python/process/traversal.py b/gremlin-python/src/main/python/gremlin_python/process/traversal.py index fb74433348..f687e14bac 100644 --- a/gremlin-python/src/main/python/gremlin_python/process/traversal.py +++ b/gremlin-python/src/main/python/gremlin_python/process/traversal.py @@ -214,10 +214,11 @@ statics.add_static('shuffle', Order.shuffle) statics.add_static('asc', Order.asc) statics.add_static('desc', Order.desc) -Pick = Enum('Pick', ' any_ none') +Pick = Enum('Pick', ' any_ none unproductive') statics.add_static('any_', Pick.any_) statics.add_static('none', Pick.none) +statics.add_static('unproductive', Pick.unproductive) Pop = Enum('Pop', ' all_ first last mixed') diff --git a/gremlin-python/src/main/python/radish/gremlin.py b/gremlin-python/src/main/python/radish/gremlin.py index 9f9d5aed6e..e8db3cfea5 100644 --- a/gremlin-python/src/main/python/radish/gremlin.py +++ b/gremlin-python/src/main/python/radish/gremlin.py @@ -41,13 +41,39 @@ world.gremlins = { 'g_V_branchXageX_optionXltX30X__youngX_optionXgtX30X__oldX_optionXnone__on_the_edgeX': [(lambda g:g.V().has_label('person').branch(__.values('age')).option(P.lt(30), __.constant('young')).option(P.gt(30), __.constant('old')).option(Pick.none, __.constant('on the edge')))], 'g_V_branchXidentityX_optionXhasLabelXsoftwareX__inXcreatedX_name_order_foldX_optionXhasXname_vadasX__ageX_optionXneqX123X__bothE_countX': [(lambda g:g.V().branch(__.identity()).option(__.has_label('software'), __.in_('created').values('name').order().fold()).option(__.has('name', 'vadas'), __.values('age')).option(P.neq(123), __.both_e().count()))], 'g_V_chooseXout_countX_optionX2L_nameX_optionX3L_ageX': [(lambda g, xx1=None,xx2=None:g.V().choose(__.out().count()).option(xx1, __.values('name')).option(xx2, __.values('age')))], - 'g_V_chooseXhasLabelXpersonX_and_outXcreatedX__outXknowsX__identityX_name': [(lambda g:g.V().choose(__.has_label('person').and_().out('created'), __.out('knows'), __.identity()).values('name'))], + 'g_V_chooseXhasLabelXpersonX_and_outXcreatedX__outXknowsX_identityX_name': [(lambda g:g.V().choose(__.has_label('person').and_().out('created'), __.out('knows'), __.identity()).values('name'))], + 'g_V_chooseXhasLabelXpersonX_and_outXcreatedX_outXknowsX_name': [(lambda g:g.V().choose(__.has_label('person').and_().out('created'), __.out('knows')).values('name'))], 'g_V_chooseXlabelX_optionXblah__outXknowsXX_optionXbleep__outXcreatedXX_optionXnone__identityX_name': [(lambda g:g.V().choose(__.label()).option('blah', __.out('knows')).option('bleep', __.out('created')).option(Pick.none, __.identity()).values('name'))], + 'g_V_chooseXTlabelX_optionXblah__outXknowsXX_optionXbleep__outXcreatedXX_optionXnone__identityX_name': [(lambda g:g.V().choose(T.label).option('blah', __.out('knows')).option('bleep', __.out('created')).option(Pick.none, __.identity()).values('name'))], + 'g_V_chooseXTlabelX_optionXblah__outXknowsXX_optionXbleep__outXcreatedXX_name': [(lambda g:g.V().choose(T.label).option('blah', __.out('knows')).option('bleep', __.out('created')).values('name'))], 'g_V_chooseXoutXknowsX_count_isXgtX0XX__outXknowsXX_name': [(lambda g:g.V().choose(__.out('knows').count().is_(P.gt(0)), __.out('knows')).values('name'))], 'g_V_hasLabelXpersonX_asXp1X_chooseXoutEXknowsX__outXknowsXX_asXp2X_selectXp1_p2X_byXnameX': [(lambda g:g.V().has_label('person').as_('p1').choose(__.out_e('knows'), __.out('knows')).as_('p2').select('p1', 'p2').by('name'))], '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_constantXyXX_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_orXgtX34XX_constantXxXX_optionXgtX34X_constantXyXX_optionXnone_constantXzXX': [(lambda g:g.V().has_label('person').choose(__.values('age')).option(P.between(26, 30).or_(P.gt(34)), __.constant('x')).option(P.gt(34), __.constant('y')).option(Pick.none, __.constant('z')))], + 'g_V_hasLabelXpersonX_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_chooseXhasLabelXpersonX_localXchooseXageX_optionXbetweenX26_30X_name_foldX_optionXnone_name_foldXX': [(lambda g:g.V().has_label('person').local(__.choose(__.values('age')).option(P.between(26, 30), __.values('name').fold()).option(Pick.none, __.values('name').fold())))], + 'g_V_chooseXhasLabelXpersonX_mapXchooseXageX_optionXbetweenX26_30X_name_foldX_optionXnone_name_foldXX': [(lambda g:g.V().has_label('person').map(__.choose(__.values('age')).option(P.between(26, 30), __.values('name').fold()).option(Pick.none, __.values('name').fold())))], + 'g_unionXV_VXhasLabelXpersonX_barrier_localXchooseXageX_optionXbetweenX26_30X_name_foldX_optionXnone_name_foldXX': [(lambda g:g.union(__.V(), __.V()).has_label('person').barrier().local(__.choose(__.values('age')).option(P.between(26, 30), __.values('name').fold()).option(Pick.none, __.values('name').fold())))], + 'g_unionXV_VXhasLabelXpersonX_barrier_mapXchooseXageX_optionXbetweenX26_30X_name_foldX_optionXnone_name_foldXX': [(lambda g:g.union(__.V(), __.V()).has_label('person').barrier().map(__.choose(__.values('age')).option(P.between(26, 30), __.values('name').fold()).option(Pick.none, __.values('name').fold())))], + 'g_V_chooseXageX_optionXbetweenX26_30X_nameX_optionXnone_nameX': [(lambda g:g.V().choose(__.values('age')).option(P.between(26, 30), __.values('name')).option(Pick.none, __.values('name')))], + 'g_V_chooseXageX_optionXbetweenX26_30X_nameX_optionXnone_nameX_optionXunproductive_labelX': [(lambda g:g.V().choose(__.values('age')).option(P.between(26, 30), __.values('name')).option(Pick.none, __.values('name')).option(Pick.unproductive, __.label()))], + 'g_V_chooseXageX_optionXbetweenX26_30X_nameX_optionXnone_nameX_optionXnone_identityX_optionXnone_failX_optionXunproductive_identityX_optionXunproductive_labelX_optionXnone_failX': [(lambda g:g.V().choose(__.values('age')).option(P.between(26, 30), __.values('name')).option(Pick.none, __.values('name')).option(Pick.none, __.identity()).option(Pick.none, __.fail()).option(Pick.unproductive, __.label()).option(Pick.unproductive, __.identity()).option(Pick.unproductive, __.fail()))], + 'g_V_chooseXage_nameX': [(lambda g:g.V().choose(__.values('age'), __.values('name')))], + 'g_V_chooseXageX_optionXbetweenX26_30X_nameX': [(lambda g:g.V().choose(__.values('age')).option(P.between(26, 30), __.values('name')))], + 'g_V_hasLabelXpersonX_chooseXoutXcreatedX_count_isXeqX0XX__constantXdidnt_createX__constantXcreatedXX': [(lambda g:g.V().has_label('person').choose(__.out('created').count().is_(P.eq(0)), __.constant('didnt_create'), __.constant('created')))], + 'g_V_hasLabelXpersonX_chooseXvaluesXageX_isXgtX30XX__valuesXageX__constantX30XX': [(lambda g:g.V().has_label('person').choose(__.values('age').is_(P.gt(30)), __.values('age'), __.constant(30)))], + 'g_V_hasLabelXpersonX_chooseXvaluesXageX_isXgtX29XX_and_valuesXageX_isXltX35XX__valuesXnameX__constantXotherXX': [(lambda g:g.V().has_label('person').choose(__.values('age').is_(P.gt(29)).and_().values('age').is_(P.lt(35)), __.values('name'), __.constant('other')))], + 'g_V_chooseXhasXname_vadasX__valuesXnameX__valuesXageXX': [(lambda g:g.V().choose(__.has('name', 'vadas'), __.values('name'), __.values('age')))], + 'g_V_hasLabelXpersonX_chooseXoutXcreatedX_countX_optionX0__constantXnoneXX_optionX1__constantXoneXX_optionX2__constantXmanyXX': [(lambda g, xx1=None,xx0=None,xx2=None:g.V().has_label('person').choose(__.out('created').count()).option(xx0, __.constant('none')).option(xx1, __.constant('one')).option(xx2, __.constant('many')))], + 'g_V_hasLabelXpersonX_chooseXlocalXoutXknowsX_countX__optionX0__constantXnoFriendsXX__optionXnone__constantXhasFriendsXXX': [(lambda g, xx0=None:g.V().has_label('person').choose(__.local(__.out('knows').count())).option(xx0, __.constant('noFriends')).option(Pick.none, __.constant('hasFriends')))], + 'g_V_chooseXoutE_countX_optionX0__constantXnoneXX_optionXnone__constantXsomeXX': [(lambda g, xx0=None:g.V().choose(__.out_e().count()).option(xx0, __.constant('none')).option(Pick.none, __.constant('some')))], + 'g_V_chooseXlabelX_optionXperson__chooseXageX_optionXP_lt_30__constantXyoungXX_optionXP_gte_30__constantXoldXXX_optionXsoftware__constantXprogramXX_optionXnone__constantXunknownXX': [(lambda g:g.V().choose(__.label()).option('person', __.choose(__.values('age')).option(P.lt(30), __.constant('young')).option(P.gte(30), __.constant('old'))).option('software', __.constant('program')).option(Pick.none, __.constant('unknown')))], + 'g_V_chooseXhasXname_vadasX__valuesXnameXX': [(lambda g:g.V().choose(__.has('name', 'vadas'), __.values('name')))], + 'g_V_hasLabelXpersonX_age_chooseXP_eqX29X__valuesXnameX__constantXotherXX': [(lambda g:g.V().has_label('person').values('age').choose(P.eq(29), __.constant('matched'), __.constant('other')))], + 'g_V_hasLabelXpersonX_age_chooseXP_eqX29X__valuesXnameXX': [(lambda g:g.V().has_label('person').values('age').choose(P.eq(29), __.constant('matched')))], '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..2787f222b5 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 @@ -34,7 +34,7 @@ Feature: Step - choose() | d[29].i | | josh | - Scenario: g_V_chooseXhasLabelXpersonX_and_outXcreatedX__outXknowsX__identityX_name + Scenario: g_V_chooseXhasLabelXpersonX_and_outXcreatedX__outXknowsX_identityX_name Given the modern graph And the traversal of """ @@ -52,6 +52,23 @@ Feature: Step - choose() | vadas | | vadas | + Scenario: g_V_chooseXhasLabelXpersonX_and_outXcreatedX_outXknowsX_name + Given the modern graph + And the traversal of + """ + g.V().choose(__.hasLabel("person").and().out("created"), + __.out("knows")). + values("name") + """ + When iterated to list + Then the result should be unordered + | result | + | lop | + | ripple | + | josh | + | vadas | + | vadas | + Scenario: g_V_chooseXlabelX_optionXblah__outXknowsXX_optionXbleep__outXcreatedXX_optionXnone__identityX_name Given the modern graph And the traversal of @@ -72,6 +89,38 @@ Feature: Step - choose() | lop | | ripple | + Scenario: g_V_chooseXTlabelX_optionXblah__outXknowsXX_optionXbleep__outXcreatedXX_optionXnone__identityX_name + Given the modern graph + And the traversal of + """ + g.V().choose(T.label). + option("blah", __.out("knows")). + option("bleep", __.out("created")). + option(Pick.none, __.identity()). + values("name") + """ + When iterated to list + Then the result should be unordered + | result | + | marko | + | vadas | + | peter | + | josh | + | lop | + | ripple | + + Scenario: g_V_chooseXTlabelX_optionXblah__outXknowsXX_optionXbleep__outXcreatedXX_name + Given the modern graph + And the traversal of + """ + g.V().choose(T.label). + option("blah", __.out("knows")). + option("bleep", __.out("created")). + values("name") + """ + When iterated to list + Then the result should be empty + Scenario: g_V_chooseXoutXknowsX_count_isXgtX0XX__outXknowsXX_name Given the modern graph And the traversal of @@ -152,3 +201,417 @@ Feature: Step - choose() Then the result should be unordered | result | | l[d[2].i] | + + Scenario: g_V_chooseXhasLabelXpersonX_chooseXageX_optionXbetweenX26_30X_constantXxXX_optionXbetweenX20_30X_constantXyXX_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_orXgtX34XX_constantXxXX_optionXgtX34X_constantXyXX_optionXnone_constantXzXX + Given the modern graph + And the traversal of + """ + g.V().hasLabel("person"). + choose(__.values("age")). + option(P.between(26, 30).or(P.gt(34)), __.constant("x")). + option(P.gt(34), __.constant("y")). + option(Pick.none, __.constant("z")) + """ + When iterated to list + Then the result should be unordered + | result | + | x | + | x | + | x | + | z | + + Scenario: g_V_hasLabelXpersonX_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 | + + Scenario: g_V_chooseXhasLabelXpersonX_localXchooseXageX_optionXbetweenX26_30X_name_foldX_optionXnone_name_foldXX + Given the modern graph + And the traversal of + """ + g.V().hasLabel("person"). + local(__.choose(__.values("age")). + option(P.between(26, 30), __.values("name").fold()). + option(Pick.none, __.values("name").fold())) + """ + When iterated to list + Then the result should be unordered + | result | + | l[marko] | + | l[vadas] | + | l[josh] | + | l[peter] | + + Scenario: g_V_chooseXhasLabelXpersonX_mapXchooseXageX_optionXbetweenX26_30X_name_foldX_optionXnone_name_foldXX + Given the modern graph + And the traversal of + """ + g.V().hasLabel("person"). + map(__.choose(__.values("age")). + option(P.between(26, 30), __.values("name").fold()). + option(Pick.none, __.values("name").fold())) + """ + When iterated to list + Then the result should be unordered + | result | + | l[marko] | + | l[vadas] | + | l[josh] | + | l[peter] | + + @GraphComputerVerificationMidVNotSupported + Scenario: g_unionXV_VXhasLabelXpersonX_barrier_localXchooseXageX_optionXbetweenX26_30X_name_foldX_optionXnone_name_foldXX + Given the modern graph + And the traversal of + """ + g.union(__.V(), __.V()).hasLabel("person").barrier(). + local(__.choose(__.values("age")). + option(P.between(26, 30), __.values("name").fold()). + option(Pick.none, __.values("name").fold())) + """ + When iterated to list + Then the result should be unordered + | result | + | l[marko,marko] | + | l[vadas,vadas] | + | l[josh,josh] | + | l[peter,peter] | + + @GraphComputerVerificationMidVNotSupported + Scenario: g_unionXV_VXhasLabelXpersonX_barrier_mapXchooseXageX_optionXbetweenX26_30X_name_foldX_optionXnone_name_foldXX + Given the modern graph + And the traversal of + """ + g.union(__.V(), __.V()).hasLabel("person").barrier(). + map(__.choose(__.values("age")). + option(P.between(26, 30), __.values("name").fold()). + option(Pick.none, __.values("name").fold())) + """ + When iterated to list + Then the result should be unordered + | result | + | l[marko] | + | l[marko] | + | l[vadas] | + | l[vadas] | + | l[josh] | + | l[josh] | + | l[peter] | + | l[peter] | + + Scenario: g_V_chooseXageX_optionXbetweenX26_30X_nameX_optionXnone_nameX + Given the modern graph + And the traversal of + """ + g.V().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 | + | v[lop] | + | josh | + | v[ripple] | + | peter | + + Scenario: g_V_chooseXageX_optionXbetweenX26_30X_nameX_optionXnone_nameX_optionXunproductive_labelX + Given the modern graph + And the traversal of + """ + g.V().choose(__.values("age")). + option(P.between(26, 30), __.values("name")). + option(Pick.none, __.values("name")). + option(Pick.unproductive, __.label()) + """ + When iterated to list + Then the result should be unordered + | result | + | marko | + | vadas | + | software | + | josh | + | software | + | peter | + + Scenario: g_V_chooseXageX_optionXbetweenX26_30X_nameX_optionXnone_nameX_optionXnone_identityX_optionXnone_failX_optionXunproductive_identityX_optionXunproductive_labelX_optionXnone_failX + Given the modern graph + And the traversal of + """ + g.V().choose(__.values("age")). + option(P.between(26, 30), __.values("name")). + option(Pick.none, __.values("name")). + option(Pick.none, __.identity()). + option(Pick.none, __.fail()). + option(Pick.unproductive, __.label()). + option(Pick.unproductive, __.identity()). + option(Pick.unproductive, __.fail()) + """ + When iterated to list + Then the result should be unordered + | result | + | marko | + | vadas | + | software | + | josh | + | software | + | peter | + + Scenario: g_V_chooseXage_nameX + Given the modern graph + And the traversal of + """ + g.V().choose(__.values("age"), __.values("name")) + """ + When iterated to list + Then the result should be unordered + | result | + | marko | + | vadas | + | v[lop] | + | josh | + | v[ripple] | + | peter | + + Scenario: g_V_chooseXageX_optionXbetweenX26_30X_nameX + Given the modern graph + And the traversal of + """ + g.V().choose(__.values("age")). + option(P.between(26, 30), __.values("name")) + """ + When iterated to list + Then the result should be unordered + | result | + | marko | + | vadas | + | v[lop] | + | v[ripple] | + + Scenario: g_V_hasLabelXpersonX_chooseXoutXcreatedX_count_isXeqX0XX__constantXdidnt_createX__constantXcreatedXX + Given the modern graph + And the traversal of + """ + g.V().hasLabel("person"). + choose(__.out("created").count().is(P.eq(0)), + __.constant("didnt_create"), + __.constant("created")) + """ + When iterated to list + Then the result should be unordered + | result | + | didnt_create | + | created | + | created | + | created | + + Scenario: g_V_hasLabelXpersonX_chooseXvaluesXageX_isXgtX30XX__valuesXageX__constantX30XX + Given the modern graph + And the traversal of + """ + g.V().hasLabel("person"). + choose(__.values("age").is(P.gt(30)), + __.values("age"), + __.constant(30)) + """ + When iterated to list + Then the result should be unordered + | result | + | d[30].i | + | d[30].i | + | d[32].i | + | d[35].i | + + Scenario: g_V_hasLabelXpersonX_chooseXvaluesXageX_isXgtX29XX_and_valuesXageX_isXltX35XX__valuesXnameX__constantXotherXX + Given the modern graph + And the traversal of + """ + g.V().hasLabel("person"). + choose(__.values("age").is(P.gt(29)).and().values("age").is(P.lt(35)), + __.values("name"), + __.constant("other")) + """ + When iterated to list + Then the result should be unordered + | result | + | other | + | other | + | josh | + | other | + + Scenario: g_V_chooseXhasXname_vadasX__valuesXnameX__valuesXageXX + Given the modern graph + And the traversal of + """ + g.V().choose(__.has("name", "vadas"), + __.values("name"), + __.values("age")) + """ + When iterated to list + Then the result should be unordered + | result | + | d[29].i | + | vadas | + | d[32].i | + | d[35].i | + + Scenario: g_V_hasLabelXpersonX_chooseXoutXcreatedX_countX_optionX0__constantXnoneXX_optionX1__constantXoneXX_optionX2__constantXmanyXX + Given the modern graph + And using the parameter xx0 defined as "d[0].l" + And using the parameter xx1 defined as "d[1].l" + And using the parameter xx2 defined as "d[2].l" + And the traversal of + """ + g.V().hasLabel("person"). + choose(__.out("created").count()). + option(xx0, __.constant("none")). + option(xx1, __.constant("one")). + option(xx2, __.constant("many")) + """ + When iterated to list + Then the result should be unordered + | result | + | none | + | one | + | many | + | one | + + Scenario: g_V_hasLabelXpersonX_chooseXlocalXoutXknowsX_countX__optionX0__constantXnoFriendsXX__optionXnone__constantXhasFriendsXXX + Given the modern graph + And using the parameter xx0 defined as "d[0].l" + And the traversal of + """ + g.V().hasLabel("person"). + choose(__.local(__.out("knows").count())). + option(xx0, __.constant("noFriends")). + option(Pick.none, __.constant("hasFriends")) + """ + When iterated to list + Then the result should be unordered + | result | + | hasFriends | + | noFriends | + | noFriends | + | noFriends | + + Scenario: g_V_chooseXoutE_countX_optionX0__constantXnoneXX_optionXnone__constantXsomeXX + Given the modern graph + And using the parameter xx0 defined as "d[0].l" + And the traversal of + """ + g.V().choose(__.outE().count()). + option(xx0, __.constant("none")). + option(Pick.none, __.constant("some")) + """ + When iterated to list + Then the result should be unordered + | result | + | some | + | none | + | some | + | some | + | none | + | none | + + Scenario: g_V_chooseXlabelX_optionXperson__chooseXageX_optionXP_lt_30__constantXyoungXX_optionXP_gte_30__constantXoldXXX_optionXsoftware__constantXprogramXX_optionXnone__constantXunknownXX + Given the modern graph + And the traversal of + """ + g.V().choose(__.label()). + option("person", __.choose(__.values("age")). + option(P.lt(30), __.constant("young")). + option(P.gte(30), __.constant("old"))). + option("software", __.constant("program")). + option(Pick.none, __.constant("unknown")) + """ + When iterated to list + Then the result should be unordered + | result | + | young | + | young | + | old | + | old | + | program | + | program | + + Scenario: g_V_chooseXhasXname_vadasX__valuesXnameXX + Given the modern graph + And the traversal of + """ + g.V().choose(__.has("name", "vadas"), + __.values("name")) + """ + When iterated to list + Then the result should be unordered + | result | + | v[marko] | + | vadas | + | v[lop] | + | v[josh] | + | v[ripple] | + | v[peter] | + + Scenario: g_V_hasLabelXpersonX_age_chooseXP_eqX29X__valuesXnameX__constantXotherXX + Given the modern graph + And the traversal of + """ + g.V().hasLabel("person").values("age"). + choose(P.eq(29), + __.constant("matched"), + __.constant("other")) + """ + When iterated to list + Then the result should be unordered + | result | + | matched | + | other | + | other | + | other | + + Scenario: g_V_hasLabelXpersonX_age_chooseXP_eqX29X__valuesXnameXX + Given the modern graph + And the traversal of + """ + g.V().hasLabel("person").values("age"). + choose(P.eq(29), + __.constant("matched")) + """ + When iterated to list + Then the result should be unordered + | result | + | matched | + | d[27].i | + | d[32].i | + | d[35].i | \ No newline at end of file