TINKERPOP-2011 Treat numerical options in `ChooseStep` as in any other numerical comparison (value matters, data type does not).
Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/f565345b Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/f565345b Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/f565345b Branch: refs/heads/master Commit: f565345b03b69d06e9770e7acab4435f355df8d0 Parents: ec561d8 Author: Daniel Kuppitz <daniel_kupp...@hotmail.com> Authored: Wed Jul 18 12:34:16 2018 -0700 Committer: Daniel Kuppitz <daniel_kupp...@hotmail.com> Committed: Mon Jul 23 09:52:38 2018 -0700 ---------------------------------------------------------------------- .gitignore | 1 + CHANGELOG.asciidoc | 1 + docker/hadoop/.gitignore | 1 + docker/hadoop/Dockerfile | 25 ---------- .../traversal/step/branch/BranchStep.java | 51 +++++++++++++++++--- .../step/branch/GroovyChooseTest.groovy | 5 ++ gremlin-test/features/branch/Choose.feature | 15 ++++++ .../traversal/step/branch/ChooseTest.java | 24 +++++++++ 8 files changed, 91 insertions(+), 32 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/f565345b/.gitignore ---------------------------------------------------------------------- diff --git a/.gitignore b/.gitignore index a27eb44..fa8dac6 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,4 @@ tools/ *nupkg NuGet.Config nuget*.exe +/Dockerfile http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/f565345b/CHANGELOG.asciidoc ---------------------------------------------------------------------- diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index f50b9ec..6270880 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -23,6 +23,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima [[release-3-2-10]] === TinkerPop 3.2.10 (Release Date: NOT OFFICIALLY RELEASED YET) +* Match numbers in `choose()` options using `NumberHelper` (match values, ignore data type). * Fixed bug in Java driver where an disorderly shutdown of the server would cause the client to hang. * Added a dotnet template project that should make it easier to get started with Gremlin.Net. * Removed `ThreadInterruptCustomizerProvider` from documentation as a way to timeout. http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/f565345b/docker/hadoop/.gitignore ---------------------------------------------------------------------- diff --git a/docker/hadoop/.gitignore b/docker/hadoop/.gitignore new file mode 100644 index 0000000..9414382 --- /dev/null +++ b/docker/hadoop/.gitignore @@ -0,0 +1 @@ +Dockerfile http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/f565345b/docker/hadoop/Dockerfile ---------------------------------------------------------------------- diff --git a/docker/hadoop/Dockerfile b/docker/hadoop/Dockerfile deleted file mode 100644 index 86b2598..0000000 --- a/docker/hadoop/Dockerfile +++ /dev/null @@ -1,25 +0,0 @@ -# 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. - -FROM tinkerpop:base - -MAINTAINER Daniel Kuppitz <m...@gremlin.guru> - -ENV HADOOP_VERSION 2.7.2 - -COPY install.sh /usr/local/sbin/install-hadoop.sh -RUN /usr/local/sbin/install-hadoop.sh http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/f565345b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/BranchStep.java ---------------------------------------------------------------------- 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 0b1a059..6c38351 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,6 +18,7 @@ */ package org.apache.tinkerpop.gremlin.process.traversal.step.branch; +import org.apache.tinkerpop.gremlin.process.traversal.NumberHelper; import org.apache.tinkerpop.gremlin.process.traversal.Traversal; import org.apache.tinkerpop.gremlin.process.traversal.Traverser; import org.apache.tinkerpop.gremlin.process.traversal.step.Barrier; @@ -46,7 +47,7 @@ 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<M, List<Traversal.Admin<S, E>>> traversalOptions = new HashMap<>(); + protected Map<Object, List<Traversal.Admin<S, E>>> traversalOptions = new HashMap<>(); private boolean first = true; private boolean hasBarrier = false; @@ -60,10 +61,11 @@ 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) { - if (this.traversalOptions.containsKey(pickToken)) - this.traversalOptions.get(pickToken).add(traversalOption); + final Object pickTokenKey = PickTokenKey.make(pickToken); + if (this.traversalOptions.containsKey(pickTokenKey)) + this.traversalOptions.get(pickTokenKey).add(traversalOption); else - this.traversalOptions.put(pickToken, new ArrayList<>(Collections.singletonList(traversalOption))); + this.traversalOptions.put(pickTokenKey, new ArrayList<>(Collections.singletonList(traversalOption))); // adding an IdentityStep acts as a placeholder when reducing barriers get in the way - see the // standardAlgorithm() method for more information. @@ -136,7 +138,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 M choice = TraversalUtil.apply(start, this.branchTraversal); + final Object choice = PickTokenKey.make(TraversalUtil.apply(start, this.branchTraversal)); final List<Traversal.Admin<S, E>> branch = this.traversalOptions.containsKey(choice) ? this.traversalOptions.get(choice) : this.traversalOptions.get(Pick.none); @@ -156,7 +158,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 M choice = TraversalUtil.apply(start, this.branchTraversal); + final Object choice = PickTokenKey.make(TraversalUtil.apply(start, this.branchTraversal)); final List<Traversal.Admin<S, E>> branch = this.traversalOptions.containsKey(choice) ? this.traversalOptions.get(choice) : this.traversalOptions.get(Pick.none); if (null != branch) { branch.forEach(traversal -> { @@ -184,7 +186,7 @@ public class BranchStep<S, E, M> extends ComputerAwareStep<S, E> implements Trav 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<M, List<Traversal.Admin<S, E>>> entry : this.traversalOptions.entrySet()) { + for (final Map.Entry<Object, List<Traversal.Admin<S, E>>> entry : this.traversalOptions.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) -> @@ -226,4 +228,39 @@ public class BranchStep<S, E, M> extends ComputerAwareStep<S, E> implements Trav this.getGlobalChildren().forEach(Traversal.Admin::reset); this.first = true; } + + /** + * PickTokenKey is basically a wrapper for numbers that are used as a PickToken. This is + * required in order to treat equal numbers of different data types as a match. + */ + private static class PickTokenKey { + + final Number number; + + private PickTokenKey(final Number number) { + this.number = number; + } + + static Object make(final Object value) { + return value instanceof Number ? new PickTokenKey((Number) value) : value; + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + final PickTokenKey other = (PickTokenKey) o; + return 0 == NumberHelper.compare(number, other.number); + } + + @Override + public int hashCode() { + return number.hashCode(); + } + + @Override + public String toString() { + return "PickTokenKey(" + number + ")"; + } + } } http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/f565345b/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/branch/GroovyChooseTest.groovy ---------------------------------------------------------------------- diff --git a/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/branch/GroovyChooseTest.groovy b/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/branch/GroovyChooseTest.groovy index b3e9955..d1801c4 100644 --- a/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/branch/GroovyChooseTest.groovy +++ b/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/branch/GroovyChooseTest.groovy @@ -66,6 +66,11 @@ public abstract class GroovyChooseTest { } @Override + public Traversal<Vertex, Map<String, Long>> get_g_V_hasLabelXpersonX_chooseXageX__optionX27L__constantXyoungXX_optionXnone__constantXoldXX_groupCount() { + new ScriptTraversal<>(g, "gremlin-groovy", "g.V().hasLabel('person').choose(values('age')).option(27L, constant('young')).option(none, constant('old')).groupCount") + } + + @Override public Traversal<Integer, List<Integer>> get_g_injectX1X_chooseXisX1X__constantX10Xfold__foldX() { new ScriptTraversal<>(g, "gremlin-groovy", "g.inject(1).choose(__.is(1), __.constant(10).fold(), __.fold())") } http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/f565345b/gremlin-test/features/branch/Choose.feature ---------------------------------------------------------------------- diff --git a/gremlin-test/features/branch/Choose.feature b/gremlin-test/features/branch/Choose.feature index 225e40c..187c96e 100644 --- a/gremlin-test/features/branch/Choose.feature +++ b/gremlin-test/features/branch/Choose.feature @@ -123,6 +123,21 @@ Feature: Step - choose() | m[{"p1":"josh", "p2":"josh"}] | | m[{"p1":"peter", "p2":"peter"}] | + Scenario: g_V_hasLabelXpersonX_chooseXageX__optionX27L__constantXyoungXX_optionXnone__constantXoldXX_groupCount + Given the modern graph + And using the parameter d27 defined as "d[27].l" + And the traversal of + """ + g.V().hasLabel("person").choose(__.values("age")). + option(d27, __.constant("young")). + option(Pick.none, __.constant("old")). + groupCount() + """ + When iterated to list + Then the result should be unordered + | result | + | m[{"young":"d[1].l", "old":"d[3].l"}] | + Scenario: g_injectX1X_chooseXisX1X__constantX10Xfold__foldX Given the empty graph And using the parameter d10 defined as "d[10].i" http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/f565345b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/ChooseTest.java ---------------------------------------------------------------------- diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/ChooseTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/ChooseTest.java index 6da38a7..105e307 100644 --- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/ChooseTest.java +++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/ChooseTest.java @@ -49,6 +49,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; /** * @author Marko A. Rodriguez (http://markorodriguez.com) @@ -69,6 +70,8 @@ public abstract class ChooseTest extends AbstractGremlinProcessTest { public abstract Traversal<Vertex, Map<String, String>> get_g_V_hasLabelXpersonX_asXp1X_chooseXoutEXknowsX__outXknowsXX_asXp2X_selectXp1_p2X_byXnameX(); + public abstract Traversal<Vertex, Map<String, Long>> get_g_V_hasLabelXpersonX_chooseXageX__optionX27L__constantXyoungXX_optionXnone__constantXoldXX_groupCount(); + public abstract Traversal<Integer, List<Integer>> get_g_injectX1X_chooseXisX1X__constantX10Xfold__foldX(); public abstract Traversal<Integer, List<Integer>> get_g_injectX2X_chooseXisX1X__constantX10Xfold__foldX(); @@ -138,6 +141,19 @@ public abstract class ChooseTest extends AbstractGremlinProcessTest { } @Test + @LoadGraphWith(MODERN) + public void g_V_hasLabelXpersonX_chooseXageX__optionX27L__constantXyoungXX_optionXnone__constantXoldXX_groupCount() { + final Traversal<Vertex, Map<String, Long>> traversal = get_g_V_hasLabelXpersonX_chooseXageX__optionX27L__constantXyoungXX_optionXnone__constantXoldXX_groupCount(); + printTraversalForm(traversal); + final Map<String, Long> expected = new HashMap<>(2); + expected.put("young", 1L); + expected.put("old", 3L); + assertTrue(traversal.hasNext()); + checkMap(expected, traversal.next()); + assertFalse(traversal.hasNext()); + } + + @Test public void g_injectX1X_chooseXisX1X__constantX10Xfold__foldX() { final Traversal<Integer, List<Integer>> traversal = get_g_injectX1X_chooseXisX1X__constantX10Xfold__foldX(); printTraversalForm(traversal); @@ -191,6 +207,14 @@ public abstract class ChooseTest extends AbstractGremlinProcessTest { } @Override + public Traversal<Vertex, Map<String, Long>> get_g_V_hasLabelXpersonX_chooseXageX__optionX27L__constantXyoungXX_optionXnone__constantXoldXX_groupCount() { + return g.V().hasLabel("person").choose(values("age")) + .option(27L, __.constant("young")) + .option(TraversalOptionParent.Pick.none, __.constant("old")) + .groupCount(); + } + + @Override public Traversal<Integer, List<Integer>> get_g_injectX1X_chooseXisX1X__constantX10Xfold__foldX() { return g.inject(1).choose(__.is(1), __.constant(10).fold(), __.fold()); }