added where().by() semantics to Gremlin and fixed a severe bug in Gremlin-Python's P object. Optimized TraversalRing for non-existent modulators.
Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/68ecda40 Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/68ecda40 Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/68ecda40 Branch: refs/heads/TINKERPOP-1404 Commit: 68ecda40486650cb9f209b61570485d3c24eed37 Parents: a2ddf8f Author: Marko A. Rodriguez <okramma...@gmail.com> Authored: Wed Sep 14 15:30:34 2016 -0600 Committer: Marko A. Rodriguez <okramma...@gmail.com> Committed: Thu Sep 15 09:58:53 2016 -0600 ---------------------------------------------------------------------- CHANGELOG.asciidoc | 4 + .../step/filter/WherePredicateStep.java | 54 ++++++++-- .../process/traversal/step/map/PathStep.java | 2 +- .../process/traversal/step/map/ProjectStep.java | 2 +- .../process/traversal/step/map/SelectStep.java | 2 +- .../process/traversal/step/map/TreeStep.java | 2 +- .../step/sideEffect/TreeSideEffectStep.java | 2 +- .../process/traversal/util/TraversalRing.java | 2 +- .../traversal/step/filter/WhereStepTest.java | 6 +- .../step/filter/GroovyWhereTest.groovy | 15 +++ .../python/TraversalSourceGenerator.groovy | 8 +- .../gremlin/python/jsr223/PythonTranslator.java | 2 +- .../jython/gremlin_python/process/traversal.py | 8 +- .../main/jython/tests/process/test_traversal.py | 8 ++ .../jython/tests/structure/io/test_graphson.py | 5 + .../io/graphson/GraphSONWriterTest.java | 2 +- .../traversal/step/filter/WhereTest.java | 104 ++++++++++++++++--- 17 files changed, 188 insertions(+), 40 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/68ecda40/CHANGELOG.asciidoc ---------------------------------------------------------------------- diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index cf1cae8..2210ecf 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -26,6 +26,10 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima TinkerPop 3.2.3 (Release Date: NOT OFFICIALLY RELEASED YET) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +* Fixed a bug in Gremlin-Python `P` where predicates reversed the order of the predicates. +* Fixed a naming bug in Gremlin-Python where `P._and` and `P._or` should be `P.and_` and `P.or_`. (*breaking*) +* `where()` predicate-based steps now support `by()`-modulation. +* `TraversalRing` returns an null if it does not contain traversals (previously `IdentityTraversal`). * Fixed a `JavaTranslator` bug where `Bytecode` instructions were being mutated during translation. * Added `Path` to Gremlin-Python with respective GraphSON 2.0 deserializer. * VertexPrograms can now declare traverser requirements, e.g. to have access to the path when used with `.program()`. http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/68ecda40/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WherePredicateStep.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WherePredicateStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WherePredicateStep.java index 898a42a..05637f6 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WherePredicateStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WherePredicateStep.java @@ -22,19 +22,30 @@ import org.apache.tinkerpop.gremlin.process.traversal.P; import org.apache.tinkerpop.gremlin.process.traversal.Pop; import org.apache.tinkerpop.gremlin.process.traversal.Traversal; import org.apache.tinkerpop.gremlin.process.traversal.Traverser; +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.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.util.ConnectiveP; 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; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Optional; +import java.util.Set; /** * @author Marko A. Rodriguez (http://markorodriguez.com) */ -public final class WherePredicateStep<S> extends FilterStep<S> implements Scoping, PathProcessor { +public final class WherePredicateStep<S> extends FilterStep<S> implements Scoping, PathProcessor, ByModulating, TraversalParent { protected String startKey; protected List<String> selectKeys; @@ -42,6 +53,8 @@ public final class WherePredicateStep<S> extends FilterStep<S> implements Scopin protected final Set<String> scopeKeys = new HashSet<>(); protected Set<String> keepLabels; + protected TraversalRing<S, ?> traversalRing = new TraversalRing<>(); + public WherePredicateStep(final Traversal.Admin traversal, final Optional<String> startKey, final P<String> predicate) { super(traversal); this.startKey = startKey.orElse(null); @@ -66,7 +79,7 @@ public final class WherePredicateStep<S> extends FilterStep<S> implements Scopin if (predicate instanceof ConnectiveP) ((ConnectiveP<Object>) predicate).getPredicates().forEach(p -> this.setPredicateValues(p, traverser, selectKeysIterator)); else - predicate.setValue(this.getScopeValue(Pop.last, selectKeysIterator.next(), traverser)); + predicate.setValue(TraversalUtil.applyNullable((S) this.getScopeValue(Pop.last, selectKeysIterator.next(), traverser), this.traversalRing.next())); } public Optional<P<?>> getPredicate() { @@ -84,14 +97,18 @@ public final class WherePredicateStep<S> extends FilterStep<S> implements Scopin @Override protected boolean filter(final Traverser.Admin<S> traverser) { + final Object value = null == this.startKey ? + TraversalUtil.applyNullable(traverser, this.traversalRing.next()) : + TraversalUtil.applyNullable((S) this.getScopeValue(Pop.last, this.startKey, traverser), this.traversalRing.next()); this.setPredicateValues(this.predicate, traverser, this.selectKeys.iterator()); - return this.predicate.test(null == this.startKey ? traverser.get() : this.getScopeValue(Pop.last, this.startKey, traverser)); + this.traversalRing.reset(); + return this.predicate.test(value); } @Override public String toString() { // TODO: revert the predicates to their string form? - return StringFactory.stepString(this, this.startKey, this.predicate); + return StringFactory.stepString(this, this.startKey, this.predicate, this.traversalRing); } @Override @@ -103,19 +120,33 @@ public final class WherePredicateStep<S> extends FilterStep<S> implements Scopin public WherePredicateStep<S> clone() { final WherePredicateStep<S> clone = (WherePredicateStep<S>) super.clone(); clone.predicate = this.predicate.clone(); + clone.traversalRing = this.traversalRing.clone(); return clone; } @Override + public void setTraversal(final Traversal.Admin<?, ?> parentTraversal) { + super.setTraversal(parentTraversal); + this.traversalRing.getTraversals().forEach(this::integrateChild); + } + + @Override public int hashCode() { - return super.hashCode() ^ (null == this.startKey ? "null".hashCode() : this.startKey.hashCode()) ^ this.predicate.hashCode(); + return super.hashCode() ^ this.traversalRing.hashCode() ^ (null == this.startKey ? "null".hashCode() : this.startKey.hashCode()) ^ this.predicate.hashCode(); } @Override public Set<TraverserRequirement> getRequirements() { - return TraversalHelper.getLabels(TraversalHelper.getRootTraversal(this.traversal)).stream().filter(this.scopeKeys::contains).findAny().isPresent() ? - TYPICAL_GLOBAL_REQUIREMENTS : - TYPICAL_LOCAL_REQUIREMENTS; + final Set<TraverserRequirement> requirements = + TraversalHelper.getLabels(TraversalHelper.getRootTraversal(this.traversal)).stream().filter(this.scopeKeys::contains).findAny().isPresent() ? + TYPICAL_GLOBAL_REQUIREMENTS : + TYPICAL_LOCAL_REQUIREMENTS; + return this.getSelfAndChildRequirements(requirements.toArray(new TraverserRequirement[requirements.size()])); + } + + @Override + public List<Traversal.Admin<S, ?>> getLocalChildren() { + return (List) this.traversalRing.getTraversals(); } @Override @@ -132,4 +163,9 @@ public final class WherePredicateStep<S> extends FilterStep<S> implements Scopin public Set<String> getKeepLabels() { return this.keepLabels; } + + @Override + public void modulateBy(final Traversal.Admin<?, ?> traversal) throws UnsupportedOperationException { + this.traversalRing.addTraversal(this.integrateChild(traversal)); + } } http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/68ecda40/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PathStep.java ---------------------------------------------------------------------- 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 6dca028..705cf0c 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 @@ -53,7 +53,7 @@ public final class PathStep<S> extends MapStep<S, Path> implements TraversalPare path = traverser.path(); else { path = MutablePath.make(); - traverser.path().forEach((object, labels) -> path.extend(TraversalUtil.apply(object, this.traversalRing.next()), labels)); + traverser.path().forEach((object, labels) -> path.extend(TraversalUtil.applyNullable(object, this.traversalRing.next()), labels)); } this.traversalRing.reset(); return path; http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/68ecda40/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProjectStep.java ---------------------------------------------------------------------- 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 2e586b7..83e095a 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 @@ -52,7 +52,7 @@ public final class ProjectStep<S, E> extends MapStep<S, Map<String, E>> implemen protected Map<String, E> map(final Traverser.Admin<S> traverser) { final Map<String, E> end = new LinkedHashMap<>(this.projectKeys.size(), 1.0f); for (final String projectKey : this.projectKeys) { - end.put(projectKey, TraversalUtil.apply(traverser, this.traversalRing.next())); + end.put(projectKey, TraversalUtil.applyNullable(traverser, this.traversalRing.next())); } this.traversalRing.reset(); return end; http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/68ecda40/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SelectStep.java ---------------------------------------------------------------------- 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 7c54708..77db60f 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 @@ -66,7 +66,7 @@ public final class SelectStep<S, E> extends MapStep<S, Map<String, E>> implement for (final String selectKey : this.selectKeys) { final E end = this.getNullableScopeValue(this.pop, selectKey, traverser); if (null != end) - bindings.put(selectKey, TraversalUtil.apply(end, this.traversalRing.next())); + bindings.put(selectKey, TraversalUtil.applyNullable(end, this.traversalRing.next())); else { this.traversalRing.reset(); return null; http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/68ecda40/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TreeStep.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TreeStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TreeStep.java index 8bdc692..ac1fa07 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TreeStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TreeStep.java @@ -73,7 +73,7 @@ public final class TreeStep<S> extends ReducingBarrierStep<S, Tree> implements T Tree depth = topTree; final Path path = traverser.path(); for (int i = 0; i < path.size(); i++) { - final Object object = TraversalUtil.apply(path.<Object>get(i), this.traversalRing.next()); + final Object object = TraversalUtil.applyNullable(path.<Object>get(i), this.traversalRing.next()); if (!depth.containsKey(object)) depth.put(object, new Tree<>()); depth = (Tree) depth.get(object); http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/68ecda40/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/TreeSideEffectStep.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/TreeSideEffectStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/TreeSideEffectStep.java index 9996c83..15756d2 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/TreeSideEffectStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/TreeSideEffectStep.java @@ -59,7 +59,7 @@ public final class TreeSideEffectStep<S> extends SideEffectStep<S> implements Si Tree depth = root; final Path path = traverser.path(); for (int i = 0; i < path.size(); i++) { - final Object object = TraversalUtil.apply(path.<Object>get(i), this.traversalRing.next()); + final Object object = TraversalUtil.applyNullable(path.<Object>get(i), this.traversalRing.next()); if (!depth.containsKey(object)) depth.put(object, new Tree<>()); depth = (Tree) depth.get(object); http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/68ecda40/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalRing.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalRing.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalRing.java index 841f280..d6d10c0 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalRing.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalRing.java @@ -42,7 +42,7 @@ public final class TraversalRing<A, B> implements Serializable, Cloneable { public Traversal.Admin<A, B> next() { if (this.traversals.size() == 0) { - return this.identityTraversal; // TODO: return null and TraversalUtil.applyNullable()? + return null; } else { this.currentTraversal = (this.currentTraversal + 1) % this.traversals.size(); return this.traversals.get(this.currentTraversal); http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/68ecda40/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WhereStepTest.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WhereStepTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WhereStepTest.java index cb1795d..7f65f23 100644 --- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WhereStepTest.java +++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WhereStepTest.java @@ -43,7 +43,11 @@ public class WhereStepTest extends StepTest { as("a").out().as("b").where(as("a").out()), as("a").out().as("b").where(as("a").out().as("b")), as("a").out().as("b").where("a", P.neq("b")), - as("a").out().as("b").where("a", P.neq("c")) + as("a").out().as("b").where("a", P.neq("c")), + as("a").out().as("b").where("a", P.neq("b")).by("name"), + as("a").out().as("b").where("a", P.neq("b")).by("name").by("age"), + as("a").out().as("b").where("a", P.neq("b")).by("age"), + as("a").out().as("b").where("a", P.neq("b").and(P.neq("a"))).by("age") ); } http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/68ecda40/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/filter/GroovyWhereTest.groovy ---------------------------------------------------------------------- diff --git a/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/filter/GroovyWhereTest.groovy b/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/filter/GroovyWhereTest.groovy index fc0aca9..a28c3dc 100644 --- a/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/filter/GroovyWhereTest.groovy +++ b/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/filter/GroovyWhereTest.groovy @@ -132,5 +132,20 @@ public abstract class GroovyWhereTest { new ScriptTraversal<>(g, "gremlin-groovy", "g.V.as('a').out.as('b').where(__.as('b').in.count.is(eq(3)).or.where(__.as('b').out('created').and.as('b').has(label,'person'))).select('a','b')") } + @Override + public Traversal<Vertex, Map<String, String>> get_g_V_asXaX_outXcreatedX_inXcreatedX_asXbX_whereXa_gtXbXX_byXageX_selectXa_bX_byXnameX() { + new ScriptTraversal<>(g, "gremlin-groovy", "g.V.as('a').out('created').in('created').as('b').where('a', gt('b')).by('age').select('a', 'b').by('name')") + } + + @Override + public Traversal<Vertex, Map<String, String>> get_g_V_asXaX_outEXcreatedX_asXbX_inV_asXcX_whereXa_gtXbX_orXeqXbXXX_byXageX_byXweightX_byXweightX_selectXa_cX_byXnameX() { + new ScriptTraversal<>(g, "gremlin-groovy", "g.V.as('a').outE('created').as('b').inV().as('c').where('a', gt('b').or(eq('b'))).by('age').by('weight').by('weight').select('a', 'c').by('name')") + } + + @Override + public Traversal<Vertex, Map<String, String>> get_g_V_asXaX_outEXcreatedX_asXbX_inV_asXcX_inXcreatedX_asXdX_whereXa_ltXbX_orXgtXcXX_andXneqXdXXX_byXageX_byXweightX_byXinXcreatedX_valuesXageX_minX_selectXa_c_dX() { + new ScriptTraversal<>(g, "gremlin-groovy", "g.V().as('a').outE('created').as('b').inV().as('c').in('created').as('d').where('a', lt('b').or(gt('c')).and(neq('d'))).by('age').by('weight').by(__.in('created').values('age').min()).select('a', 'c', 'd').by('name')") + } + } } http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/68ecda40/gremlin-python/src/main/groovy/org/apache/tinkerpop/gremlin/python/TraversalSourceGenerator.groovy ---------------------------------------------------------------------- diff --git a/gremlin-python/src/main/groovy/org/apache/tinkerpop/gremlin/python/TraversalSourceGenerator.groovy b/gremlin-python/src/main/groovy/org/apache/tinkerpop/gremlin/python/TraversalSourceGenerator.groovy index 79a1a4e..95bfdbf 100644 --- a/gremlin-python/src/main/groovy/org/apache/tinkerpop/gremlin/python/TraversalSourceGenerator.groovy +++ b/gremlin-python/src/main/groovy/org/apache/tinkerpop/gremlin/python/TraversalSourceGenerator.groovy @@ -152,10 +152,10 @@ class Traversal(object): return P("${SymbolHelper.toJava(method)}", *args) """) }; - pythonClass.append(""" def _and(self, arg): - return P("and", arg, self) - def _or(self, arg): - return P("or", arg, self) + pythonClass.append(""" def and_(self, arg): + return P("and", self, arg) + def or_(self, arg): + return P("or", self, arg) def __eq__(self, other): return isinstance(other, self.__class__) and self.operator == other.operator and self.value == other.value and self.other == other.other def __repr__(self): http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/68ecda40/gremlin-python/src/main/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonTranslator.java ---------------------------------------------------------------------- diff --git a/gremlin-python/src/main/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonTranslator.java b/gremlin-python/src/main/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonTranslator.java index 08295e0..90d29e8 100644 --- a/gremlin-python/src/main/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonTranslator.java +++ b/gremlin-python/src/main/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonTranslator.java @@ -175,7 +175,7 @@ public class PythonTranslator implements Translator.ScriptTranslator { for (int i = 0; i < list.size(); i++) { convertPToString(list.get(i), current); if (i < list.size() - 1) - current.append(p instanceof OrP ? "._or(" : "._and("); + current.append(p instanceof OrP ? ".or_(" : ".and_("); } current.append(")"); } else http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/68ecda40/gremlin-python/src/main/jython/gremlin_python/process/traversal.py ---------------------------------------------------------------------- diff --git a/gremlin-python/src/main/jython/gremlin_python/process/traversal.py b/gremlin-python/src/main/jython/gremlin_python/process/traversal.py index 0302047..05739da 100644 --- a/gremlin-python/src/main/jython/gremlin_python/process/traversal.py +++ b/gremlin-python/src/main/jython/gremlin_python/process/traversal.py @@ -172,10 +172,10 @@ class P(object): @staticmethod def without(*args): return P("without", *args) - def _and(self, arg): - return P("and", arg, self) - def _or(self, arg): - return P("or", arg, self) + def and_(self, arg): + return P("and", self, arg) + def or_(self, arg): + return P("or", self, arg) def __eq__(self, other): return isinstance(other, self.__class__) and self.operator == other.operator and self.value == other.value and self.other == other.other def __repr__(self): http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/68ecda40/gremlin-python/src/main/jython/tests/process/test_traversal.py ---------------------------------------------------------------------- diff --git a/gremlin-python/src/main/jython/tests/process/test_traversal.py b/gremlin-python/src/main/jython/tests/process/test_traversal.py index fe72ac1..0f25190 100644 --- a/gremlin-python/src/main/jython/tests/process/test_traversal.py +++ b/gremlin-python/src/main/jython/tests/process/test_traversal.py @@ -23,6 +23,7 @@ import unittest from unittest import TestCase from gremlin_python.structure.graph import Graph +from gremlin_python.process.traversal import P class TestTraversal(TestCase): @@ -52,6 +53,13 @@ class TestTraversal(TestCase): assert 1 == len(bytecode.step_instructions[1]) assert 2 == len(bytecode.step_instructions[2]) + def test_P(self): + # verify that the order of operations is respected + assert "and(eq(a),lt(b))" == str(P.eq("a").and_(P.lt("b"))) + assert "and(or(lt(b),gt(c)),neq(d))" == str(P.lt("b").or_(P.gt("c")).and_(P.neq("d"))) + assert "and(or(lt(b),gt(c)),or(neq(d),gte(e)))" == str( + P.lt("b").or_(P.gt("c")).and_(P.neq("d").or_(P.gte("e")))) + if __name__ == '__main__': unittest.main() http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/68ecda40/gremlin-python/src/main/jython/tests/structure/io/test_graphson.py ---------------------------------------------------------------------- diff --git a/gremlin-python/src/main/jython/tests/structure/io/test_graphson.py b/gremlin-python/src/main/jython/tests/structure/io/test_graphson.py index cae1a53..6f244f5 100644 --- a/gremlin-python/src/main/jython/tests/structure/io/test_graphson.py +++ b/gremlin-python/src/main/jython/tests/structure/io/test_graphson.py @@ -27,6 +27,7 @@ from gremlin_python.structure.graph import Vertex from gremlin_python.structure.graph import Path from gremlin_python.structure.io.graphson import GraphSONReader from gremlin_python.structure.io.graphson import GraphSONWriter +from gremlin_python.process.traversal import P class TestGraphSONReader(TestCase): @@ -87,6 +88,10 @@ class TestGraphSONWriter(TestCase): assert """{"@type":"g:Float","@value":3.2}""" == GraphSONWriter.writeObject(3.2) assert """true""" == GraphSONWriter.writeObject(True) + def test_P(self): + assert """{"@type":"g:P","@value":{"predicate":"and","value":[{"@type":"g:P","@value":{"predicate":"or","value":[{"@type":"g:P","@value":{"predicate":"lt","value":"b"}},{"@type":"g:P","@value":{"predicate":"gt","value":"c"}}]}},{"@type":"g:P","@value":{"predicate":"neq","value":"d"}}]}}""" == GraphSONWriter.writeObject( + P.lt("b").or_(P.gt("c")).and_(P.neq("d"))) + if __name__ == '__main__': unittest.main() http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/68ecda40/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/structure/io/graphson/GraphSONWriterTest.java ---------------------------------------------------------------------- diff --git a/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/structure/io/graphson/GraphSONWriterTest.java b/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/structure/io/graphson/GraphSONWriterTest.java index 0e0bcb3..0ef3158 100644 --- a/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/structure/io/graphson/GraphSONWriterTest.java +++ b/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/structure/io/graphson/GraphSONWriterTest.java @@ -91,7 +91,7 @@ public class GraphSONWriterTest { public void shouldSerializeBytecode() throws Exception { assertEquals(P.eq(7L), mapper.readValue(jythonEngine.eval("GraphSONWriter.writeObject(P.eq(7L))").toString(), Object.class)); // TODO: assertEquals(mapper.writeValueAsString(P.between(1, 2).and(P.eq(7L))), jythonEngine.eval("GraphSONWriter.writeObject(P.eq(7L)._and(P.between(1,2)))").toString().replace(" ","")); - assertEquals(AndP.class, mapper.readValue(jythonEngine.eval("GraphSONWriter.writeObject(P.eq(7L)._and(P.between(1,2)))").toString(), Object.class).getClass()); + assertEquals(AndP.class, mapper.readValue(jythonEngine.eval("GraphSONWriter.writeObject(P.eq(7L).and_(P.between(1,2)))").toString(), Object.class).getClass()); // assertEquals(new Bytecode.Binding<>("a", 5L), mapper.readValue(jythonEngine.eval("GraphSONWriter.writeObject(Binding('a',5L))").toString(), Object.class)); // http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/68ecda40/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WhereTest.java ---------------------------------------------------------------------- diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WhereTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WhereTest.java index a3ba0cc..03f76b7 100644 --- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WhereTest.java +++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WhereTest.java @@ -21,24 +21,39 @@ package org.apache.tinkerpop.gremlin.process.traversal.step.filter; import org.apache.tinkerpop.gremlin.LoadGraphWith; import org.apache.tinkerpop.gremlin.process.AbstractGremlinProcessTest; import org.apache.tinkerpop.gremlin.process.GremlinProcessRunner; -import org.apache.tinkerpop.gremlin.process.IgnoreEngine; import org.apache.tinkerpop.gremlin.process.traversal.P; import org.apache.tinkerpop.gremlin.process.traversal.Path; import org.apache.tinkerpop.gremlin.process.traversal.Traversal; -import org.apache.tinkerpop.gremlin.process.traversal.TraversalEngine; import org.apache.tinkerpop.gremlin.structure.T; import org.apache.tinkerpop.gremlin.structure.Vertex; import org.junit.Test; import org.junit.runner.RunWith; -import java.util.*; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.MODERN; -import static org.apache.tinkerpop.gremlin.process.traversal.P.*; +import static org.apache.tinkerpop.gremlin.process.traversal.P.eq; +import static org.apache.tinkerpop.gremlin.process.traversal.P.gt; +import static org.apache.tinkerpop.gremlin.process.traversal.P.lt; +import static org.apache.tinkerpop.gremlin.process.traversal.P.neq; import static org.apache.tinkerpop.gremlin.process.traversal.P.not; -import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.*; +import static org.apache.tinkerpop.gremlin.process.traversal.P.within; +import static org.apache.tinkerpop.gremlin.process.traversal.P.without; +import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.and; +import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.as; +import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.bothE; +import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.in; import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.not; -import static org.junit.Assert.*; +import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.or; +import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.out; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; /** * @author Marko A. Rodriguez (http://markorodriguez.com) @@ -94,6 +109,14 @@ public abstract class WhereTest extends AbstractGremlinProcessTest { //public abstract Traversal<Vertex, String> get_g_V_asXaX_outXknowsX_asXbX_whereXasXa__bX_outXcreatedX_hasXname__rippleX_name(); + // where()-by + + public abstract Traversal<Vertex, Map<String, String>> get_g_V_asXaX_outXcreatedX_inXcreatedX_asXbX_whereXa_gtXbXX_byXageX_selectXa_bX_byXnameX(); + + public abstract Traversal<Vertex, Map<String, String>> get_g_V_asXaX_outEXcreatedX_asXbX_inV_asXcX_whereXa_gtXbX_orXeqXbXXX_byXageX_byXweightX_byXweightX_selectXa_cX_byXnameX(); + + public abstract Traversal<Vertex, Map<String, String>> get_g_V_asXaX_outEXcreatedX_asXbX_inV_asXcX_inXcreatedX_asXdX_whereXa_ltXbX_orXgtXcXX_andXneqXdXXX_byXageX_byXweightX_byXinXcreatedX_valuesXageX_minX_selectXa_c_dX(); + @Test @LoadGraphWith(MODERN) public void g_V_hasXageX_asXaX_out_in_hasXageX_asXbX_selectXa_bX_whereXa_eqXbXX() { @@ -317,28 +340,64 @@ public abstract class WhereTest extends AbstractGremlinProcessTest { "a", convertToVertex(graph, "josh"), "b", convertToVertex(graph, "lop")), traversal); } + @Test + @LoadGraphWith(MODERN) + public void g_V_asXaX_outXcreatedX_inXcreatedX_asXbX_whereXa_gtXbXX_byXageX_selectXa_bX_byXnameX() { + final Traversal<Vertex, Map<String, String>> traversal = get_g_V_asXaX_outXcreatedX_inXcreatedX_asXbX_whereXa_gtXbXX_byXageX_selectXa_bX_byXnameX(); + printTraversalForm(traversal); + checkResults(makeMapList(2, + "a", "peter", "b", "josh", + "a", "peter", "b", "marko", + "a", "josh", "b", "marko"), traversal); + } + + @Test + @LoadGraphWith(MODERN) + public void g_V_asXaX_outEXcreatedX_asXbX_inV_asXcX_whereXa_gtXbX_orXeqXbXXX_byXageX_byXweightX_byXweightX_selectXa_cX_byXnameX() { + final Traversal<Vertex, Map<String, String>> traversal = get_g_V_asXaX_outEXcreatedX_asXbX_inV_asXcX_whereXa_gtXbX_orXeqXbXXX_byXageX_byXweightX_byXweightX_selectXa_cX_byXnameX(); + printTraversalForm(traversal); + checkResults(makeMapList(2, + "a", "peter", "c", "lop", + "a", "josh", "c", "lop", + "a", "josh", "c", "ripple", + "a", "marko", "c", "lop"), traversal); + } + + @Test + @LoadGraphWith(MODERN) + public void g_V_asXaX_outEXcreatedX_asXbX_inV_asXcX_inXcreatedX_asXdX_whereXa_ltXbX_orXgtXcXX_andXneqXdXXX_byXageX_byXweightX_byXinXcreatedX_valuesXageX_minX_selectXa_c_dX() { + final Traversal<Vertex, Map<String, String>> traversal = get_g_V_asXaX_outEXcreatedX_asXbX_inV_asXcX_inXcreatedX_asXdX_whereXa_ltXbX_orXgtXcXX_andXneqXdXXX_byXageX_byXweightX_byXinXcreatedX_valuesXageX_minX_selectXa_c_dX(); + printTraversalForm(traversal); + checkResults(makeMapList(3, + "a", "peter", "c", "lop", "d", "josh", + "a", "peter", "c", "lop", "d", "marko", + "a", "josh", "c", "lop", "d", "marko", + "a", "josh", "c", "lop", "d", "peter"), traversal); + } + + public static class Traversals extends WhereTest { /// where(local) @Override public Traversal<Vertex, Map<String, Object>> get_g_V_hasXageX_asXaX_out_in_hasXageX_asXbX_selectXa_bX_whereXa_eqXbXX() { - return g.V().has("age").as("a").out().in().has("age").as("b").select("a","b").where("a", eq("b")); + return g.V().has("age").as("a").out().in().has("age").as("b").select("a", "b").where("a", eq("b")); } @Override public Traversal<Vertex, Map<String, Object>> get_g_V_hasXageX_asXaX_out_in_hasXageX_asXbX_selectXa_bX_whereXa_neqXbXX() { - return g.V().has("age").as("a").out().in().has("age").as("b").select("a","b").where("a", neq("b")); + return g.V().has("age").as("a").out().in().has("age").as("b").select("a", "b").where("a", neq("b")); } @Override public Traversal<Vertex, Map<String, Object>> get_g_V_hasXageX_asXaX_out_in_hasXageX_asXbX_selectXa_bX_whereXb_hasXname_markoXX() { - return g.V().has("age").as("a").out().in().has("age").as("b").select("a","b").where(as("b").has("name", "marko")); + return g.V().has("age").as("a").out().in().has("age").as("b").select("a", "b").where(as("b").has("name", "marko")); } @Override public Traversal<Vertex, Map<String, Object>> get_g_V_hasXageX_asXaX_out_in_hasXageX_asXbX_selectXa_bX_whereXa_outXknowsX_bX() { - return g.V().has("age").as("a").out().in().has("age").as("b").select("a","b").where(as("a").out("knows").as("b")); + return g.V().has("age").as("a").out().in().has("age").as("b").select("a", "b").where(as("a").out("knows").as("b")); } /// where(global) @@ -391,7 +450,7 @@ public abstract class WhereTest extends AbstractGremlinProcessTest { @Override public Traversal<Vertex, Map<String, Object>> get_g_V_asXaX_out_asXbX_whereXandXasXaX_outXknowsX_asXbX__orXasXbX_outXcreatedX_hasXname_rippleX__asXbX_inXknowsX_count_isXnotXeqX0XXXXX_selectXa_bX() { - return g.V().as("a").out().as("b").where(and(as("a").out("knows").as("b"), or(as("b").out("created").has("name", "ripple"), as("b").in("knows").count().is(not(eq(0)))))).select("a","b"); + return g.V().as("a").out().as("b").where(and(as("a").out("knows").as("b"), or(as("b").out("created").has("name", "ripple"), as("b").in("knows").count().is(not(eq(0)))))).select("a", "b"); } @Override @@ -401,17 +460,34 @@ public abstract class WhereTest extends AbstractGremlinProcessTest { @Override public Traversal<Vertex, Map<String, Object>> get_g_V_asXaX_outXcreatedX_asXbX_whereXandXasXbX_in__notXasXaX_outXcreatedX_hasXname_rippleXXX_selectXa_bX() { - return g.V().as("a").out("created").as("b").where(and(as("b").in(), not(as("a").out("created").has("name", "ripple")))).select("a","b"); + return g.V().as("a").out("created").as("b").where(and(as("b").in(), not(as("a").out("created").has("name", "ripple")))).select("a", "b"); } @Override public Traversal<Vertex, Map<String, Object>> get_g_V_asXaX_outXcreatedX_asXbX_inXcreatedX_asXcX_bothXknowsX_bothXknowsX_asXdX_whereXc__notXeqXaX_orXeqXdXXXX_selectXa_b_c_dX() { - return g.V().as("a").out("created").as("b").in("created").as("c").both("knows").both("knows").as("d").where("c", P.not(P.eq("a").or(P.eq("d")))).select("a","b","c","d"); + return g.V().as("a").out("created").as("b").in("created").as("c").both("knows").both("knows").as("d").where("c", P.not(P.eq("a").or(P.eq("d")))).select("a", "b", "c", "d"); } @Override public Traversal<Vertex, Map<String, Object>> get_g_V_asXaX_out_asXbX_whereXin_count_isXeqX3XX_or_whereXoutXcreatedX_and_hasXlabel_personXXX_selectXa_bX() { - return g.V().as("a").out().as("b").where(as("b").in().count().is(eq(3)).or().where(as("b").out("created").and().as("b").has(T.label, "person"))).select("a","b"); + return g.V().as("a").out().as("b").where(as("b").in().count().is(eq(3)).or().where(as("b").out("created").and().as("b").has(T.label, "person"))).select("a", "b"); + } + + // where()-by + + @Override + public Traversal<Vertex, Map<String, String>> get_g_V_asXaX_outXcreatedX_inXcreatedX_asXbX_whereXa_gtXbXX_byXageX_selectXa_bX_byXnameX() { + return g.V().as("a").out("created").in("created").as("b").where("a", gt("b")).by("age").<String>select("a", "b").by("name"); + } + + @Override + public Traversal<Vertex, Map<String, String>> get_g_V_asXaX_outEXcreatedX_asXbX_inV_asXcX_whereXa_gtXbX_orXeqXbXXX_byXageX_byXweightX_byXweightX_selectXa_cX_byXnameX() { + return g.V().as("a").outE("created").as("b").inV().as("c").where("a", gt("b").or(eq("b"))).by("age").by("weight").by("weight").<String>select("a", "c").by("name"); + } + + @Override + public Traversal<Vertex, Map<String, String>> get_g_V_asXaX_outEXcreatedX_asXbX_inV_asXcX_inXcreatedX_asXdX_whereXa_ltXbX_orXgtXcXX_andXneqXdXXX_byXageX_byXweightX_byXinXcreatedX_valuesXageX_minX_selectXa_c_dX() { + return g.V().as("a").outE("created").as("b").inV().as("c").in("created").as("d").where("a", lt("b").or(gt("c")).and(neq("d"))).by("age").by("weight").by(in("created").values("age").min()).<String>select("a", "c", "d").by("name"); } } } \ No newline at end of file