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 <daniel_kupp...@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