You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by dk...@apache.org on 2019/06/12 17:12:47 UTC

[tinkerpop] branch TINKERPOP-1084 updated (277e34c -> 7d202f7)

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

dkuppitz pushed a change to branch TINKERPOP-1084
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git.


 discard 277e34c  TINKERPOP-1084 Allow predicates and traversals to be used as options in `BranchStep`.
     new 7d202f7  TINKERPOP-1084 Allow predicates and traversals to be used as options in `BranchStep`.

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (277e34c)
            \
             N -- N -- N   refs/heads/TINKERPOP-1084 (7d202f7)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../process/traversal/lambda/PredicateTraversal.java   |  2 +-
 .../gremlin/process/traversal/step/ComplexTest.java    | 18 +++++++++++++++---
 2 files changed, 16 insertions(+), 4 deletions(-)


[tinkerpop] 01/01: TINKERPOP-1084 Allow predicates and traversals to be used as options in `BranchStep`.

Posted by dk...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 7d202f733a55d245f9c092de8a2fcc910b457f5e
Author: Daniel Kuppitz <da...@hotmail.com>
AuthorDate: Tue Jun 11 07:46:51 2019 -0700

    TINKERPOP-1084 Allow predicates and traversals to be used as options in `BranchStep`.
---
 CHANGELOG.asciidoc                                 |   2 +-
 .../traversal/lambda/PredicateTraversal.java       |  68 +++++++++
 .../process/traversal/step/branch/BranchStep.java  | 163 +++++++--------------
 .../process/traversal/step/branch/ChooseStep.java  |  10 +-
 .../process/traversal/step/branch/UnionStep.java   |   2 +-
 .../process/traversal/step/ComplexTest.java        |  22 ++-
 .../tinkergraph/structure/TinkerGraphPlayTest.java |   8 +-
 7 files changed, 151 insertions(+), 124 deletions(-)

diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 320930e..3c4021d 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -31,7 +31,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 * Fixed multiple iterator leaks in query processor.
 * Fixed bug in `MatchStep` where the correct was not properly determined.
 * Fixed bug where client/server exception mismatch when server throw StackOverflowError
-* Allow predicates to be used as options in BranchSteps.
+* Allow predicates and traversals to be used as options in `BranchStep`.
 
 [[release-3-3-7]]
 === TinkerPop 3.3.7 (Release Date: May 28, 2019)
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
new file mode 100644
index 0000000..603ac50
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/PredicateTraversal.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.process.traversal.lambda;
+
+import org.apache.tinkerpop.gremlin.process.traversal.P;
+import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
+import org.apache.tinkerpop.gremlin.process.traversal.util.FastNoSuchElementException;
+
+import java.util.function.Predicate;
+
+/**
+ * @author Daniel Kuppitz (http://gremlin.guru)
+ */
+public final class PredicateTraversal<S> extends AbstractLambdaTraversal<S, S> {
+
+    private final Predicate predicate;
+    private S s;
+    private boolean pass;
+
+    public PredicateTraversal(final Object value) {
+        this.predicate = value instanceof Predicate ? (Predicate) value : P.eq(value);
+    }
+
+    @Override
+    public S next() {
+        if (this.pass)
+            return this.s;
+        throw FastNoSuchElementException.instance();
+    }
+
+    @Override
+    public boolean hasNext() {
+        return this.pass;
+    }
+
+    @Override
+    public void addStart(final Traverser.Admin<S> start) {
+        //noinspection unchecked
+        this.pass = this.predicate.test(this.s = start.get());
+    }
+
+    @Override
+    public String toString() {
+        return "(" + this.predicate.toString() + ")";
+    }
+
+    @Override
+    public int hashCode() {
+        return this.getClass().hashCode() ^ this.predicate.hashCode();
+    }
+}
+
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 efc43cc..d92ce2d 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
@@ -18,8 +18,10 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.step.branch;
 
+import org.apache.tinkerpop.gremlin.process.traversal.P;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
+import org.apache.tinkerpop.gremlin.process.traversal.lambda.PredicateTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.step.Barrier;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent;
 import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.IdentityStep;
@@ -30,7 +32,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.util.FastNoSuchElementExce
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
-import org.apache.tinkerpop.gremlin.util.NumberHelper;
+import org.javatuples.Pair;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -38,10 +40,10 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Objects;
 import java.util.Set;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
