diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/CoreImports.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/CoreImports.java index 8839dcd3ef2..ab66c4365d1 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/CoreImports.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/CoreImports.java @@ -59,6 +59,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.Pop; import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions; import org.apache.tinkerpop.gremlin.process.traversal.Scope; +import org.apache.tinkerpop.gremlin.process.traversal.SearchAlgo; import org.apache.tinkerpop.gremlin.process.traversal.Translator; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; @@ -292,6 +293,7 @@ public final class CoreImports { Collections.addAll(ENUM_IMPORTS, Order.values()); Collections.addAll(ENUM_IMPORTS, Pop.values()); Collections.addAll(ENUM_IMPORTS, Scope.values()); + Collections.addAll(ENUM_IMPORTS, SearchAlgo.values()); Collections.addAll(ENUM_IMPORTS, T.values()); Collections.addAll(ENUM_IMPORTS, TraversalOptionParent.Pick.values()); } diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/SearchAlgo.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/SearchAlgo.java new file mode 100644 index 00000000000..c6b30991bf8 --- /dev/null +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/SearchAlgo.java @@ -0,0 +1,30 @@ +/* + * 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; + +/** + * The repeat step can behave either as a: + * + * {@link SearchAlgo#BFS}: Breadth First Search. This is the Default. + * {@link SearchAlgo#DFS}: Depth First Search + * + */ +public enum SearchAlgo { + BFS, DFS; +} 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 8722886b0fa..a46854437e0 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 @@ -27,6 +27,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.Path; import org.apache.tinkerpop.gremlin.process.traversal.Pop; import org.apache.tinkerpop.gremlin.process.traversal.Scope; +import org.apache.tinkerpop.gremlin.process.traversal.SearchAlgo; import org.apache.tinkerpop.gremlin.process.traversal.Step; import org.apache.tinkerpop.gremlin.process.traversal.Traversal; import org.apache.tinkerpop.gremlin.process.traversal.Traverser; @@ -496,6 +497,19 @@ public default GraphTraversal order(final Scope scope) { return this.asAdmin().addStep(scope.equals(Scope.global) ? new OrderGlobalStep<>(this.asAdmin()) : new OrderLocalStep<>(this.asAdmin())); } + /** + * Order the repeat step by depth first or breadth first + * + * @param algo either DFS or BFS + * + * @see Reference Documentation - Order Step + * @since 3.3.3 + */ + public default GraphTraversal order(final SearchAlgo algo) { + this.asAdmin().getBytecode().addStep(Symbols.order, algo); + return RepeatStep.addSearchAlgo(this, algo); + } + /** * Map the {@link Element} to its associated properties given the provide property keys. * If no property keys are provided, then all properties are emitted. 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 dce5497aa5c..44c7065cad8 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 @@ -22,6 +22,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.Path; import org.apache.tinkerpop.gremlin.process.traversal.Pop; import org.apache.tinkerpop.gremlin.process.traversal.Scope; +import org.apache.tinkerpop.gremlin.process.traversal.SearchAlgo; import org.apache.tinkerpop.gremlin.process.traversal.Traversal; import org.apache.tinkerpop.gremlin.process.traversal.Traverser; import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree; @@ -232,6 +233,13 @@ public static GraphTraversal order(final Scope scope) { return __.start().order(scope); } + /** + * @see GraphTraversal#order(SearchAlgo) + */ + public static GraphTraversal order(final SearchAlgo algo) { + return __.start().order(algo); + } + /** * @see GraphTraversal#properties(String...) */ diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/RepeatStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/RepeatStep.java index bf2c203e850..ec3aad2210e 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/RepeatStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/RepeatStep.java @@ -18,6 +18,7 @@ */ package org.apache.tinkerpop.gremlin.process.traversal.step.branch; +import org.apache.tinkerpop.gremlin.process.traversal.SearchAlgo; import org.apache.tinkerpop.gremlin.process.traversal.Step; import org.apache.tinkerpop.gremlin.process.traversal.Traversal; import org.apache.tinkerpop.gremlin.process.traversal.Traverser; @@ -31,6 +32,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import java.util.NoSuchElementException; import java.util.Set; @@ -43,6 +45,7 @@ public final class RepeatStep extends ComputerAwareStep implements Trav private Traversal.Admin repeatTraversal = null; private Traversal.Admin untilTraversal = null; private Traversal.Admin emitTraversal = null; + private SearchAlgo searchAlgo = SearchAlgo.BFS; public boolean untilFirst = false; public boolean emitFirst = false; @@ -79,6 +82,10 @@ public void setUntilTraversal(final Traversal.Admin untilTraversal) { return this.untilTraversal; } + public void setSearchAlgo(final SearchAlgo s) { + this.searchAlgo = s; + } + public void setEmitTraversal(final Traversal.Admin emitTraversal) { if (null != this.emitTraversal) throw new IllegalStateException("The repeat()-step already has its emit()-modulator declared: " + this); @@ -179,6 +186,20 @@ public int hashCode() { return result; } + private final LinkedList> stashedStarts = new LinkedList<>(); + + private Traverser.Admin nextStart() { + if (this.searchAlgo.equals(SearchAlgo.BFS)) { + return this.starts.next(); + } else { + if (this.starts.hasNext()) { + return this.starts.next(); + } else { + return this.stashedStarts.pop(); + } + } + } + @Override protected Iterator> standardAlgorithm() throws NoSuchElementException { if (null == this.repeatTraversal) @@ -188,7 +209,14 @@ protected Iterator> standardAlgorithm() throws NoSuchElementE if (this.repeatTraversal.getEndStep().hasNext()) { return this.repeatTraversal.getEndStep(); } else { - final Traverser.Admin start = this.starts.next(); + final Traverser.Admin start = nextStart(); + if (this.searchAlgo.equals(SearchAlgo.DFS)) { + final List> localStarts = new ArrayList<>(); + while (this.starts.hasNext()) { + localStarts.add(this.starts.next()); + } + stashedStarts.addAll(0, localStarts); + } if (doUntil(start, true)) { start.resetLoops(); return IteratorUtils.of(start); @@ -241,6 +269,19 @@ public static > C addRepeatToTraversal(final C t return traversal; } + + public static > C addSearchAlgo(final C traversal, final SearchAlgo s) { + final Step step = traversal.asAdmin().getEndStep(); + if (step instanceof RepeatStep) { + ((RepeatStep) step).setSearchAlgo(s); + } else { + final RepeatStep repeatStep = new RepeatStep<>(traversal.asAdmin()); + repeatStep.setSearchAlgo(s); + traversal.asAdmin().addStep(repeatStep); + } + return traversal; + } + public static > C addUntilToTraversal(final C traversal, final Traversal.Admin untilPredicate) { final Step step = traversal.asAdmin().getEndStep(); if (step instanceof RepeatStep && null == ((RepeatStep) step).untilTraversal) { @@ -273,11 +314,37 @@ public RepeatEndStep(final Traversal.Admin traversal) { super(traversal); } + final LinkedList> stashedStarts = new LinkedList<>(); + + private Traverser.Admin nextStart(RepeatStep repeatStep) { + if (repeatStep.searchAlgo.equals(SearchAlgo.BFS)) { + return this.starts.next(); + } else { + if (this.starts.hasNext()) { + return this.starts.next(); + } else { + return this.stashedStarts.pop(); + } + } + } + + @Override + public boolean hasNext() { + return super.hasNext() || this.stashedStarts.peek() != null; + } + @Override protected Iterator> standardAlgorithm() throws NoSuchElementException { final RepeatStep repeatStep = (RepeatStep) this.getTraversal().getParent(); while (true) { - final Traverser.Admin start = this.starts.next(); + final Traverser.Admin start = nextStart(repeatStep); + if (repeatStep.searchAlgo.equals(SearchAlgo.DFS)) { + final List> localStarts = new ArrayList<>(); + while (this.starts.hasNext()) { + localStarts.add(this.starts.next()); + } + stashedStarts.addAll(0, localStarts); + } start.incrLoops(this.getId()); if (repeatStep.doUntil(start, false)) { start.resetLoops(); @@ -320,4 +387,4 @@ protected Iterator> computerAlgorithm() throws NoSuchElementE } } -} \ No newline at end of file +} diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java index 2e795a54aab..66dc2718e88 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java @@ -28,6 +28,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.Pop; import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions; import org.apache.tinkerpop.gremlin.process.traversal.Scope; +import org.apache.tinkerpop.gremlin.process.traversal.SearchAlgo; import org.apache.tinkerpop.gremlin.process.traversal.Traversal; import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy; import org.apache.tinkerpop.gremlin.process.traversal.Traverser; @@ -155,6 +156,7 @@ static final class GraphSONModuleV3d0 extends GraphSONModule { SackFunctions.Barrier.class, TraversalOptionParent.Pick.class, Scope.class, + SearchAlgo.class, T.class).forEach(e -> put(e, e.getSimpleName())); Arrays.asList( ConnectiveStrategy.class, @@ -227,6 +229,7 @@ protected GraphSONModuleV3d0(final boolean normalize) { Pop.class, SackFunctions.Barrier.class, Scope.class, + SearchAlgo.class, TraversalOptionParent.Pick.class, T.class).forEach(e -> addSerializer(e, new TraversalSerializersV3d0.EnumJacksonSerializer())); addSerializer(P.class, new TraversalSerializersV3d0.PJacksonSerializer()); @@ -267,6 +270,7 @@ protected GraphSONModuleV3d0(final boolean normalize) { Pop.values(), SackFunctions.Barrier.values(), Scope.values(), + SearchAlgo.values(), TraversalOptionParent.Pick.values(), T.values()).flatMap(Stream::of).forEach(e -> addDeserializer(e.getClass(), new TraversalSerializersV3d0.EnumJacksonDeserializer(e.getDeclaringClass()))); addDeserializer(P.class, new TraversalSerializersV3d0.PJacksonDeserializer()); @@ -369,6 +373,7 @@ static final class GraphSONModuleV2d0 extends GraphSONModule { SackFunctions.Barrier.class, TraversalOptionParent.Pick.class, Scope.class, + SearchAlgo.class, T.class).forEach(e -> put(e, e.getSimpleName())); Arrays.asList( ConnectiveStrategy.class, @@ -438,6 +443,7 @@ protected GraphSONModuleV2d0(final boolean normalize) { Pop.class, SackFunctions.Barrier.class, Scope.class, + SearchAlgo.class, TraversalOptionParent.Pick.class, T.class).forEach(e -> addSerializer(e, new TraversalSerializersV2d0.EnumJacksonSerializer())); addSerializer(P.class, new TraversalSerializersV2d0.PJacksonSerializer()); @@ -473,6 +479,7 @@ protected GraphSONModuleV2d0(final boolean normalize) { Pop.values(), SackFunctions.Barrier.values(), Scope.values(), + SearchAlgo.values(), TraversalOptionParent.Pick.values(), T.values()).flatMap(Stream::of).forEach(e -> addDeserializer(e.getClass(), new TraversalSerializersV2d0.EnumJacksonDeserializer(e.getDeclaringClass()))); addDeserializer(P.class, new TraversalSerializersV2d0.PJacksonDeserializer()); diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONTypeSerializerV2d0.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONTypeSerializerV2d0.java index 3fdb50a19ae..2fca13296b4 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONTypeSerializerV2d0.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONTypeSerializerV2d0.java @@ -24,6 +24,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.Pop; import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions; import org.apache.tinkerpop.gremlin.process.traversal.Scope; +import org.apache.tinkerpop.gremlin.process.traversal.SearchAlgo; import org.apache.tinkerpop.gremlin.process.traversal.Traverser; import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent; import org.apache.tinkerpop.gremlin.process.traversal.util.Metrics; @@ -135,6 +136,8 @@ else if (TraversalOptionParent.Pick.class.isAssignableFrom(c)) mapped = TraversalOptionParent.Pick.class; else if (Scope.class.isAssignableFrom(c)) mapped = Scope.class; + else if (SearchAlgo.class.isAssignableFrom(c)) + mapped = SearchAlgo.class; else if (T.class.isAssignableFrom(c)) mapped = T.class; else diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONTypeSerializerV3d0.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONTypeSerializerV3d0.java index 3bdbc7128f4..439adfdd68d 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONTypeSerializerV3d0.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONTypeSerializerV3d0.java @@ -24,6 +24,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.Pop; import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions; import org.apache.tinkerpop.gremlin.process.traversal.Scope; +import org.apache.tinkerpop.gremlin.process.traversal.SearchAlgo; import org.apache.tinkerpop.gremlin.process.traversal.Traverser; import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent; import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree; @@ -168,6 +169,8 @@ else if (TraversalOptionParent.Pick.class.isAssignableFrom(c)) mapped = TraversalOptionParent.Pick.class; else if (Scope.class.isAssignableFrom(c)) mapped = Scope.class; + else if (SearchAlgo.class.isAssignableFrom(c)) + mapped = SearchAlgo.class; else if (T.class.isAssignableFrom(c)) mapped = T.class; else diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java index 6bb7b34c566..b59103aa19f 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java @@ -33,6 +33,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.Pop; import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions; import org.apache.tinkerpop.gremlin.process.traversal.Scope; +import org.apache.tinkerpop.gremlin.process.traversal.SearchAlgo; import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent; import org.apache.tinkerpop.gremlin.process.traversal.step.filter.RangeGlobalStep; import org.apache.tinkerpop.gremlin.process.traversal.step.map.FoldStep; @@ -303,6 +304,7 @@ public static List> initV3d0Registrations() { add(GryoTypeReg.of(Bytecode.Binding.class, 126, new GryoSerializersV3d0.BindingSerializer())); add(GryoTypeReg.of(Order.class, 127)); add(GryoTypeReg.of(Scope.class, 128)); + add(GryoTypeReg.of(SearchAlgo.class, 174)); // ***LAST ID*** add(GryoTypeReg.of(VertexProperty.Cardinality.class, 131)); add(GryoTypeReg.of(Column.class, 132)); add(GryoTypeReg.of(Pop.class, 133)); @@ -373,8 +375,7 @@ public static List> initV3d0Registrations() { add(GryoTypeReg.of(RangeGlobalStep.RangeBiOperator.class, 114)); add(GryoTypeReg.of(OrderGlobalStep.OrderBiOperator.class, 118)); add(GryoTypeReg.of(ProfileStep.ProfileBiOperator.class, 119)); - add(GryoTypeReg.of(IndexedTraverserSet.VertexIndexedTraverserSet.class, 173)); // ***LAST ID*** - + add(GryoTypeReg.of(IndexedTraverserSet.VertexIndexedTraverserSet.class, 173)); // placeholder serializers for classes that don't live here in core. this will allow them to be used if // present or ignored if the class isn't available. either way the registration numbers are held as // placeholders so that the format stays stable @@ -479,6 +480,7 @@ public static List> initV1d0Registrations() { add(GryoTypeReg.of(Bytecode.Binding.class, 126, new GryoSerializersV1d0.BindingSerializer())); add(GryoTypeReg.of(Order.class, 127)); add(GryoTypeReg.of(Scope.class, 128)); + add(GryoTypeReg.of(SearchAlgo.class, 174)); // ***LAST ID*** add(GryoTypeReg.of(VertexProperty.Cardinality.class, 131)); add(GryoTypeReg.of(Column.class, 132)); add(GryoTypeReg.of(Pop.class, 133)); @@ -552,7 +554,7 @@ public static List> initV1d0Registrations() { add(GryoTypeReg.of(MatchStep.CountMatchAlgorithm.class, 160)); add(GryoTypeReg.of(MatchStep.GreedyMatchAlgorithm.class, 167)); // skip 171, 172 to sync with tp33 - add(GryoTypeReg.of(IndexedTraverserSet.VertexIndexedTraverserSet.class, 173)); // ***LAST ID*** + add(GryoTypeReg.of(IndexedTraverserSet.VertexIndexedTraverserSet.class, 173)); }}; } diff --git a/gremlin-test/features/branch/Repeat.feature b/gremlin-test/features/branch/Repeat.feature index 61755196947..0fa5c96cc2e 100644 --- a/gremlin-test/features/branch/Repeat.feature +++ b/gremlin-test/features/branch/Repeat.feature @@ -244,3 +244,18 @@ Feature: Step - repeat() | loop | | loop | | loop | + + Scenario: g_V_hasXname_markoX_repeatXoutE_order_byXweight_decrX_inVX_emit_orderXDFSX + Given the modern graph + And the traversal of + """ + g.V().has("name", "marko").repeat(__.outE().order().by("weight", decr).inV()).emit().order(SearchAlgo.DFS) + """ + When iterated to list + Then the result should be ordered + | result | + | josh | + | ripple | + | lop | + | vadas | + | lop | diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/RepeatTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/RepeatTest.java index 6d90687925c..c8056ab7c37 100644 --- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/RepeatTest.java +++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/RepeatTest.java @@ -45,6 +45,8 @@ import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.loops; 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.Order.decr; +import static org.apache.tinkerpop.gremlin.process.traversal.SearchAlgo.DFS; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; import static org.hamcrest.collection.IsIterableContainingInOrder.contains; @@ -98,6 +100,8 @@ public abstract class RepeatTest extends AbstractGremlinProcessTest { public abstract Traversal get_g_V_hasXname_markoX_repeatXoutE_inV_simplePathX_untilXhasXname_rippleXX_path_byXnameX_byXlabelX(); + public abstract Traversal get_g_V_hasXname_markoX_repeatXoutE_order_byXweight_decrX_inVX_emit_orderXDFSX(); + @Test @LoadGraphWith(MODERN) public void g_V_repeatXoutX_timesX2X_emit_path() { @@ -310,6 +314,18 @@ public void g_V_hasXname_markoX_repeatXoutE_inV_simplePathX_untilXhasXname_rippl assertEquals("ripple", path.get(4)); } + @Test + @LoadGraphWith(MODERN) + public void g_V_hasXname_markoX_repeatXoutE_order_byXweight_decrX_inVX_emit_orderXDFSX() { + final List vertices = get_g_V_hasXname_markoX_repeatXoutE_order_byXweight_decrX_inVX_emit_orderXDFSX().toList(); + assertEquals(5, vertices.size()); + assertEquals("josh", vertices.get(0).values("name").next()); + assertEquals("ripple", vertices.get(1).values("name").next()); + assertEquals("lop", vertices.get(2).values("name").next()); + assertEquals("vadas", vertices.get(3).values("name").next()); + assertEquals("lop", vertices.get(4).values("name").next()); + } + public static class Traversals extends RepeatTest { @Override @@ -386,5 +402,10 @@ public Traversal get_g_V_hasXname_markoX_repeatXoutE_inV_simplePat public Traversal get_g_V_hasXloop_name_loopX_repeatXinX_timesX5X_path_by_name() { return g.V().has("loops","name","loop").repeat(__.in()).times(5).path().by("name"); } + + @Override + public Traversal get_g_V_hasXname_markoX_repeatXoutE_order_byXweight_decrX_inVX_emit_orderXDFSX() { + return g.V().has("name", "marko").repeat(__.outE().order().by("weight", decr).inV()).emit().order(DFS); + } } }