sorry for the late tweak. Here is the thing. With then new Bindings model, you don't need withBindings() in Gremlin-Java. And, moreoever, it was never used in Gremlin-Python (or any script-based GLV). Thus, its pointless. Deprecated it. Updated the docs accordingly. Also added more test cases to BytecodeTest and test_traversal.py to ensure that both Gremlin-Java bindings and Gremlin-Python bindings have the same look and feel to the user.
Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/987e6ab4 Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/987e6ab4 Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/987e6ab4 Branch: refs/heads/TINKERPOP-1562 Commit: 987e6ab4f2ca643a5eb181f4b52417bf9814fcbd Parents: b70ba90 Author: Marko A. Rodriguez <okramma...@gmail.com> Authored: Wed Nov 30 10:14:01 2016 -0700 Committer: Marko A. Rodriguez <okramma...@gmail.com> Committed: Wed Nov 30 10:14:01 2016 -0700 ---------------------------------------------------------------------- CHANGELOG.asciidoc | 1 + .../src/reference/gremlin-applications.asciidoc | 6 +-- docs/src/reference/gremlin-variants.asciidoc | 5 --- .../gremlin-language-variants/index.asciidoc | 3 -- .../gremlin/process/traversal/Bindings.java | 41 ++++++++++++++------ .../gremlin/process/traversal/Bytecode.java | 10 ++--- .../process/traversal/TraversalSource.java | 7 ++-- .../dsl/graph/GraphTraversalSource.java | 4 +- .../gremlin/process/traversal/BytecodeTest.java | 8 ++-- .../python/GraphTraversalSourceGenerator.groovy | 2 - .../python/TraversalSourceGenerator.groovy | 6 +++ .../gremlin_python/process/graph_traversal.py | 2 - .../jython/gremlin_python/process/traversal.py | 6 +++ .../main/jython/tests/process/test_traversal.py | 13 +++++++ 14 files changed, 72 insertions(+), 42 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/987e6ab4/CHANGELOG.asciidoc ---------------------------------------------------------------------- diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index 10a0604..237b7ce 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -26,6 +26,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima TinkerPop 3.2.4 (Release Date: NOT OFFICIALLY RELEASED YET) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +* Deprecated `TraversalSource.withBindings()` as it is no longer needed in Gremlin-Java and never was needed for other variants. * Fixed a bug in Gremlin-Java `Bytecode` where anonymous traversals were not aware of parent bindings. * Fixed a bug in Gremlin-Java GraphSON deserialization around `P.within()` and `P.without()`. * Converted Spark process suite tests to "integration" tests. http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/987e6ab4/docs/src/reference/gremlin-applications.asciidoc ---------------------------------------------------------------------- diff --git a/docs/src/reference/gremlin-applications.asciidoc b/docs/src/reference/gremlin-applications.asciidoc index c452a0f..f7ba2b5 100644 --- a/docs/src/reference/gremlin-applications.asciidoc +++ b/docs/src/reference/gremlin-applications.asciidoc @@ -939,13 +939,13 @@ times and sizing) can be done in the Gremlin Server configuration file as descri Finally, Gremlin `Bytecode` supports the encoding of bindings which allow GremlinServer to cache traversals that will be reused over and over again save that some parameterization may change. Thus, instead of translating, compiling, and then executing each submitted bytecode, it is possible to simply execute. To express bindings in Gremlin-Java and -Gremlin-Groovy, use the `withBindings()` traversal source method. +Gremlin-Groovy, use `Bindings`. [gremlin-groovy] ---- cluster = Cluster.open('conf/remote-objects.yaml') -b = new Bindings() -g = EmptyGraph.instance().traversal().withBindings(b).withRemote(DriverRemoteConnection.using(cluster, "g")) +b = Bindings.instance() +g = EmptyGraph.instance().traversal().withRemote(DriverRemoteConnection.using(cluster, "g")) g.V(b.of('id',1)).out('created').values('name') g.V(b.of('id',4)).out('created').values('name') g.V(b.of('id',4)).out('created').values('name').getBytecode() http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/987e6ab4/docs/src/reference/gremlin-variants.asciidoc ---------------------------------------------------------------------- diff --git a/docs/src/reference/gremlin-variants.asciidoc b/docs/src/reference/gremlin-variants.asciidoc index 853b087..39b5558 100644 --- a/docs/src/reference/gremlin-variants.asciidoc +++ b/docs/src/reference/gremlin-variants.asciidoc @@ -265,11 +265,6 @@ g.V(('id',1)).out('created').name.toList() g.V(('id',4)).out('created').name.toList() ---- -NOTE: The Gremlin `withBindings()` traversal source step is not needed. Typically `withBindings()` is only required -in statically typed languages where bindings need to have the same typing as the `Traversal` API. However, if desired, -it is possible to use the `withBindings()`-model as Gremlin-Python's `Bindings.of()` simply returns a 2-tuple of `(str,object)` -(see <<connecting-via-remotegraph,`Bindings`>>). - Traversal Strategies ~~~~~~~~~~~~~~~~~~~~ http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/987e6ab4/docs/src/tutorials/gremlin-language-variants/index.asciidoc ---------------------------------------------------------------------- diff --git a/docs/src/tutorials/gremlin-language-variants/index.asciidoc b/docs/src/tutorials/gremlin-language-variants/index.asciidoc index 533aa04..abd402b 100644 --- a/docs/src/tutorials/gremlin-language-variants/index.asciidoc +++ b/docs/src/tutorials/gremlin-language-variants/index.asciidoc @@ -346,7 +346,6 @@ class GraphTraversalSourceGenerator { findAll { GraphTraversalSource.class.equals(it.returnType) }. findAll { !it.name.equals("clone") && - !it.name.equals(TraversalSource.Symbols.withBindings) && !it.name.equals(TraversalSource.Symbols.withRemote) }. collect { SymbolHelper.toPython(it.name) }. @@ -365,8 +364,6 @@ class GraphTraversalSourceGenerator { source = GraphTraversalSource(self.graph, TraversalStrategies(self.traversal_strategies), Bytecode(self.bytecode)) source.traversal_strategies.add_strategies([RemoteStrategy(remote_connection)]) return source - def withBindings(self, bindings): - return self """) GraphTraversalSource.getMethods(). // SPAWN STEPS findAll { GraphTraversal.class.equals(it.returnType) }. http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/987e6ab4/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Bindings.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Bindings.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Bindings.java index 3359942..d399bb2 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Bindings.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Bindings.java @@ -19,7 +19,6 @@ package org.apache.tinkerpop.gremlin.process.traversal; -import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -30,8 +29,8 @@ import java.util.Map; * For instance: * <p> * <code> - * b = new Bindings() - * g = graph.traversal().withBindings(b) + * b = Bindings.instance() + * g = graph.traversal() * g.V().out(b.of("a","knows")) * // bindings can be reused over and over * g.V().out("knows").in(b.of("a","created")) @@ -42,26 +41,44 @@ import java.util.Map; */ public final class Bindings { + private static final Bindings INSTANCE = new Bindings(); private static final ThreadLocal<Map<Object, String>> MAP = new ThreadLocal<>(); + /** + * @deprecated Since 3.2.4. Instead, use {@link Bindings#instance()}. + */ + @Deprecated + public Bindings() { + + } + public <V> V of(final String variable, final V value) { - if (null == MAP.get()) - MAP.set(new HashMap<>()); - MAP.get().put(value, variable); + Map<Object, String> map = MAP.get(); + if (null == map) { + map = new HashMap<>(); + MAP.set(map); + } + map.put(value, variable); return value; } - protected <V> String getBoundVariable(final V value) { - return null == MAP.get() ? null : MAP.get().get(value); + protected static <V> String getBoundVariable(final V value) { + final Map<Object, String> map = MAP.get(); + return null == map ? null : map.get(value); + } + + protected static void clear() { + final Map<Object, String> map = MAP.get(); + if (null != map) + map.clear(); } - protected void clear() { - if (null != MAP.get()) - MAP.get().clear(); + public static Bindings instance() { + return INSTANCE; } @Override public String toString() { - return null == MAP.get() ? Collections.emptyMap().toString() : MAP.get().toString(); + return "bindings[" + Thread.currentThread().getName() + "]"; } } http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/987e6ab4/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Bytecode.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Bytecode.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Bytecode.java index 11f6341..7ea5f6f 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Bytecode.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Bytecode.java @@ -52,7 +52,6 @@ public final class Bytecode implements Cloneable, Serializable { private List<Instruction> sourceInstructions = new ArrayList<>(); private List<Instruction> stepInstructions = new ArrayList<>(); - private final transient Bindings bindings = new Bindings(); /** * Add a {@link TraversalSource} instruction to the bytecode. @@ -69,10 +68,9 @@ public final class Bytecode implements Cloneable, Serializable { (Class) arguments[i]; } this.sourceInstructions.add(new Instruction(sourceName, classes)); - } else if (!sourceName.equals(TraversalSource.Symbols.withBindings)) { + } else this.sourceInstructions.add(new Instruction(sourceName, flattenArguments(arguments))); - } - this.bindings.clear(); + Bindings.clear(); } /** @@ -83,7 +81,7 @@ public final class Bytecode implements Cloneable, Serializable { */ public void addStep(final String stepName, final Object... arguments) { this.stepInstructions.add(new Instruction(stepName, flattenArguments(arguments))); - this.bindings.clear(); + Bindings.clear(); } /** @@ -271,7 +269,7 @@ public final class Bytecode implements Cloneable, Serializable { private final Object convertArgument(final Object argument, final boolean searchBindings) { if (searchBindings) { - final String variable = this.bindings.getBoundVariable(argument); + final String variable = Bindings.getBoundVariable(argument); if (null != variable) return new Binding<>(variable, convertArgument(argument, false)); } http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/987e6ab4/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalSource.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalSource.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalSource.java index df1d89a..32c034a 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalSource.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalSource.java @@ -84,6 +84,7 @@ public interface TraversalSource extends Cloneable, AutoCloseable { // static fields only } + @Deprecated public static final String withBindings = "withBindings"; public static final String withSack = "withSack"; public static final String withStrategies = "withStrategies"; @@ -133,11 +134,11 @@ public interface TraversalSource extends Cloneable, AutoCloseable { * * @param bindings the bindings instance to use * @return a new traversal source with set bindings + * @deprecated Since 3.2.4, simply use {@link Bindings} without reference to a {@link TraversalSource}. */ + @Deprecated public default TraversalSource withBindings(final Bindings bindings) { - final TraversalSource clone = this.clone(); - clone.getBytecode().addSource(Symbols.withBindings, bindings); - return clone; + return this; } /** http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/987e6ab4/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSource.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSource.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSource.java index 362c571..af78add 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSource.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSource.java @@ -45,7 +45,6 @@ import org.apache.tinkerpop.gremlin.structure.util.StringFactory; import java.util.ArrayList; import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.function.BinaryOperator; import java.util.function.Supplier; @@ -134,10 +133,11 @@ public class GraphTraversalSource implements TraversalSource { } @Override + @Deprecated public GraphTraversalSource withBindings(final Bindings bindings) { return (GraphTraversalSource) TraversalSource.super.withBindings(bindings); } - + @Override public GraphTraversalSource withComputer(final Computer computer) { return (GraphTraversalSource) TraversalSource.super.withComputer(computer); http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/987e6ab4/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/BytecodeTest.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/BytecodeTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/BytecodeTest.java index ea81bdc..e1a31c4 100644 --- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/BytecodeTest.java +++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/BytecodeTest.java @@ -82,8 +82,8 @@ public class BytecodeTest { @Test public void shouldIncludeBindingsInEquality() { - final Bindings b = new Bindings(); - final GraphTraversalSource g = EmptyGraph.instance().traversal().withBindings(b); + final Bindings b = Bindings.instance(); + final GraphTraversalSource g = EmptyGraph.instance().traversal(); final Bytecode bytecode1 = g.V().out(b.of("a", "created")).asAdmin().getBytecode(); final Bytecode bytecode2 = g.V().out(b.of("a", "knows")).asAdmin().getBytecode(); @@ -103,8 +103,8 @@ public class BytecodeTest { @Test public void shouldIncludeBindingsInNestedTraversals() { - final Bindings b = new Bindings(); - final GraphTraversalSource g = EmptyGraph.instance().traversal().withBindings(b); + final Bindings b = Bindings.instance(); + final GraphTraversalSource g = EmptyGraph.instance().traversal(); final Bytecode bytecode = g.V().in(b.of("a","created")).where(__.out(b.of("b","knows")).has("age",b.of("c",P.gt(32))).map(__.values(b.of("d","name")))).asAdmin().getBytecode(); assertEquals(4, bytecode.getBindings().size()); assertEquals("created", bytecode.getBindings().get("a")); http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/987e6ab4/gremlin-python/src/main/groovy/org/apache/tinkerpop/gremlin/python/GraphTraversalSourceGenerator.groovy ---------------------------------------------------------------------- diff --git a/gremlin-python/src/main/groovy/org/apache/tinkerpop/gremlin/python/GraphTraversalSourceGenerator.groovy b/gremlin-python/src/main/groovy/org/apache/tinkerpop/gremlin/python/GraphTraversalSourceGenerator.groovy index ed377bd..0d36581 100644 --- a/gremlin-python/src/main/groovy/org/apache/tinkerpop/gremlin/python/GraphTraversalSourceGenerator.groovy +++ b/gremlin-python/src/main/groovy/org/apache/tinkerpop/gremlin/python/GraphTraversalSourceGenerator.groovy @@ -102,8 +102,6 @@ under the License. source = GraphTraversalSource(self.graph, TraversalStrategies(self.traversal_strategies), Bytecode(self.bytecode)) source.traversal_strategies.add_strategies([RemoteStrategy(remote_connection)]) return source - def withBindings(self, bindings): - return self def withComputer(self,graph_computer=None, workers=None, result=None, persist=None, vertices=None, edges=None, configuration=None): return self.withStrategies(VertexProgramStrategy(graph_computer,workers,result,persist,vertices,edges,configuration)) """) http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/987e6ab4/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 a3684cb..b6f25e3 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 @@ -310,6 +310,12 @@ class Binding(object): def __init__(self,key,value): self.key = key self.value = value + def __eq__(self, other): + return isinstance(other, self.__class__) and self.key == other.key and self.value == other.value + def __hash__(self): + return hash(self.key) + hash(self.value) + def __repr__(self): + return "binding[" + self.key + "=" + str(self.value) + "]" """) ////////////// http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/987e6ab4/gremlin-python/src/main/jython/gremlin_python/process/graph_traversal.py ---------------------------------------------------------------------- diff --git a/gremlin-python/src/main/jython/gremlin_python/process/graph_traversal.py b/gremlin-python/src/main/jython/gremlin_python/process/graph_traversal.py index 6165ed3..ceb4cb4 100644 --- a/gremlin-python/src/main/jython/gremlin_python/process/graph_traversal.py +++ b/gremlin-python/src/main/jython/gremlin_python/process/graph_traversal.py @@ -62,8 +62,6 @@ class GraphTraversalSource(object): source = GraphTraversalSource(self.graph, TraversalStrategies(self.traversal_strategies), Bytecode(self.bytecode)) source.traversal_strategies.add_strategies([RemoteStrategy(remote_connection)]) return source - def withBindings(self, bindings): - return self def withComputer(self,graph_computer=None, workers=None, result=None, persist=None, vertices=None, edges=None, configuration=None): return self.withStrategies(VertexProgramStrategy(graph_computer,workers,result,persist,vertices,edges,configuration)) def E(self, *args): http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/987e6ab4/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 d30db35..a7b6118 100644 --- a/gremlin-python/src/main/jython/gremlin_python/process/traversal.py +++ b/gremlin-python/src/main/jython/gremlin_python/process/traversal.py @@ -373,4 +373,10 @@ class Binding(object): def __init__(self,key,value): self.key = key self.value = value + def __eq__(self, other): + return isinstance(other, self.__class__) and self.key == other.key and self.value == other.value + def __hash__(self): + return hash(self.key) + hash(self.value) + def __repr__(self): + return "binding[" + self.key + "=" + str(self.value) + "]" http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/987e6ab4/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 0f25190..e68b1e2 100644 --- a/gremlin-python/src/main/jython/tests/process/test_traversal.py +++ b/gremlin-python/src/main/jython/tests/process/test_traversal.py @@ -24,6 +24,8 @@ from unittest import TestCase from gremlin_python.structure.graph import Graph from gremlin_python.process.traversal import P +from gremlin_python.process.traversal import Binding +from gremlin_python.process.graph_traversal import __ class TestTraversal(TestCase): @@ -52,6 +54,17 @@ class TestTraversal(TestCase): assert 1 == len(bytecode.step_instructions[0]) assert 1 == len(bytecode.step_instructions[1]) assert 2 == len(bytecode.step_instructions[2]) + ## + bytecode = g.V(('a',[1,2,3])).out(('b','created')).where(__.in_(('c','created'),('d','knows')).count().is_(('e',P.gt(2)))).bytecode + assert 5 == len(bytecode.bindings.keys()) + assert [1,2,3] == bytecode.bindings['a'] + assert 'created' == bytecode.bindings['b'] + assert 'created' == bytecode.bindings['c'] + assert 'knows' == bytecode.bindings['d'] + assert P.gt(2) == bytecode.bindings['e'] + assert Binding('b','created') == bytecode.step_instructions[1][1] + assert 'binding[b=created]' == str(bytecode.step_instructions[1][1]) + assert isinstance(hash(bytecode.step_instructions[1][1]),int) def test_P(self): # verify that the order of operations is respected