@@ -50,11 +52,11 @@ import java.util.stream.Collectors;
 public class BranchStep<S, E, M> extends ComputerAwareStep<S, E> implements TraversalOptionParent<M, S, E> {
 
     protected Traversal.Admin<S, M> branchTraversal;
-    protected Map<Object, List<Traversal.Admin<S, E>>> traversalOptions = new HashMap<>();
+    protected Map<Pick, List<Traversal.Admin<S, E>>> traversalPickOptions = new HashMap<>();
+    protected List<Pair<Traversal.Admin, Traversal.Admin<S, E>>> traversalOptions = new ArrayList<>();
 
     private boolean first = true;
     private boolean hasBarrier;
-    private boolean hasPredicateOptions;
 
     public BranchStep(final Traversal.Admin traversal) {
         super(traversal);
@@ -66,13 +68,20 @@ public class BranchStep<S, E, M> extends ComputerAwareStep<S, E> implements Trav
 
     @Override
     public void addGlobalChildOption(final M pickToken, final Traversal.Admin<S, E> traversalOption) {
-        final Object pickTokenKey = makePickTokenKey(pickToken);
-        this.hasPredicateOptions |= pickTokenKey instanceof PredicateOption;
-        if (this.traversalOptions.containsKey(pickTokenKey))
-            this.traversalOptions.get(pickTokenKey).add(traversalOption);
-        else
-            this.traversalOptions.put(pickTokenKey, new ArrayList<>(Collections.singletonList(traversalOption)));
-
+        if (pickToken instanceof Pick) {
+            if (this.traversalPickOptions.containsKey(pickToken))
+                this.traversalPickOptions.get(pickToken).add(traversalOption);
+            else
+                this.traversalPickOptions.put((Pick) pickToken, new ArrayList<>(Collections.singletonList(traversalOption)));
+        } else {
+            final Traversal.Admin pickOptionTraversal;
+            if (pickToken instanceof Traversal) {
+                pickOptionTraversal = ((Traversal) pickToken).asAdmin();
+            } else {
+                pickOptionTraversal = new PredicateTraversal(pickToken);
+            }
+            this.traversalOptions.add(Pair.with(pickOptionTraversal, traversalOption));
+        }
         // adding an IdentityStep acts as a placeholder when reducing barriers get in the way - see the
         // standardAlgorithm() method for more information.
         if (TraversalHelper.hasStepOfAssignableClass(ReducingBarrierStep.class, traversalOption))
@@ -91,9 +100,9 @@ public class BranchStep<S, E, M> extends ComputerAwareStep<S, E> implements Trav
 
     @Override
     public List<Traversal.Admin<S, E>> getGlobalChildren() {
-        return Collections.unmodifiableList(this.traversalOptions.values().stream()
-                .flatMap(List::stream)
-                .collect(Collectors.toList()));
+        return Collections.unmodifiableList(Stream.concat(
+                this.traversalPickOptions.values().stream().flatMap(List::stream),
+                this.traversalOptions.stream().map(Pair::getValue1)).collect(Collectors.toList()));
     }
 
     @Override
@@ -113,11 +122,9 @@ public class BranchStep<S, E, M> extends ComputerAwareStep<S, E> implements Trav
                 // traverser as part of the condition for using that traversal option in the output. This is necessary
                 // because barriers like fold(), max(), etc. will always return true for hasNext() even if a traverser
                 // was not seeded in applyCurrentTraverser().
-                for (final List<Traversal.Admin<S, E>> options : this.traversalOptions.values()) {
-                    for (final Traversal.Admin<S, E> option : options) {
-                        if (option.getStartStep().hasNext() && option.hasNext())
-                            return option.getEndStep();
-                    }
+                for (final Traversal.Admin<S, E> option : getGlobalChildren()) {
+                    if (option.getStartStep().hasNext() && option.hasNext())
+                        return option.getEndStep();
                 }
             }
 
@@ -144,7 +151,7 @@ public class BranchStep<S, E, M> extends ComputerAwareStep<S, E> implements Trav
     private 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 Object choice = makePickTokenKey(TraversalUtil.apply(start, this.branchTraversal));
+        final Object choice = TraversalUtil.apply(start, this.branchTraversal);
         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
@@ -153,7 +160,7 @@ public class BranchStep<S, E, M> extends ComputerAwareStep<S, E> implements Trav
             branches.forEach(traversal -> traversal.addStart(start.split()));
 
         if (choice != Pick.any) {
-            final List<Traversal.Admin<S, E>> anyBranch = this.traversalOptions.get(Pick.any);
+            final List<Traversal.Admin<S, E>> anyBranch = this.traversalPickOptions.get(Pick.any);
             if (null != anyBranch)
                 anyBranch.forEach(traversal -> traversal.addStart(start.split()));
         }
@@ -163,7 +170,7 @@ 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 Object choice = makePickTokenKey(TraversalUtil.apply(start, this.branchTraversal));
+        final Object choice = TraversalUtil.apply(start, this.branchTraversal);
         final List<Traversal.Admin<S, E>> branches = pickBranches(choice);
         if (null != branches) {
             branches.forEach(traversal -> {
@@ -174,7 +181,7 @@ public class BranchStep<S, E, M> extends ComputerAwareStep<S, E> implements Trav
             });
         }
         if (choice != Pick.any) {
-            final List<Traversal.Admin<S, E>> anyBranch = this.traversalOptions.get(Pick.any);
+            final List<Traversal.Admin<S, E>> anyBranch = this.traversalPickOptions.get(Pick.any);
             if (null != anyBranch) {
                 anyBranch.forEach(traversal -> {
                     final Traverser.Admin<E> split = (Traverser.Admin<E>) start.split();
@@ -189,34 +196,37 @@ public class BranchStep<S, E, M> extends ComputerAwareStep<S, E> implements Trav
 
     private List<Traversal.Admin<S, E>> pickBranches(final Object choice) {
         final List<Traversal.Admin<S, E>> branches = new ArrayList<>();
-        if (this.hasPredicateOptions) {
-            for (final Map.Entry<Object, List<Traversal.Admin<S, E>>> e : this.traversalOptions.entrySet()) {
-                if (Objects.equals(e.getKey(), choice)) {
-                    branches.addAll(e.getValue());
-                }
+        if (choice instanceof Pick) {
+            if (this.traversalPickOptions.containsKey(choice)) {
+                branches.addAll(this.traversalPickOptions.get(choice));
             }
-        } else {
-            if (this.traversalOptions.containsKey(choice)) {
-                branches.addAll(this.traversalOptions.get(choice));
+        }
+        for (final Pair<Traversal.Admin, Traversal.Admin<S, E>> p : this.traversalOptions) {
+            if (TraversalUtil.test(choice, p.getValue0())) {
+                branches.add(p.getValue1());
             }
         }
-        return branches.isEmpty() ? this.traversalOptions.get(Pick.none) : branches;
+        return branches.isEmpty() ? this.traversalPickOptions.get(Pick.none) : branches;
     }
 
     @Override
     public BranchStep<S, E, M> clone() {
         final BranchStep<S, E, M> clone = (BranchStep<S, E, M>) super.clone();
-        clone.traversalOptions = new HashMap<>(this.traversalOptions.size());
-        for (final Map.Entry<Object, List<Traversal.Admin<S, E>>> entry : this.traversalOptions.entrySet()) {
+        clone.traversalPickOptions = new HashMap<>(this.traversalPickOptions.size());
+        clone.traversalOptions = new ArrayList<>(this.traversalOptions.size());
+        for (final Map.Entry<Pick, List<Traversal.Admin<S, E>>> entry : this.traversalPickOptions.entrySet()) {
             final List<Traversal.Admin<S, E>> traversals = entry.getValue();
             if (traversals.size() > 0) {
-                final List<Traversal.Admin<S, E>> clonedTraversals = clone.traversalOptions.compute(entry.getKey(), (k, v) ->
+                final List<Traversal.Admin<S, E>> clonedTraversals = clone.traversalPickOptions.compute(entry.getKey(), (k, v) ->
                         (v == null) ? new ArrayList<>(traversals.size()) : v);
                 for (final Traversal.Admin<S, E> traversal : traversals) {
                     clonedTraversals.add(traversal.clone());
                 }
             }
         }
+        for (final Pair<Traversal.Admin, Traversal.Admin<S, E>> pair : this.traversalOptions) {
+            clone.traversalOptions.add(Pair.with(pair.getValue0().clone(), pair.getValue1().clone()));
+        }
         clone.branchTraversal = this.branchTraversal.clone();
         return clone;
     }
@@ -225,12 +235,14 @@ public class BranchStep<S, E, M> extends ComputerAwareStep<S, E> implements Trav
     public void setTraversal(final Traversal.Admin<?, ?> parentTraversal) {
         super.setTraversal(parentTraversal);
         this.integrateChild(this.branchTraversal);
-        this.traversalOptions.values().stream().flatMap(List::stream).forEach(this::integrateChild);
+        this.getGlobalChildren().forEach(this::integrateChild);
     }
 
     @Override
     public int hashCode() {
         int result = super.hashCode();
+        if (this.traversalPickOptions != null)
+            result ^= this.traversalPickOptions.hashCode();
         if (this.traversalOptions != null)
             result ^= this.traversalOptions.hashCode();
         if (this.branchTraversal != null)
@@ -240,7 +252,10 @@ public class BranchStep<S, E, M> extends ComputerAwareStep<S, E> implements Trav
 
     @Override
     public String toString() {
-        return StringFactory.stepString(this, this.branchTraversal, this.traversalOptions);
+        final List<Pair> combinedOptions = Stream.concat(
+                this.traversalPickOptions.entrySet().stream().map(e -> Pair.with(e.getKey(), e.getValue())),
+                this.traversalOptions.stream()).collect(Collectors.toList());
+        return StringFactory.stepString(this, this.branchTraversal, combinedOptions);
     }
 
     @Override
@@ -249,78 +264,4 @@ public class BranchStep<S, E, M> extends ComputerAwareStep<S, E> implements Trav
         this.getGlobalChildren().forEach(Traversal.Admin::reset);
         this.first = true;
     }
-
-    /**
-     * Converts numbers into {@link NumberOption} and predicates into {@link PredicateOption}.
-     */
-    private static Object makePickTokenKey(final Object o) {
-        return
-                o instanceof Number ? new NumberOption((Number) o) :
-                o instanceof Predicate ? new PredicateOption((Predicate) o) : o;
-    }
-
-    /**
-     * Wraps a single number and overrides equals/hashCode/compareTo in order to ignore the numeric data type.
-     */
-    private static class NumberOption implements Comparable<Number> {
-
-        final Number number;
-
-        NumberOption(final Number number) {
-            this.number = number;
-        }
-
-        @Override
-        public boolean equals(final Object o) {
-            if (this == o) return true;
-            if (o == null || getClass() != o.getClass()) return false;
-            final NumberOption other = (NumberOption) o;
-            return 0 == NumberHelper.compare(number, other.number);
-        }
-
-        @Override
-        public int hashCode() {
-            return number.hashCode();
-        }
-
-        @Override
-        public String toString() {
-            return number.toString();
-        }
-
-        @Override
-        public int compareTo(final Number other) {
-            return NumberHelper.compare(this.number, other);
-        }
-    }
-
-    /**
-     * Wraps a single predicate and overrides equals/hashCode so that the predicate can be matched against a concrete value.
-     */
-    private static class PredicateOption {
-
-        final Predicate predicate;
-
-        PredicateOption(final Predicate predicate) {
-            this.predicate = predicate;
-        }
-
-        @SuppressWarnings({"EqualsWhichDoesntCheckParameterClass", "unchecked"})
-        @Override
-        public boolean equals(final Object o) {
-            if (o instanceof PredicateOption)
-                return ((PredicateOption) o).predicate.equals(predicate);
-            return predicate.test(o);
-        }
-
-        @Override
-        public int hashCode() {
-            return 0;
-        }
-
-        @Override
-        public String toString() {
-            return predicate.toString();
-        }
-    }
 }
\ No newline at end of file
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 e699f22..a804d8f 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
@@ -42,10 +42,12 @@ public final class ChooseStep<S, E, M> extends BranchStep<S, E, M> {
 
     @Override
     public void addGlobalChildOption(final M pickToken, final Traversal.Admin<S, E> traversalOption) {
-        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.traversalOptions.containsKey(pickToken))
-            throw new IllegalArgumentException("Choose step can only have one traversal per pick token: " + pickToken);
+        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);
+        }
         super.addGlobalChildOption(pickToken, traversalOption);
     }
 }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/UnionStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/UnionStep.java
index 85f3645..de70479 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/UnionStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/UnionStep.java
@@ -47,6 +47,6 @@ public final class UnionStep<S, E> extends BranchStep<S, E, TraversalOptionParen
 
     @Override
     public String toString() {
-        return StringFactory.stepString(this, this.traversalOptions.getOrDefault(Pick.any, Collections.emptyList()));
+        return StringFactory.stepString(this, this.traversalPickOptions.getOrDefault(Pick.any, Collections.emptyList()));
     }
 }
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/ComplexTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/ComplexTest.java
index a3bb1cd..0110d44 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/ComplexTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/ComplexTest.java
@@ -51,7 +51,19 @@ import static org.apache.tinkerpop.gremlin.process.traversal.Pop.all;
 import static org.apache.tinkerpop.gremlin.process.traversal.Pop.first;
 import static org.apache.tinkerpop.gremlin.process.traversal.Pop.last;
 import static org.apache.tinkerpop.gremlin.process.traversal.Scope.local;
-import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.*;
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.both;
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.branch;
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.constant;
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.count;
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.group;
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.in;
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.out;
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.outE;
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.project;
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.select;
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.unfold;
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.values;
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.where;
 import static org.apache.tinkerpop.gremlin.structure.Column.keys;
 import static org.apache.tinkerpop.gremlin.structure.Column.values;
 import static org.junit.Assert.assertEquals;
@@ -252,9 +264,10 @@ public abstract class ComplexTest extends AbstractGremlinProcessTest {
         assertTrue(map.get("vadas").contains("pretty young"));
         assertTrue(map.get("vadas").contains("younger than peter"));
         assertTrue(map.containsKey("josh"));
-        assertEquals(2, map.get("josh").size());
+        assertEquals(3, map.get("josh").size());
         assertTrue(map.get("josh").contains("younger than peter"));
         assertTrue(map.get("josh").contains("pretty old"));
+        assertTrue(map.get("josh").contains("looks like josh"));
         assertTrue(map.containsKey("peter"));
         assertEquals(1, map.get("peter").size());
         assertTrue(map.get("peter").contains("pretty old"));
@@ -282,7 +295,7 @@ public abstract class ComplexTest extends AbstractGremlinProcessTest {
         public Traversal<Vertex, Map<String, Map<String, Map<String, Object>>>> getCoworkerSummary() {
             return g.V().hasLabel("person").filter(outE("created")).aggregate("p").as("p1").values("name").as("p1n")
                     .select("p").unfold().where(neq("p1")).as("p2").values("name").as("p2n").select("p2")
-                    .out("created").choose(in("created").where(eq("p1")), __.values("name"), constant(emptyList()))
+                    .out("created").choose(in("created").where(eq("p1")), values("name"), constant(emptyList()))
                     .<String, Map<String, Map<String, Object>>>group().by(select("p1n")).
                             by(group().by(select("p2n")).
                                     by(unfold().fold().project("numCoCreated", "coCreated").by(count(local)).by()));
@@ -346,8 +359,9 @@ public abstract class ComplexTest extends AbstractGremlinProcessTest {
             return g.V().hasLabel("person")
                     .<String, List<String>> group()
                         .by("name")
-                        .by(branch(__.values("age"))
+                        .by(branch(values("age"))
                                 .option(29, constant("almost old"))
+                                .option(__.is(32), constant("looks like josh"))
                                 .option(lt(29), constant("pretty young"))
                                 .option(lt(35), constant("younger than peter"))
                                 .option(gte(30), constant("pretty old")).fold());
diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphPlayTest.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphPlayTest.java
index 3b241bc..3216803 100644
--- a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphPlayTest.java
+++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphPlayTest.java
@@ -130,16 +130,18 @@ public class TinkerGraphPlayTest {
     public void testPlayDK() throws Exception {
 
         GraphTraversalSource g = TinkerFactory.createModern().traversal();
-        g./*withComputer().*/V().hasLabel("person")
+        System.out.println(g./*withComputer().*/V().hasLabel("person")
                 .project("name", "age", "comments")
                     .by("name")
                     .by("age")
                     .by(branch(values("age"))
+                            .option(TraversalOptionParent.Pick.any, constant("foo"))
                             .option(29, constant("almost old"))
+                            .option(__.is(32), constant("looks like josh"))
                             .option(lt(29), constant("pretty young"))
                             .option(lt(35), constant("younger than peter"))
-                            .option(gte(30), constant("pretty old")).fold())
-                .forEachRemaining(System.out::println);
+                            .option(gte(30), constant("pretty old")).fold()).explain());
+                //.forEachRemaining(System.out::println);
     }
 
     @Test