This is an automated email from the ASF dual-hosted git repository. spmallette pushed a commit to branch TINKERPOP-2235 in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit 4ef74c3aa17bac2b18006ee3144e16eee833fb9c Author: stephen <[email protected]> AuthorDate: Tue Nov 19 13:20:15 2019 -0500 TINKERPOP-2235 Major refactoring and introduction of ScalarMapStep ScalarMapStep extends and replaces MapStep as the "easy" way to implement a new MapStep. ScalarMapStep works nicely when you don't have to fuss with null logic and is still appropriate for use in those cases where a step will not produce a null value (e.g. addV()). For all other cases, you basically have to extend MapStep directly and implement processNextStart() by hand. --- CHANGELOG.asciidoc | 1 + docs/src/upgrade/release-3.5.x.asciidoc | 40 ++++++++++++++++ .../traversal/step/filter/WhereTraversalStep.java | 4 +- .../process/traversal/step/map/AddEdgeStep.java | 2 +- .../process/traversal/step/map/AddVertexStep.java | 2 +- .../process/traversal/step/map/ConstantStep.java | 2 +- .../process/traversal/step/map/CountLocalStep.java | 2 +- .../process/traversal/step/map/DedupLocalStep.java | 2 +- .../traversal/step/map/EdgeOtherVertexStep.java | 2 +- .../process/traversal/step/map/ElementMapStep.java | 2 +- .../gremlin/process/traversal/step/map/IdStep.java | 2 +- .../process/traversal/step/map/IndexStep.java | 2 +- .../process/traversal/step/map/LabelStep.java | 2 +- .../process/traversal/step/map/LambdaMapStep.java | 2 +- .../process/traversal/step/map/LoopsStep.java | 2 +- .../process/traversal/step/map/MapStep.java | 27 ++--------- .../process/traversal/step/map/MathStep.java | 2 +- .../process/traversal/step/map/MaxLocalStep.java | 2 +- .../process/traversal/step/map/MeanLocalStep.java | 2 +- .../process/traversal/step/map/MinLocalStep.java | 2 +- .../process/traversal/step/map/OrderLocalStep.java | 2 +- .../process/traversal/step/map/PathStep.java | 2 +- .../process/traversal/step/map/ProjectStep.java | 2 +- .../traversal/step/map/PropertyKeyStep.java | 2 +- .../traversal/step/map/PropertyMapStep.java | 2 +- .../traversal/step/map/PropertyValueStep.java | 2 +- .../process/traversal/step/map/RangeLocalStep.java | 2 +- .../process/traversal/step/map/SackStep.java | 2 +- .../traversal/step/map/SampleLocalStep.java | 2 +- .../{PropertyKeyStep.java => ScalarMapStep.java} | 25 +++++----- .../process/traversal/step/map/SelectOneStep.java | 54 +++++++++++++++------- .../process/traversal/step/map/SelectStep.java | 20 +++----- .../process/traversal/step/map/SumLocalStep.java | 2 +- .../process/traversal/step/map/TailLocalStep.java | 2 +- .../traversal/step/map/TraversalMapStep.java | 12 ++--- .../traversal/step/map/TraversalSelectStep.java | 41 ++++++++-------- .../finalization/ReferenceElementStrategy.java | 4 +- gremlin-test/features/map/Map.feature | 16 +++++++ .../process/traversal/step/map/MapTest.java | 22 +++++++++ .../strategy/decoration/OptionsStrategyTest.java | 4 +- 40 files changed, 198 insertions(+), 126 deletions(-) diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index 58dc701..b88d717 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -27,6 +27,7 @@ This release also includes changes from <<release-3-4-3, 3.4.3>>. * Allowed the possibility for the user of `null` in Gremlin. * Added a `Graph.Feature` for `supportsNullPropertyValues`. +* Refactored `MapStep` to move its logic to `ScalarMapStep` so that the old behavior could be preserved while allow other implementations to have more flexibility. * Modified TinkerGraph to support `null` property values and can be configured to disable that feature. * Modified `null` handling in mutations to be consistent for a new `Vertex` as well as update to an existing one. * Upgraded to Apache Commons Configuration2. diff --git a/docs/src/upgrade/release-3.5.x.asciidoc b/docs/src/upgrade/release-3.5.x.asciidoc index f0739e5..cdd920b 100644 --- a/docs/src/upgrade/release-3.5.x.asciidoc +++ b/docs/src/upgrade/release-3.5.x.asciidoc @@ -257,6 +257,46 @@ link:http://tinkerpop.apache.org/docs/3.5.0/upgrade/#_ssl_security[3.2.10 Upgrad ==== Graph System Providers +===== ScalarMapStep + +`MapStep` had a single abstract method that needed to be implemented: + +[source,java] +---- +protected abstract E map(final Traverser.Admin<S> traverser); +---- + +This method made it easy to implement new implementations because it hid certain processing logic and made it so that +the implementer only had to reason about how to take the current object from the `Traverser` and transform it to a +new value. As 3.5.0 changed semantics around how `null` is processed, this method became a bit of a hindrance to the +more complex logic which those semantics entailed. Specifically, this method could not easily communicate to underlying +processing what a `null` might mean - is the `null` the end of the traversal stream or should the `null` be promoted +down the stream as a value to be processed. + +Interestingly, the method that enabled the handling of this more complex decision making already existed in +`AbstractStep`: + +[source,java] +---- +protected Traverser.Admin<E> processNextStart() +---- + +It returns a whole `Traverser` object and forces manual retrieval of the "next" `Traverser`. At this level it becomes +possible to make choices on `null` and return it if it should be propagated or dismiss it and return an +`EmptyTraverser`. To better accommodate the `MapStep` which provides the nice helper `map(Traverser)` method as well +as the more flexible version that doesn't need that infrastructure, `ScalarMapStep` was added to extend `MapStep`. The +`map(Traverser)` was then moved to `ScalarMapStep` and those steps that could rely on that helper method now extend +from it. All other steps of this sort still extend `MapStep` and directly implement `processNextStart()`. + +Providers will get compile errors if they extended `MapStep`. The easy solution will be to simply modify that code so +that their step instead extends `ScalarMapStep`. As a secondary task, providers should then examine their step +implementation to ensure that `null` semantics as presented in 3.5.0 apply properly. If they do not, then it is likely +that the step should simply implement `MapStep` directly and former `map(Traverser)` logic should be migrated to +`processNextStart()`. + +See: link:https://issues.apache.org/jira/browse/TINKERPOP-2235[TINKERPOP-2235], +link:https://issues.apache.org/jira/browse/TINKERPOP-2099[TINKERPOP-2099] + ===== TraversalStrategy Application The methodology for strategy application has been altered and the change is most easily described by example. Given a diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WhereTraversalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WhereTraversalStep.java index 384bbce..8c701a9 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WhereTraversalStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WhereTraversalStep.java @@ -25,7 +25,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.Traverser; import org.apache.tinkerpop.gremlin.process.traversal.step.PathProcessor; import org.apache.tinkerpop.gremlin.process.traversal.step.Scoping; import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent; -import org.apache.tinkerpop.gremlin.process.traversal.step.map.MapStep; +import org.apache.tinkerpop.gremlin.process.traversal.step.map.ScalarMapStep; import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.StartStep; import org.apache.tinkerpop.gremlin.process.traversal.step.util.ProfileStep; import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.ConnectiveStrategy; @@ -149,7 +149,7 @@ public final class WhereTraversalStep<S> extends FilterStep<S> implements Traver ////////////////////////////// - public static class WhereStartStep<S> extends MapStep<S, Object> implements Scoping { + public static class WhereStartStep<S> extends ScalarMapStep<S, Object> implements Scoping { private String selectKey; diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStep.java index aa3818b..b8d7d35 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStep.java @@ -45,7 +45,7 @@ import java.util.Set; * @author Marko A. Rodriguez (http://markorodriguez.com) * @author Stephen Mallette (http://stephen.genoprime.com) */ -public class AddEdgeStep<S> extends MapStep<S, Edge> +public class AddEdgeStep<S> extends ScalarMapStep<S, Edge> implements Mutating<Event.EdgeAddedEvent>, TraversalParent, Scoping, FromToModulating { private static final String FROM = Graph.Hidden.hide("from"); diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStep.java index 4961025..296e8b5 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStep.java @@ -40,7 +40,7 @@ import java.util.Set; * @author Marko A. Rodriguez (http://markorodriguez.com) * @author Stephen Mallette (http://stephen.genoprime.com) */ -public class AddVertexStep<S> extends MapStep<S, Vertex> +public class AddVertexStep<S> extends ScalarMapStep<S, Vertex> implements Mutating<Event.VertexAddedEvent>, TraversalParent, Scoping { private Parameters parameters = new Parameters(); diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConstantStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConstantStep.java index 749de31..9434cc3 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConstantStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConstantStep.java @@ -27,7 +27,7 @@ import java.util.Collections; import java.util.Objects; import java.util.Set; -public class ConstantStep<S, E> extends MapStep<S, E> { +public class ConstantStep<S, E> extends ScalarMapStep<S, E> { private final E constant; diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/CountLocalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/CountLocalStep.java index 87b699d..25e75e4 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/CountLocalStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/CountLocalStep.java @@ -32,7 +32,7 @@ import java.util.Set; * @author Marko A. Rodriguez (http://markorodriguez.com) * @author Daniel Kuppitz (http://gremlin.guru) */ -public final class CountLocalStep<S> extends MapStep<S, Long> { +public final class CountLocalStep<S> extends ScalarMapStep<S, Long> { public CountLocalStep(final Traversal.Admin traversal) { super(traversal); diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DedupLocalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DedupLocalStep.java index 59c66c7..4d75270 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DedupLocalStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DedupLocalStep.java @@ -29,7 +29,7 @@ import java.util.Set; /** * @author Daniel Kuppitz (http://gremlin.guru) */ -public final class DedupLocalStep<E, S extends Iterable<E>> extends MapStep<S, Set<E>> { +public final class DedupLocalStep<E, S extends Iterable<E>> extends ScalarMapStep<S, Set<E>> { public DedupLocalStep(final Traversal.Admin traversal) { super(traversal); diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/EdgeOtherVertexStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/EdgeOtherVertexStep.java index a53dd50..0d151d0 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/EdgeOtherVertexStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/EdgeOtherVertexStep.java @@ -34,7 +34,7 @@ import java.util.Set; /** * @author Marko A. Rodriguez (http://markorodriguez.com) */ -public class EdgeOtherVertexStep extends MapStep<Edge, Vertex> implements Configuring { +public class EdgeOtherVertexStep extends ScalarMapStep<Edge, Vertex> implements Configuring { protected Parameters parameters = new Parameters(); public EdgeOtherVertexStep(final Traversal.Admin traversal) { diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ElementMapStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ElementMapStep.java index 2f1db43..1654aa1 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ElementMapStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ElementMapStep.java @@ -45,7 +45,7 @@ import java.util.Set; * @author Daniel Kuppitz (http://gremlin.guru) * @author Stephen Mallette (http://stephen.genoprime.com) */ -public class ElementMapStep<K,E> extends MapStep<Element, Map<K, E>> implements TraversalParent, GraphComputing { +public class ElementMapStep<K,E> extends ScalarMapStep<Element, Map<K, E>> implements TraversalParent, GraphComputing { protected final String[] propertyKeys; private boolean onGraphComputer = false; diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/IdStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/IdStep.java index 018c91e..c5eb7c4 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/IdStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/IdStep.java @@ -29,7 +29,7 @@ import java.util.Set; /** * @author Marko A. Rodriguez (http://markorodriguez.com) */ -public final class IdStep<S extends Element> extends MapStep<S, Object> { +public final class IdStep<S extends Element> extends ScalarMapStep<S, Object> { public IdStep(final Traversal.Admin traversal) { super(traversal); diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/IndexStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/IndexStep.java index b903c15..314e751 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/IndexStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/IndexStep.java @@ -40,7 +40,7 @@ import java.util.function.Function; /** * @author Daniel Kuppitz (http://gremlin.guru) */ -public class IndexStep<S, E> extends MapStep<S, E> implements TraversalParent, Configuring { +public class IndexStep<S, E> extends ScalarMapStep<S, E> implements TraversalParent, Configuring { private final static IllegalArgumentException INVALID_CONFIGURATION_EXCEPTION = new IllegalArgumentException("WithOptions.indexer requires a single Integer argument (possible " + "" + diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LabelStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LabelStep.java index 2b2313f..060dc68 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LabelStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LabelStep.java @@ -29,7 +29,7 @@ import java.util.Set; /** * @author Marko A. Rodriguez (http://markorodriguez.com) */ -public final class LabelStep<S extends Element> extends MapStep<S, String> { +public final class LabelStep<S extends Element> extends ScalarMapStep<S, String> { public LabelStep(final Traversal.Admin traversal) { super(traversal); diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LambdaMapStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LambdaMapStep.java index b2024f8..ce6a1bd 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LambdaMapStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LambdaMapStep.java @@ -28,7 +28,7 @@ import java.util.function.Function; /** * @author Marko A. Rodriguez (http://markorodriguez.com) */ -public final class LambdaMapStep<S, E> extends MapStep<S, E> implements LambdaHolder { +public final class LambdaMapStep<S, E> extends ScalarMapStep<S, E> implements LambdaHolder { private final Function<Traverser<S>, E> function; diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LoopsStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LoopsStep.java index 11d8729..c3d2ac8 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LoopsStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LoopsStep.java @@ -24,7 +24,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.Traverser; /** * @author Daniel Kuppitz (http://gremlin.guru) */ -public final class LoopsStep<S> extends MapStep<S, Integer> { +public final class LoopsStep<S> extends ScalarMapStep<S, Integer> { private String loopName; diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MapStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MapStep.java index 51535e7..5d5103c 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MapStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MapStep.java @@ -18,12 +18,16 @@ */ package org.apache.tinkerpop.gremlin.process.traversal.step.map; +import org.apache.tinkerpop.gremlin.process.traversal.Step; 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.AbstractStep; -import org.apache.tinkerpop.gremlin.process.traversal.traverser.util.EmptyTraverser; /** + * A marker base class that designates an extending {@link Step} as a "Map" step which will transform the object of one + * {@link Traverser} into another. In many cases, it may be easier to simply extend from {@link ScalarMapStep} which + * has a straightforward implementation pattern. + * * @author Marko A. Rodriguez (http://markorodriguez.com) * @author Stephen Mallette (http://stephen.genoprime.com) */ @@ -32,26 +36,5 @@ public abstract class MapStep<S, E> extends AbstractStep<S, E> { public MapStep(final Traversal.Admin traversal) { super(traversal); } - - @Override - protected Traverser.Admin<E> processNextStart() { - final Traverser.Admin<S> traverser = this.starts.next(); - final E obj = this.map(traverser); - return isEmptyTraverser(obj) ? EmptyTraverser.instance() : traverser.split(obj, this); - } - - protected abstract E map(final Traverser.Admin<S> traverser); - - /** - * Determines if the value returned from {@link #map(Traverser.Admin)} should be representative of an - * {@link EmptyTraverser}. Such traversers will effectively be filtered out by the traversal. This method works in - * conjunction with {@link #map(Traverser.Admin)} in the sense that both work are called in the default - * implementation of {@link #processNextStart()} which will call this method after "map()"-ing the traverser to - * determine if that step consider the returned value as "empty". - */ - protected boolean isEmptyTraverser(final E obj) { - return false; - } - } diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MathStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MathStep.java index 0994411..b463833 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MathStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MathStep.java @@ -44,7 +44,7 @@ import java.util.regex.Pattern; /** * @author Marko A. Rodriguez (http://markorodriguez.com) */ -public final class MathStep<S> extends MapStep<S, Double> implements ByModulating, TraversalParent, Scoping, PathProcessor { +public final class MathStep<S> extends ScalarMapStep<S, Double> implements ByModulating, TraversalParent, Scoping, PathProcessor { private static final String CURRENT = "_"; private final String equation; diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MaxLocalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MaxLocalStep.java index 3ad326f..187ad39 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MaxLocalStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MaxLocalStep.java @@ -33,7 +33,7 @@ import static org.apache.tinkerpop.gremlin.util.NumberHelper.max; * @author Marko A. Rodriguez (http://markorodriguez.com) * @author Daniel Kuppitz (http://gremlin.guru) */ -public final class MaxLocalStep<E extends Comparable, S extends Iterable<E>> extends MapStep<S, E> { +public final class MaxLocalStep<E extends Comparable, S extends Iterable<E>> extends ScalarMapStep<S, E> { public MaxLocalStep(final Traversal.Admin traversal) { super(traversal); diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MeanLocalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MeanLocalStep.java index 91447fd..5ffb1a6 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MeanLocalStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MeanLocalStep.java @@ -32,7 +32,7 @@ import java.util.Set; * @author Marko A. Rodriguez (http://markorodriguez.com) * @author Daniel Kuppitz (http://gremlin.guru) */ -public final class MeanLocalStep<E extends Number, S extends Iterable<E>> extends MapStep<S, Number> { +public final class MeanLocalStep<E extends Number, S extends Iterable<E>> extends ScalarMapStep<S, Number> { public MeanLocalStep(final Traversal.Admin traversal) { super(traversal); diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MinLocalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MinLocalStep.java index 4139a7d..3bdb969 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MinLocalStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MinLocalStep.java @@ -33,7 +33,7 @@ import static org.apache.tinkerpop.gremlin.util.NumberHelper.min; * @author Marko A. Rodriguez (http://markorodriguez.com) * @author Daniel Kuppitz (http://gremlin.guru) */ -public final class MinLocalStep<E extends Comparable, S extends Iterable<E>> extends MapStep<S, E> { +public final class MinLocalStep<E extends Comparable, S extends Iterable<E>> extends ScalarMapStep<S, E> { public MinLocalStep(final Traversal.Admin traversal) { super(traversal); diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/OrderLocalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/OrderLocalStep.java index 95cb6db..97a68ff 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/OrderLocalStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/OrderLocalStep.java @@ -43,7 +43,7 @@ import java.util.stream.Collectors; /** * @author Marko A. Rodriguez (http://markorodriguez.com) */ -public final class OrderLocalStep<S, C extends Comparable> extends MapStep<S, S> implements ComparatorHolder<S, C>, ByModulating, TraversalParent { +public final class OrderLocalStep<S, C extends Comparable> extends ScalarMapStep<S, S> implements ComparatorHolder<S, C>, ByModulating, TraversalParent { private List<Pair<Traversal.Admin<S, C>, Comparator<C>>> comparators = new ArrayList<>(); private ChainedComparator<S, C> chainedComparator = null; diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PathStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PathStep.java index b49a1e4..82f19b4 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PathStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PathStep.java @@ -38,7 +38,7 @@ import java.util.Set; /** * @author Marko A. Rodriguez (http://markorodriguez.com) */ -public final class PathStep<S> extends MapStep<S, Path> implements TraversalParent, PathProcessor, ByModulating, FromToModulating { +public final class PathStep<S> extends ScalarMapStep<S, Path> implements TraversalParent, PathProcessor, ByModulating, FromToModulating { private TraversalRing<Object, Object> traversalRing; private Set<String> keepLabels; diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProjectStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProjectStep.java index 3ddd4a6..66c63e0 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProjectStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProjectStep.java @@ -37,7 +37,7 @@ import java.util.Set; /** * @author Marko A. Rodriguez (http://markorodriguez.com) */ -public final class ProjectStep<S, E> extends MapStep<S, Map<String, E>> implements TraversalParent, ByModulating { +public final class ProjectStep<S, E> extends ScalarMapStep<S, Map<String, E>> implements TraversalParent, ByModulating { private final List<String> projectKeys; private TraversalRing<S, E> traversalRing; diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyKeyStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyKeyStep.java index ea1db27..9e7a0ab 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyKeyStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyKeyStep.java @@ -29,7 +29,7 @@ import java.util.Set; /** * @author Marko A. Rodriguez (http://markorodriguez.com) */ -public final class PropertyKeyStep extends MapStep<Property, String> { +public final class PropertyKeyStep extends ScalarMapStep<Property, String> { public PropertyKeyStep(final Traversal.Admin traversal) { super(traversal); diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyMapStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyMapStep.java index a58aaaf..ecc82f9 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyMapStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyMapStep.java @@ -49,7 +49,7 @@ import java.util.Set; * @author Marko A. Rodriguez (http://markorodriguez.com) * @author Daniel Kuppitz (http://gremlin.guru) */ -public class PropertyMapStep<K,E> extends MapStep<Element, Map<K, E>> +public class PropertyMapStep<K,E> extends ScalarMapStep<Element, Map<K, E>> implements TraversalParent, ByModulating, Configuring { protected final String[] propertyKeys; diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyValueStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyValueStep.java index eab0ea6..6f41010 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyValueStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyValueStep.java @@ -29,7 +29,7 @@ import java.util.Set; /** * @author Marko A. Rodriguez (http://markorodriguez.com) */ -public final class PropertyValueStep<E> extends MapStep<Property<E>, E> { +public final class PropertyValueStep<E> extends ScalarMapStep<Property<E>, E> { public PropertyValueStep(final Traversal.Admin traversal) { super(traversal); diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/RangeLocalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/RangeLocalStep.java index 905a80c..f72a0cb 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/RangeLocalStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/RangeLocalStep.java @@ -36,7 +36,7 @@ import java.util.Set; /** * @author Daniel Kuppitz (http://gremlin.guru) */ -public final class RangeLocalStep<S> extends MapStep<S, S> { +public final class RangeLocalStep<S> extends ScalarMapStep<S, S> { private final long low; private final long high; diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SackStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SackStep.java index 3e0385b..7f12a00 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SackStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SackStep.java @@ -28,7 +28,7 @@ import java.util.Set; /** * @author Marko A. Rodriguez (http://markorodriguez.com) */ -public final class SackStep<S, E> extends MapStep<S, E> { +public final class SackStep<S, E> extends ScalarMapStep<S, E> { public SackStep(final Traversal.Admin traversal) { super(traversal); diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SampleLocalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SampleLocalStep.java index 5f83c53..ef65202 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SampleLocalStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SampleLocalStep.java @@ -36,7 +36,7 @@ import java.util.Set; * @author Daniel Kuppitz (http://gremlin.guru) * @author Marko A. Rodriguez (http://markorodriguez.com) */ -public final class SampleLocalStep<S> extends MapStep<S, S> { +public final class SampleLocalStep<S> extends ScalarMapStep<S, S> { private static final Random RANDOM = new Random(); diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyKeyStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ScalarMapStep.java similarity index 60% copy from gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyKeyStep.java copy to gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ScalarMapStep.java index ea1db27..78e0766 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyKeyStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ScalarMapStep.java @@ -20,28 +20,25 @@ package org.apache.tinkerpop.gremlin.process.traversal.step.map; import org.apache.tinkerpop.gremlin.process.traversal.Traversal; import org.apache.tinkerpop.gremlin.process.traversal.Traverser; -import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement; -import org.apache.tinkerpop.gremlin.structure.Property; - -import java.util.Collections; -import java.util.Set; /** + * A type of {@link MapStep} class which will transform the object of one {@link Traverser} into another. This class + * simply requires the implementation of the {@link #map(Traverser.Admin)} method to extract the object of the given + * {@link Traverser} and return the transformation of that object as {@code E}. + * * @author Marko A. Rodriguez (http://markorodriguez.com) + * @author Stephen Mallette (http://stephen.genoprime.com) */ -public final class PropertyKeyStep extends MapStep<Property, String> { - - public PropertyKeyStep(final Traversal.Admin traversal) { +public abstract class ScalarMapStep<S, E> extends MapStep<S,E> { + public ScalarMapStep(final Traversal.Admin traversal) { super(traversal); } @Override - protected String map(final Traverser.Admin<Property> traverser) { - return traverser.get().key(); + protected Traverser.Admin<E> processNextStart() { + final Traverser.Admin<S> traverser = this.starts.next(); + return traverser.split(this.map(traverser), this); } - @Override - public Set<TraverserRequirement> getRequirements() { - return Collections.singleton(TraverserRequirement.OBJECT); - } + protected abstract E map(final Traverser.Admin<S> traverser); } diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SelectOneStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SelectOneStep.java index a87f9ef..44e22fe 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SelectOneStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SelectOneStep.java @@ -18,6 +18,7 @@ */ package org.apache.tinkerpop.gremlin.process.traversal.step.map; +import org.apache.tinkerpop.gremlin.process.traversal.Path; import org.apache.tinkerpop.gremlin.process.traversal.Pop; import org.apache.tinkerpop.gremlin.process.traversal.Traversal; import org.apache.tinkerpop.gremlin.process.traversal.Traverser; @@ -26,12 +27,16 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.PathProcessor; import org.apache.tinkerpop.gremlin.process.traversal.step.Scoping; import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent; import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement; +import org.apache.tinkerpop.gremlin.process.traversal.traverser.util.EmptyTraverser; import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil; import org.apache.tinkerpop.gremlin.structure.util.StringFactory; import java.util.Collections; import java.util.HashSet; +import java.util.Iterator; import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; import java.util.Set; /** @@ -39,7 +44,6 @@ import java.util.Set; */ public final class SelectOneStep<S, E> extends MapStep<S, E> implements TraversalParent, Scoping, PathProcessor, ByModulating { - private static final Object NOTHING_SELECTED = new Object(); private final Pop pop; private final String selectKey; private Traversal.Admin<S, E> selectTraversal = null; @@ -52,15 +56,39 @@ public final class SelectOneStep<S, E> extends MapStep<S, E> implements Traversa } @Override - protected E map(final Traverser.Admin<S> traverser) { - final E end = this.getScopeValue(this.pop, this.selectKey, traverser, (E) NOTHING_SELECTED); - if (NOTHING_SELECTED == end) return end; - return null != end ? TraversalUtil.applyNullable((S) end, this.selectTraversal) : null; - } + protected Traverser.Admin<E> processNextStart() throws NoSuchElementException { + final Traverser.Admin<S> traverser = this.starts.next(); + + final Object object = traverser.get(); + if (object instanceof Map && ((Map<String, S>) object).containsKey(this.selectKey)) { + final S o = ((Map<String, S>) object).get(this.selectKey); + if (null == o) return traverser.split(null, this); + final Traverser.Admin<E> outTraverser = traverser.split(TraversalUtil.applyNullable(o, this.selectTraversal), this); + if (!(this.getTraversal().getParent() instanceof MatchStep)) + PathProcessor.processTraverserPathLabels(outTraverser, this.keepLabels); + return outTraverser; + } - @Override - protected boolean isEmptyTraverser(final E obj) { - return NOTHING_SELECTED == obj; + if (traverser.getSideEffects().exists(this.selectKey)) { + final S o = (S) traverser.getSideEffects().get(this.selectKey); + if (null == o) return traverser.split(null, this); + final Traverser.Admin<E> outTraverser = traverser.split(TraversalUtil.applyNullable(o, this.selectTraversal), this); + if (!(this.getTraversal().getParent() instanceof MatchStep)) + PathProcessor.processTraverserPathLabels(outTraverser, this.keepLabels); + return outTraverser; + } + + final Path path = traverser.path(); + if (path.hasLabel(this.selectKey)) { + final S o = (S) path.get(pop, this.selectKey); + if (null == o) return traverser.split(null, this); + final Traverser.Admin<E> outTraverser = traverser.split(TraversalUtil.applyNullable(o, this.selectTraversal), this); + if (!(this.getTraversal().getParent() instanceof MatchStep)) + PathProcessor.processTraverserPathLabels(outTraverser, this.keepLabels); + return outTraverser; + } + + return EmptyTraverser.instance(); } @Override @@ -132,14 +160,6 @@ public final class SelectOneStep<S, E> extends MapStep<S, E> implements Traversa return this.keepLabels; } - @Override - protected Traverser.Admin<E> processNextStart() { - final Traverser.Admin<E> traverser = super.processNextStart(); - if (!(this.getTraversal().getParent() instanceof MatchStep)) { - PathProcessor.processTraverserPathLabels(traverser, this.keepLabels); - } - return traverser; - } } diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SelectStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SelectStep.java index db15a28..2fa3e1f 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SelectStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SelectStep.java @@ -27,7 +27,6 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.Scoping; import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent; import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement; import org.apache.tinkerpop.gremlin.process.traversal.traverser.util.EmptyTraverser; -import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper; import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalRing; import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil; import org.apache.tinkerpop.gremlin.structure.util.StringFactory; @@ -39,10 +38,12 @@ import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.NoSuchElementException; import java.util.Set; /** * @author Marko A. Rodriguez (http://markorodriguez.com) + * @author Stephen Mallette (http://stephen.genoprime.com) */ public final class SelectStep<S, E> extends MapStep<S, Map<String, E>> implements Scoping, TraversalParent, PathProcessor, ByModulating { @@ -62,7 +63,8 @@ public final class SelectStep<S, E> extends MapStep<S, Map<String, E>> implement } @Override - protected Map<String, E> map(final Traverser.Admin<S> traverser) { + protected Traverser.Admin<Map<String, E>> processNextStart() throws NoSuchElementException { + final Traverser.Admin<S> traverser = this.starts.next(); final Map<String, E> bindings = new LinkedHashMap<>(this.selectKeys.size(), 1.0f); for (final String selectKey : this.selectKeys) { final E end = this.getNullableScopeValue(this.pop, selectKey, traverser); @@ -70,16 +72,11 @@ public final class SelectStep<S, E> extends MapStep<S, Map<String, E>> implement bindings.put(selectKey, TraversalUtil.applyNullable(end, this.traversalRing.next())); else { this.traversalRing.reset(); - return null; + return EmptyTraverser.instance(); } } this.traversalRing.reset(); - return bindings; - } - - @Override - protected boolean isEmptyTraverser(final Map<String, E> obj) { - return null == obj; + return PathProcessor.processTraverserPathLabels(traverser.split(bindings, this), this.keepLabels); } @Override @@ -156,9 +153,4 @@ public final class SelectStep<S, E> extends MapStep<S, Map<String, E>> implement public Set<String> getKeepLabels() { return this.keepLabels; } - - @Override - protected Traverser.Admin<Map<String, E>> processNextStart() { - return PathProcessor.processTraverserPathLabels(super.processNextStart(), this.keepLabels); - } } diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SumLocalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SumLocalStep.java index 72e6539..3249e31 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SumLocalStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SumLocalStep.java @@ -32,7 +32,7 @@ import java.util.Set; * @author Marko A. Rodriguez (http://markorodriguez.com) * @author Daniel Kuppitz (http://gremlin.guru) */ -public final class SumLocalStep<E extends Number, S extends Iterable<E>> extends MapStep<S, E> { +public final class SumLocalStep<E extends Number, S extends Iterable<E>> extends ScalarMapStep<S, E> { public SumLocalStep(final Traversal.Admin traversal) { super(traversal); diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TailLocalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TailLocalStep.java index ea678a5..336323e 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TailLocalStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TailLocalStep.java @@ -34,7 +34,7 @@ import java.util.Set; /** * @author Matt Frantz (http://github.com/mhfrantz) */ -public final class TailLocalStep<S> extends MapStep<S, S> { +public final class TailLocalStep<S> extends ScalarMapStep<S, S> { private final long limit; diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TraversalMapStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TraversalMapStep.java index 32c2e3c..7dc82d7 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TraversalMapStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TraversalMapStep.java @@ -29,10 +29,12 @@ import org.apache.tinkerpop.gremlin.structure.util.StringFactory; import java.util.Collections; import java.util.Iterator; import java.util.List; +import java.util.NoSuchElementException; import java.util.Set; /** * @author Marko A. Rodriguez (http://markorodriguez.com) + * @author Stephen Mallette (http://stephen.genoprime.com) */ public final class TraversalMapStep<S, E> extends MapStep<S, E> implements TraversalParent { @@ -44,14 +46,10 @@ public final class TraversalMapStep<S, E> extends MapStep<S, E> implements Trave } @Override - protected E map(final Traverser.Admin<S> traverser) { + protected Traverser.Admin<E> processNextStart() throws NoSuchElementException { + final Traverser.Admin<S> traverser = this.starts.next(); final Iterator<E> iterator = TraversalUtil.applyAll(traverser, this.mapTraversal); - return iterator.hasNext() ? iterator.next() : null; - } - - @Override - protected boolean isEmptyTraverser(final E obj) { - return null == obj; + return iterator.hasNext() ? traverser.split(iterator.next(), this) : EmptyTraverser.instance(); } @Override diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TraversalSelectStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TraversalSelectStep.java index 71ac06c..b1b1263 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TraversalSelectStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TraversalSelectStep.java @@ -26,6 +26,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.ByModulating; import org.apache.tinkerpop.gremlin.process.traversal.step.PathProcessor; import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent; import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement; +import org.apache.tinkerpop.gremlin.process.traversal.traverser.util.EmptyTraverser; import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil; import org.apache.tinkerpop.gremlin.structure.util.StringFactory; @@ -54,26 +55,42 @@ public final class TraversalSelectStep<S, E> extends MapStep<S, E> implements Tr } @Override - protected E map(final Traverser.Admin<S> traverser) { + protected Traverser.Admin<E> processNextStart() { + final Traverser.Admin<S> traverser = this.starts.next(); + + boolean found = false; E end = null; final Iterator<E> keyIterator = TraversalUtil.applyAll(traverser, this.keyTraversal); if (keyIterator.hasNext()) { final E key = keyIterator.next(); final Object object = traverser.get(); - if (object instanceof Map && ((Map) object).containsKey(key)) + if (object instanceof Map && ((Map) object).containsKey(key)) { end = (E) ((Map) object).get(key); - else if (key instanceof String) { + found = true; + } else if (key instanceof String) { final String skey = (String) key; if (traverser.getSideEffects().exists(skey)) { end = traverser.getSideEffects().get((String) key); + found = true; } else { final Path path = traverser.path(); - if (path.hasLabel(skey)) + if (path.hasLabel(skey)) { end = null == pop ? path.get(skey) : path.get(pop, skey); + found = true; + } } } } - return null != end ? TraversalUtil.applyNullable(end, this.selectTraversal) : null; + + if (found) { + final Traverser.Admin<E> outTraverser = traverser.split(null == end ? null : TraversalUtil.applyNullable(end, this.selectTraversal), this); + if (!(this.getTraversal().getParent() instanceof MatchStep)) { + PathProcessor.processTraverserPathLabels(outTraverser, this.keepLabels); + } + return outTraverser; + } else { + return EmptyTraverser.instance(); + } } @Override @@ -130,11 +147,6 @@ public final class TraversalSelectStep<S, E> extends MapStep<S, E> implements Tr TraverserRequirement.PATH); } - //@Override - //public Set<String> getScopeKeys() { - // return Collections.singleton(this.selectKey); - //} - public Pop getPop() { return this.pop; } @@ -148,15 +160,6 @@ public final class TraversalSelectStep<S, E> extends MapStep<S, E> implements Tr public Set<String> getKeepLabels() { return this.keepLabels; } - - @Override - protected Traverser.Admin<E> processNextStart() { - final Traverser.Admin<E> traverser = super.processNextStart(); - if (!(this.getTraversal().getParent() instanceof MatchStep)) { - PathProcessor.processTraverserPathLabels(traverser, this.keepLabels); - } - return traverser; - } } diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/finalization/ReferenceElementStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/finalization/ReferenceElementStrategy.java index 41e1325..ebb0423 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/finalization/ReferenceElementStrategy.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/finalization/ReferenceElementStrategy.java @@ -21,7 +21,7 @@ package org.apache.tinkerpop.gremlin.process.traversal.strategy.finalization; import org.apache.tinkerpop.gremlin.process.traversal.Traversal; import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy; import org.apache.tinkerpop.gremlin.process.traversal.Traverser; -import org.apache.tinkerpop.gremlin.process.traversal.step.map.MapStep; +import org.apache.tinkerpop.gremlin.process.traversal.step.map.ScalarMapStep; import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.ProfileSideEffectStep; import org.apache.tinkerpop.gremlin.process.traversal.step.util.EmptyStep; import org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy; @@ -56,7 +56,7 @@ public final class ReferenceElementStrategy extends AbstractTraversalStrategy<Tr return INSTANCE; } - public static class ReferenceElementStep<S, E> extends MapStep<S, E> { + public static class ReferenceElementStep<S, E> extends ScalarMapStep<S, E> { public ReferenceElementStep(final Traversal.Admin traversal) { super(traversal); diff --git a/gremlin-test/features/map/Map.feature b/gremlin-test/features/map/Map.feature index 8d1029f..5f404ea 100644 --- a/gremlin-test/features/map/Map.feature +++ b/gremlin-test/features/map/Map.feature @@ -106,3 +106,19 @@ Feature: Step - map() | v[josh] | | v[ripple] | | v[peter] | + + Scenario: g_V_mapXconstantXnullXX + Given the modern graph + And the traversal of + """ + g.V().map(__.constant(null)) + """ + When iterated to list + Then the result should be unordered + | result | + | null | + | null | + | null | + | null | + | null | + | null | \ No newline at end of file diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MapTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MapTest.java index 9006fec..35faa03 100644 --- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MapTest.java +++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MapTest.java @@ -31,9 +31,11 @@ import org.junit.runner.RunWith; import java.util.List; import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.MODERN; +import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.constant; import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.select; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; /** @@ -53,6 +55,8 @@ public abstract class MapTest extends AbstractGremlinProcessTest { public abstract Traversal<Vertex, Vertex> get_g_V_mapXselectXaXX(); + public abstract Traversal<Vertex, Vertex> get_g_V_mapXconstantXnullXX(); + @Test @LoadGraphWith(MODERN) public void g_VX1X_mapXnameX() { @@ -139,6 +143,19 @@ public abstract class MapTest extends AbstractGremlinProcessTest { assertEquals(6, counter); } + @Test + @LoadGraphWith(MODERN) + public void g_V_mapXconstantXnullXX() { + final Traversal<Vertex, Vertex> traversal = get_g_V_mapXconstantXnullXX(); + printTraversalForm(traversal); + int counter = 0; + while (traversal.hasNext()) { + counter++; + assertNull(traversal.next()); + } + assertEquals(6, counter); + } + public static class Traversals extends MapTest { @Override public Traversal<Vertex, String> get_g_VX1X_mapXnameX(final Object v1Id) { @@ -169,5 +186,10 @@ public abstract class MapTest extends AbstractGremlinProcessTest { public Traversal<Vertex, Vertex> get_g_V_mapXselectXaXX() { return g.V().as("a").map(select("a")); } + + @Override + public Traversal<Vertex, Vertex> get_g_V_mapXconstantXnullXX() { + return g.V().map(constant(null)); + } } } diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/decoration/OptionsStrategyTest.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/decoration/OptionsStrategyTest.java index ce39953..32a77f2 100644 --- a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/decoration/OptionsStrategyTest.java +++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/decoration/OptionsStrategyTest.java @@ -21,7 +21,7 @@ package org.apache.tinkerpop.gremlin.tinkergraph.process.traversal.strategy.deco import org.apache.tinkerpop.gremlin.process.traversal.Traverser; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; -import org.apache.tinkerpop.gremlin.process.traversal.step.map.MapStep; +import org.apache.tinkerpop.gremlin.process.traversal.step.map.ScalarMapStep; import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.OptionsStrategy; import org.apache.tinkerpop.gremlin.structure.Graph; import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph; @@ -54,7 +54,7 @@ public class OptionsStrategyTest { private static void assertOptions(final GraphTraversalSource optionedG) { GraphTraversal t = optionedG.inject(1); - t = t.asAdmin().addStep(new MapStep<Object, Object>(t.asAdmin()) { + t = t.asAdmin().addStep(new ScalarMapStep<Object, Object>(t.asAdmin()) { @Override protected Object map(final Traverser.Admin<Object> traverser) { final OptionsStrategy strategy = traversal.asAdmin().getStrategies().getStrategy(OptionsStrategy.class).get();
