You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by sp...@apache.org on 2018/10/03 20:10:05 UTC
[1/9] tinkerpop git commit: TINKERPOP-2040 Updated changelog
Repository: tinkerpop
Updated Branches:
refs/heads/master 21d2444c6 -> 2ae8c5bec
TINKERPOP-2040 Updated changelog
Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/92c74c3d
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/92c74c3d
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/92c74c3d
Branch: refs/heads/master
Commit: 92c74c3d7ffc25b234187ef2459f8d3d529ac8db
Parents: e5c2e9c
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Mon Oct 1 09:12:30 2018 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Mon Oct 1 16:18:28 2018 -0400
----------------------------------------------------------------------
CHANGELOG.asciidoc | 2 ++
1 file changed, 2 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/92c74c3d/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 6d9770f..9160d09 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -37,6 +37,8 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
* Added synchronized `Map` to Gryo 1.0 registrations.
* Added `Triple` to Gryo 1.0 registrations.
* Improved escaping of special characters in strings passed to the `GroovyTranslator`.
+* Improved ability of `GroovyTranslator` to handle more types supported by GraphSON.
+* Improved ability of `GroovyTranslator` to handle custom types.
* Added better internal processing of `Column` in `by(Function)`.
* Added `hasNext()` support on `Traversal` for `gremlin-python`.
* Added support for additional extended types in Gremlin.Net with `decimal`, `TimeSpan`, `BigInteger`, `byte`, `byte[]`, `char` and `short`.
[8/9] tinkerpop git commit: Merge branch 'tp32' into tp33
Posted by sp...@apache.org.
Merge branch 'tp32' into tp33
Conflicts:
gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngine.java
gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslatorTest.java
Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/2b4c993d
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/2b4c993d
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/2b4c993d
Branch: refs/heads/master
Commit: 2b4c993ddd16a45545555858d480103952374897
Parents: 1faf762 88d6f77
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Wed Oct 3 16:09:06 2018 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Wed Oct 3 16:09:06 2018 -0400
----------------------------------------------------------------------
CHANGELOG.asciidoc | 2 +
.../gremlin/jsr223/TranslatorCustomizer.java | 38 ++++
.../gremlin/process/traversal/Translator.java | 34 +++
.../jsr223/GremlinGroovyScriptEngine.java | 11 +-
.../gremlin/groovy/jsr223/GroovyTranslator.java | 34 ++-
.../groovy/jsr223/GroovyTranslatorTest.java | 215 +++++++++++++++++--
6 files changed, 309 insertions(+), 25 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/2b4c993d/CHANGELOG.asciidoc
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/2b4c993d/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngine.java
----------------------------------------------------------------------
diff --cc gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngine.java
index 03ea883,b96b8b9..7785da6
--- a/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngine.java
+++ b/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngine.java
@@@ -222,19 -236,27 +224,20 @@@ public class GremlinGroovyScriptEngine
private final ImportGroovyCustomizer importGroovyCustomizer;
private final List<GroovyCustomizer> groovyCustomizers;
- private final Set<Artifact> artifactsToUse = new HashSet<>();
private final boolean interpreterModeEnabled;
private final long expectedCompilationTime;
+ private final Translator.ScriptTranslator.TypeTranslator typeTranslator;
/**
- * Creates a new instance using the {@link DefaultImportCustomizerProvider}.
+ * There is no need to require type checking infrastructure if type checking is not enabled.
*/
- public GremlinGroovyScriptEngine() {
- this(new Customizer[0]);
- }
+ private final boolean typeCheckingEnabled;
/**
- * @deprecated As of release 3.0.1, replaced by {@link #GremlinGroovyScriptEngine(CompilerCustomizerProvider...)}
+ * Creates a new instance using no {@link Customizer}.
*/
- @Deprecated
- public GremlinGroovyScriptEngine(final ImportCustomizerProvider importCustomizerProvider) {
- this((CompilerCustomizerProvider) importCustomizerProvider);
+ public GremlinGroovyScriptEngine() {
+ this(new Customizer[0]);
}
public GremlinGroovyScriptEngine(final Customizer... customizers) {
@@@ -273,6 -289,58 +276,12 @@@
interpreterModeEnabled = groovyCustomizers.stream()
.anyMatch(p -> p.getClass().equals(InterpreterModeGroovyCustomizer.class));
+ final Optional<TranslatorCustomizer> translatorCustomizer = listOfCustomizers.stream().
+ filter(p -> p instanceof TranslatorCustomizer).
+ map(p -> (TranslatorCustomizer) p).findFirst();
+ typeTranslator = translatorCustomizer.isPresent() ? translatorCustomizer.get().createTypeTranslator() :
+ Translator.ScriptTranslator.TypeTranslator.identity();
+
- // not using the old provider model so set that to empty list so that when createClassLoader is called
- // it knows to use groovyCustomizers instead
- customizerProviders = Collections.emptyList();
-
- createClassLoader();
- }
-
- /**
- * Creates a new instance with the specified {@link CompilerCustomizerProvider} objects.
- *
- * @deprecated As of release 3.2.4, replaced by {@link #GremlinGroovyScriptEngine(Customizer...)}.
- */
- @Deprecated
- public GremlinGroovyScriptEngine(final CompilerCustomizerProvider... compilerCustomizerProviders) {
- final List<CompilerCustomizerProvider> providers = Arrays.asList(compilerCustomizerProviders);
-
- GremlinLoader.load();
-
- importCustomizerProvider = providers.stream()
- .filter(p -> p instanceof ImportCustomizerProvider)
- .map(p -> (ImportCustomizerProvider) p)
- .findFirst().orElse(NoImportCustomizerProvider.INSTANCE);
-
- // determine if interpreter mode should be enabled
- interpreterModeEnabled = providers.stream()
- .anyMatch(p -> p.getClass().equals(InterpreterModeCustomizerProvider.class));
-
- final Optional<CompilationOptionsCustomizerProvider> compilationOptionsCustomizerProvider = providers.stream()
- .filter(p -> p instanceof CompilationOptionsCustomizerProvider)
- .map(p -> (CompilationOptionsCustomizerProvider) p).findFirst();
- expectedCompilationTime = compilationOptionsCustomizerProvider.isPresent() ?
- compilationOptionsCustomizerProvider.get().getExpectedCompilationTime() : 5000;
-
- // remove used providers as the rest will be applied directly
- customizerProviders = providers.stream()
- .filter(p -> p != null && !(p instanceof ImportCustomizerProvider) && !(p instanceof CompilationOptionsCustomizerProvider))
- .collect(Collectors.toList());
-
- // groovy customizers are not used here - set to empty list so that the customizerProviders get used
- // in createClassLoader
- groovyCustomizers = Collections.emptyList();
- importGroovyCustomizer = null;
-
- // TypeTranslator can only be set by a Customizer - use this old deprecated stuff and you're outta luck
- typeTranslator = Translator.ScriptTranslator.TypeTranslator.identity();
-
createClassLoader();
}
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/2b4c993d/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslator.java
----------------------------------------------------------------------
diff --cc gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslator.java
index 8024590,949fcac..717e1bc
--- a/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslator.java
+++ b/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslator.java
@@@ -49,10 -57,14 +56,12 @@@ import java.util.UUID
*/
public final class GroovyTranslator implements Translator.ScriptTranslator {
- private static final boolean IS_TESTING = Boolean.valueOf(System.getProperty("is.testing", "false"));
-
private final String traversalSource;
+ private final TypeTranslator typeTranslator;
- private GroovyTranslator(final String traversalSource) {
+ private GroovyTranslator(final String traversalSource, final TypeTranslator typeTranslator) {
this.traversalSource = traversalSource;
+ this.typeTranslator = typeTranslator;
}
public static final GroovyTranslator of(final String traversalSource) {
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/2b4c993d/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslatorTest.java
----------------------------------------------------------------------
diff --cc gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslatorTest.java
index 057f2f1,0000000..2cbc962
mode 100644,000000..100644
--- a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslatorTest.java
+++ b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslatorTest.java
@@@ -1,226 -1,0 +1,401 @@@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tinkerpop.gremlin.groovy.jsr223;
+
+import org.apache.commons.configuration.MapConfiguration;
++import org.apache.tinkerpop.gremlin.AbstractGremlinTest;
++import org.apache.tinkerpop.gremlin.jsr223.TranslatorCustomizer;
++import org.apache.tinkerpop.gremlin.process.traversal.Order;
++import org.apache.tinkerpop.gremlin.process.traversal.Pop;
++import org.apache.tinkerpop.gremlin.process.traversal.Scope;
++import org.apache.tinkerpop.gremlin.process.traversal.Translator;
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+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.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SubgraphStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.TranslationStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy;
++import org.apache.tinkerpop.gremlin.structure.Column;
++import org.apache.tinkerpop.gremlin.structure.Direction;
+import org.apache.tinkerpop.gremlin.structure.Edge;
++import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
++import org.apache.tinkerpop.gremlin.structure.util.ElementHelper;
+import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedEdge;
+import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex;
+import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerFactory;
+import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph;
+import org.apache.tinkerpop.gremlin.util.function.Lambda;
+import org.junit.Test;
+
+import javax.script.Bindings;
++import javax.script.ScriptException;
+import javax.script.SimpleBindings;
++import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.Arrays;
++import java.util.Calendar;
+import java.util.Collections;
++import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
++import java.util.UUID;
+import java.util.function.Function;
+
++import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
++import static org.junit.Assert.assertNotNull;
++import static org.junit.Assert.assertThat;
++import static org.junit.Assert.fail;
+
+/**
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ */
+public class GroovyTranslatorTest {
+
++ private Graph graph = TinkerGraph.open();
++ private GraphTraversalSource g = graph.traversal();
++ private static final GremlinGroovyScriptEngine engine = new GremlinGroovyScriptEngine();
++
+ @Test
+ public void shouldHandleStrategies() throws Exception {
+ final TinkerGraph graph = TinkerFactory.createModern();
- GraphTraversalSource g = graph.traversal();
- g = g.withStrategies(SubgraphStrategy.create(new MapConfiguration(new HashMap<String, Object>() {{
++ final GraphTraversalSource g = graph.traversal().withStrategies(SubgraphStrategy.create(new MapConfiguration(new HashMap<String, Object>() {{
+ put(SubgraphStrategy.VERTICES, __.has("name", "marko"));
+ }})));
+ final Bindings bindings = new SimpleBindings();
+ bindings.put("g", g);
- Traversal.Admin<Vertex, Object> traversal = new GremlinGroovyScriptEngine().eval(g.V().values("name").asAdmin().getBytecode(), bindings, "g");
++ Traversal.Admin<Vertex, Object> traversal = engine.eval(g.V().values("name").asAdmin().getBytecode(), bindings, "g");
+ assertEquals("marko", traversal.next());
+ assertFalse(traversal.hasNext());
+ //
- traversal = new GremlinGroovyScriptEngine().eval(g.withoutStrategies(SubgraphStrategy.class).V().count().asAdmin().getBytecode(), bindings, "g");
++ traversal = engine.eval(g.withoutStrategies(SubgraphStrategy.class).V().count().asAdmin().getBytecode(), bindings, "g");
+ assertEquals(new Long(6), traversal.next());
+ assertFalse(traversal.hasNext());
+ //
- traversal = new GremlinGroovyScriptEngine().eval(g.withStrategies(SubgraphStrategy.create(new MapConfiguration(new HashMap<String, Object>() {{
++ traversal = engine.eval(g.withStrategies(SubgraphStrategy.create(new MapConfiguration(new HashMap<String, Object>() {{
+ put(SubgraphStrategy.VERTICES, __.has("name", "marko"));
+ }})), ReadOnlyStrategy.instance()).V().values("name").asAdmin().getBytecode(), bindings, "g");
+ assertEquals("marko", traversal.next());
+ assertFalse(traversal.hasNext());
+ }
+
+ @Test
- public void shouldSupportStringSupplierLambdas() throws Exception {
++ public void shouldSupportStringSupplierLambdas() {
+ final TinkerGraph graph = TinkerFactory.createModern();
+ GraphTraversalSource g = graph.traversal();
+ g = g.withStrategies(new TranslationStrategy(g, GroovyTranslator.of("g")));
- GraphTraversal.Admin<Vertex, Integer> t = g.withSideEffect("lengthSum", 0).withSack(1)
++ final GraphTraversal.Admin<Vertex, Integer> t = g.withSideEffect("lengthSum", 0).withSack(1)
+ .V()
+ .filter(Lambda.predicate("it.get().label().equals('person')"))
+ .flatMap(Lambda.function("it.get().vertices(Direction.OUT)"))
+ .map(Lambda.<Traverser<Object>, Integer>function("it.get().value('name').length()"))
+ .sideEffect(Lambda.consumer("{ x -> x.sideEffects(\"lengthSum\", x.<Integer>sideEffects('lengthSum') + x.get()) }"))
+ .order().by(Lambda.comparator("a,b -> a <=> b"))
+ .sack(Lambda.biFunction("{ a,b -> a + b }"))
+ .asAdmin();
+ final List<Integer> sacks = new ArrayList<>();
+ final List<Integer> lengths = new ArrayList<>();
+ while (t.hasNext()) {
+ final Traverser.Admin<Integer> traverser = t.nextTraverser();
+ sacks.add(traverser.sack());
+ lengths.add(traverser.get());
+ }
+ assertFalse(t.hasNext());
+ //
+ assertEquals(6, lengths.size());
+ assertEquals(3, lengths.get(0).intValue());
+ assertEquals(3, lengths.get(1).intValue());
+ assertEquals(3, lengths.get(2).intValue());
+ assertEquals(4, lengths.get(3).intValue());
+ assertEquals(5, lengths.get(4).intValue());
+ assertEquals(6, lengths.get(5).intValue());
+ ///
+ assertEquals(6, sacks.size());
+ assertEquals(4, sacks.get(0).intValue());
+ assertEquals(4, sacks.get(1).intValue());
+ assertEquals(4, sacks.get(2).intValue());
+ assertEquals(5, sacks.get(3).intValue());
+ assertEquals(6, sacks.get(4).intValue());
+ assertEquals(7, sacks.get(5).intValue());
+ //
+ assertEquals(24, t.getSideEffects().<Number>get("lengthSum").intValue());
+
+ final String script = GroovyTranslator.of("g").translate(t.getBytecode());
+ assertEquals("g.withStrategies(org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.TranslationStrategy.instance())" +
+ ".withSideEffect(\"lengthSum\",(int) 0).withSack((int) 1)" +
+ ".V()" +
+ ".filter({it.get().label().equals('person')})" +
+ ".flatMap({it.get().vertices(Direction.OUT)})" +
+ ".map({it.get().value('name').length()})" +
+ ".sideEffect({ x -> x.sideEffects(\"lengthSum\", x.<Integer>sideEffects('lengthSum') + x.get()) })" +
+ ".order().by({a,b -> a <=> b})" +
+ ".sack({ a,b -> a + b })",
+ script);
+ }
+
+ @Test
+ public void shouldHandleMaps() {
+ final TinkerGraph graph = TinkerFactory.createModern();
- GraphTraversalSource g = graph.traversal();
- String script = GroovyTranslator.of("g").translate(g.V().id().is(new LinkedHashMap<Object,Object>() {{
++ final GraphTraversalSource g = graph.traversal();
++ final String script = GroovyTranslator.of("g").translate(g.V().id().is(new LinkedHashMap<Object,Object>() {{
+ put(3, "32");
+ put(Arrays.asList(1, 2, 3.1d), 4);
+ }}).asAdmin().getBytecode());
+ assertEquals("g.V().id().is([((int) 3):(\"32\"),([(int) 1, (int) 2, 3.1d]):((int) 4)])", script);
++ assertThatScriptOk(script, "g", g);
+ }
+
+ @Test
+ public void shouldHandleEmptyMaps() {
+ final TinkerGraph graph = TinkerFactory.createModern();
- final Function identity = new Lambda.OneArgLambda("it.get()", "gremlin-groovy");
+ final GraphTraversalSource g = graph.traversal();
++ final Function identity = new Lambda.OneArgLambda("it.get()", "gremlin-groovy");
+ final String script = GroovyTranslator.of("g").translate(g.inject(Collections.emptyMap()).map(identity).asAdmin().getBytecode());
+ assertEquals("g.inject([]).map({it.get()})", script);
++ assertThatScriptOk(script, "g", g);
++ }
++
++ @Test
++ public void shouldHandleDate() {
++ final Calendar c = Calendar.getInstance();
++ c.set(1975, Calendar.SEPTEMBER, 7);
++ final Date d = c.getTime();
++ assertTranslation(String.format("new java.util.Date(%s)", d.getTime()), d);
++ }
++
++ @Test
++ public void shouldHandleTimestamp() {
++ final Calendar c = Calendar.getInstance();
++ c.set(1975, Calendar.SEPTEMBER, 7);
++ final Timestamp t = new Timestamp(c.getTime().getTime());
++ assertTranslation(String.format("new java.sql.Timestamp(%s)", t.getTime()), t);
++ }
++
++ @Test
++ public void shouldHandleUuid() {
++ final UUID uuid = UUID.fromString("ffffffff-fd49-1e4b-0000-00000d4b8a1d");
++ assertTranslation(String.format("java.util.UUID.fromString('%s')", uuid), uuid);
++ }
++
++ @Test
++ public void shouldHandleColumn() {
++ assertTranslation("Column.keys", Column.keys);
++ }
++
++ @Test
++ public void shouldHandleDirection() {
++ assertTranslation("Direction.BOTH", Direction.BOTH);
++ }
++
++ @Test
++ public void shouldHandleOrder() {
++ assertTranslation("Order.decr", Order.decr);
++ }
++
++ @Test
++ public void shouldHandlePop() {
++ assertTranslation("Pop.last", Pop.last);
++ }
++
++ @Test
++ public void shouldHandleScope() {
++ assertTranslation("Scope.local", Scope.local);
++ }
++
++ @Test
++ public void shouldOverrideDefaultTypeTranslationWithSomethingBonkers() {
++ final TinkerGraph graph = TinkerGraph.open();
++ final GraphTraversalSource g = graph.traversal();
++ final String thingToSuffixAllStringsWith = "-why-would-anyone-do-this";
++ final String script = GroovyTranslator.of("g", x -> x instanceof String ? x + thingToSuffixAllStringsWith : x).
++ translate(g.inject("yyy", "xxx").asAdmin().getBytecode());
++ assertEquals(String.format("g.inject(\"yyy%s\",\"xxx%s\")", thingToSuffixAllStringsWith, thingToSuffixAllStringsWith), script);
++ assertThatScriptOk(script, "g", g);
++ }
++
++ @Test
++ public void shouldIncludeCustomTypeTranslationForSomethingSilly() throws Exception {
++ final TinkerGraph graph = TinkerGraph.open();
++ final SillyClass notSillyEnough = SillyClass.from("not silly enough", 100);
++ final GraphTraversalSource g = graph.traversal();
++
++ // without type translation we get uglinesss
++ final String scriptBad = GroovyTranslator.of("g").
++ translate(g.inject(notSillyEnough).asAdmin().getBytecode());
++ assertEquals(String.format("g.inject(%s)", "not silly enough:100"), scriptBad);
++
++ // with type translation we get valid gremlin
++ final String scriptGood = GroovyTranslator.of("g",
++ x -> x instanceof SillyClass ?
++ new Translator.ScriptTranslator.Handled(String.format("org.apache.tinkerpop.gremlin.groovy.jsr223.GroovyTranslatorTest.SillyClass.from('%s', (int) %s)",
++ ((SillyClass) x).getX(), ((SillyClass) x).getY())) : x).
++ translate(g.inject(notSillyEnough).asAdmin().getBytecode());
++ assertEquals(String.format("g.inject(org.apache.tinkerpop.gremlin.groovy.jsr223.GroovyTranslatorTest.SillyClass.from('%s', (int) %s))", notSillyEnough.getX(), notSillyEnough.getY()), scriptGood);
++ assertThatScriptOk(scriptGood, "g", g);
++
++ final GremlinGroovyScriptEngine customEngine = new GremlinGroovyScriptEngine(new SillyClassTranslatorCustomizer());
++ final Bindings b = new SimpleBindings();
++ b.put("g", g);
++ final Traversal t = customEngine.eval(g.inject(notSillyEnough).asAdmin().getBytecode(), b, "g");
++ final SillyClass sc = (SillyClass) t.next();
++ assertEquals(notSillyEnough.getX(), sc.getX());
++ assertEquals(notSillyEnough.getY(), sc.getY());
++ assertThat(t.hasNext(), is(false));
+ }
+
+ @Test
+ public void shouldHaveValidToString() {
+ assertEquals("translator[h:gremlin-groovy]", GroovyTranslator.of("h").toString());
+ }
+
+ @Test
+ public void shouldEscapeStrings() {
+ final TinkerGraph graph = TinkerFactory.createModern();
+ final GraphTraversalSource g = graph.traversal();
+ final String script = GroovyTranslator.of("g").translate(g.addV("customer")
+ .property("customer_id", 501L)
+ .property("name", "Foo\u0020Bar")
+ .property("age", 25)
+ .property("special", "`~!@#$%^&*()-_=+[{]}\\|;:'\",<.>/?")
+ .asAdmin().getBytecode());
+
+ assertEquals("g.addV(\"customer\")" +
+ ".property(\"customer_id\",501L)" +
+ ".property(\"name\",\"Foo Bar\")" +
+ ".property(\"age\",(int) 25)" +
+ ".property(\"special\",\"\"\"`~!@#\\$%^&*()-_=+[{]}\\\\|;:'\\\",<.>/?\"\"\")",
+ script);
+ }
+
+ @Test
+ public void shouldHandleVertexAndEdge() {
+ final TinkerGraph graph = TinkerFactory.createModern();
+ final GraphTraversalSource g = graph.traversal();
+
+ final Object id1 = "customer:10:foo\u0020bar\u0020\u0024100#90"; // customer:10:foo bar $100#90
+ final Vertex vertex1 = DetachedVertex.build().setLabel("customer").setId(id1)
+ .create();
- final String script1 = GroovyTranslator.of("g").translate(g.V(vertex1).asAdmin().getBytecode());
- assertEquals("g.V(new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex(" +
++ final String script1 = GroovyTranslator.of("g").translate(g.inject(vertex1).asAdmin().getBytecode());
++ assertEquals("g.inject(new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex(" +
+ "\"customer:10:foo bar \\$100#90\"," +
+ "\"customer\", Collections.emptyMap()))",
+ script1);
++ assertThatScriptOk(script1, "g", g);
+
+ final Object id2 = "user:20:foo\\u0020bar\\u005c\\u0022mr\\u005c\\u0022\\u00241000#50"; // user:20:foo\u0020bar\u005c\u0022mr\u005c\u0022\u00241000#50
+ final Vertex vertex2 = DetachedVertex.build().setLabel("user").setId(id2)
+ .create();
- final String script2 = GroovyTranslator.of("g").translate(g.V(vertex2).asAdmin().getBytecode());
- assertEquals("g.V(new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex(" +
++ final String script2 = GroovyTranslator.of("g").translate(g.inject(vertex2).asAdmin().getBytecode());
++ assertEquals("g.inject(new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex(" +
+ "\"user:20:foo\\\\u0020bar\\\\u005c\\\\u0022mr\\\\u005c\\\\u0022\\\\u00241000#50\"," +
+ "\"user\", Collections.emptyMap()))",
+ script2);
++ assertThatScriptOk(script2, "g", g);
+
+ final Object id3 = "knows:30:foo\u0020bar\u0020\u0024100:\\u0020\\u0024500#70";
+ final Edge edge = DetachedEdge.build().setLabel("knows").setId(id3)
+ .setOutV((DetachedVertex) vertex1)
+ .setInV((DetachedVertex) vertex2)
+ .create();
- final String script3 = GroovyTranslator.of("g").translate(g.E(edge).asAdmin().getBytecode());
- assertEquals("g.E(new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedEdge(" +
++ final String script3 = GroovyTranslator.of("g").translate(g.inject(edge).asAdmin().getBytecode());
++ assertEquals("g.inject(new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedEdge(" +
+ "\"knows:30:foo bar \\$100:\\\\u0020\\\\u0024500#70\"," +
+ "\"knows\",Collections.emptyMap()," +
+ "\"customer:10:foo bar \\$100#90\",\"customer\"," +
+ "\"user:20:foo\\\\u0020bar\\\\u005c\\\\u0022mr\\\\u005c\\\\u0022\\\\u00241000#50\",\"user\"))",
+ script3);
++ assertThatScriptOk(script3, "g", g);
+
+ final String script4 = GroovyTranslator.of("g").translate(
+ g.addE("knows").from(vertex1).to(vertex2).property("when", "2018/09/21")
- .asAdmin().getBytecode());
++ .asAdmin().getBytecode());
+ assertEquals("g.addE(\"knows\")" +
- ".from(new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex(\"customer:10:foo bar \\$100#90\",\"customer\", Collections.emptyMap()))" +
- ".to(new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex(\"user:20:foo\\\\u0020bar\\\\u005c\\\\u0022mr\\\\u005c\\\\u0022\\\\u00241000#50\",\"user\", Collections.emptyMap()))" +
- ".property(\"when\",\"2018/09/21\")",
++ ".from(new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex(\"customer:10:foo bar \\$100#90\",\"customer\", Collections.emptyMap()))" +
++ ".to(new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex(\"user:20:foo\\\\u0020bar\\\\u005c\\\\u0022mr\\\\u005c\\\\u0022\\\\u00241000#50\",\"user\", Collections.emptyMap()))" +
++ ".property(\"when\",\"2018/09/21\")",
+ script4);
+ }
+
++ public static Object eval(final String s, final Object... args) throws ScriptException {
++ return engine.eval(s, new SimpleBindings(ElementHelper.asMap(args)));
++ }
++
++ public static Object eval(final String s, final Bindings b) throws ScriptException {
++ return engine.eval(s, b);
++ }
++
++ private void assertTranslation(final String expectedTranslation, final Object... objs) {
++ final String script = GroovyTranslator.of("g").translate(g.inject(objs).asAdmin().getBytecode());
++ assertEquals(String.format("g.inject(%s)", expectedTranslation), script);
++ assertThatScriptOk(script, "g", g);
++ }
++
++ private void assertThatScriptOk(final String s, final Object... args) {
++ try {
++ assertNotNull(eval(s, args));
++ } catch (ScriptException se) {
++ se.printStackTrace();
++ fail("Script should have eval'd");
++ }
++ }
++
++ public static class SillyClass {
++
++ private final String x;
++ private final int y;
++
++ private SillyClass(final String x, final int y) {
++ this.x = x;
++ this.y = y;
++ }
++
++ public static SillyClass from(final String x, final int y) {
++ return new SillyClass(x, y);
++ }
++
++ public String getX() {
++ return x;
++ }
++
++ public int getY() {
++ return y;
++ }
++
++ @Override
++ public String toString() {
++ return x + ":" + String.valueOf(y);
++ }
++ }
++
++ public static class SillyClassTranslatorCustomizer implements TranslatorCustomizer {
++
++ @Override
++ public Translator.ScriptTranslator.TypeTranslator createTypeTranslator() {
++ return x -> x instanceof SillyClass ?
++ new Translator.ScriptTranslator.Handled(String.format("org.apache.tinkerpop.gremlin.groovy.jsr223.GroovyTranslatorTest.SillyClass.from('%s', (int) %s)",
++ ((SillyClass) x).getX(), ((SillyClass) x).getY())) : x;
++ }
++ }
+}
[5/9] tinkerpop git commit: Merge branch 'tp33' of
https://git-wip-us.apache.org/repos/asf/tinkerpop into tp33
Posted by sp...@apache.org.
Merge branch 'tp33' of https://git-wip-us.apache.org/repos/asf/tinkerpop into tp33
Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/1faf7629
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/1faf7629
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/1faf7629
Branch: refs/heads/master
Commit: 1faf7629cb7b3882e91a8f437ad23197aba385dc
Parents: 8ca2778 650f31f
Author: Florian Hockmann <fh...@florian-hockmann.de>
Authored: Wed Oct 3 12:33:02 2018 +0200
Committer: Florian Hockmann <fh...@florian-hockmann.de>
Committed: Wed Oct 3 12:33:02 2018 +0200
----------------------------------------------------------------------
.../traversal/dsl/graph/GraphTraversal.java | 48 ++++++++++++--------
.../step/sideEffect/SideEffectCapStep.java | 4 +-
2 files changed, 30 insertions(+), 22 deletions(-)
----------------------------------------------------------------------
[9/9] tinkerpop git commit: Merge branch 'tp33'
Posted by sp...@apache.org.
Merge branch 'tp33'
Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/2ae8c5be
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/2ae8c5be
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/2ae8c5be
Branch: refs/heads/master
Commit: 2ae8c5becc4318e45d6a48d32ea5e8f3eed451e5
Parents: 21d2444 2b4c993
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Wed Oct 3 16:09:48 2018 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Wed Oct 3 16:09:48 2018 -0400
----------------------------------------------------------------------
CHANGELOG.asciidoc | 2 +
.../gremlin/jsr223/TranslatorCustomizer.java | 38 ++++
.../gremlin/process/traversal/Translator.java | 34 +++
.../jsr223/GremlinGroovyScriptEngine.java | 11 +-
.../gremlin/groovy/jsr223/GroovyTranslator.java | 34 ++-
.../groovy/jsr223/GroovyTranslatorTest.java | 215 +++++++++++++++++--
6 files changed, 309 insertions(+), 25 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/2ae8c5be/CHANGELOG.asciidoc
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/2ae8c5be/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngine.java
----------------------------------------------------------------------
[7/9] tinkerpop git commit: Merge branch 'TINKERPOP-2040' into tp32
Posted by sp...@apache.org.
Merge branch 'TINKERPOP-2040' into tp32
Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/88d6f778
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/88d6f778
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/88d6f778
Branch: refs/heads/master
Commit: 88d6f778694e6c65ddde6fdcc18948327e01914a
Parents: fcbce50 92c74c3
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Wed Oct 3 15:28:58 2018 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Wed Oct 3 15:28:58 2018 -0400
----------------------------------------------------------------------
CHANGELOG.asciidoc | 2 +
.../gremlin/jsr223/TranslatorCustomizer.java | 38 ++++
.../gremlin/process/traversal/Translator.java | 34 +++
.../groovy/jsr223/GroovyTranslatorTest.java | 213 ++++++++++++++++---
.../jsr223/GremlinGroovyScriptEngine.java | 15 +-
.../gremlin/groovy/jsr223/GroovyTranslator.java | 34 ++-
6 files changed, 301 insertions(+), 35 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/88d6f778/CHANGELOG.asciidoc
----------------------------------------------------------------------
[6/9] tinkerpop git commit: Merge branch 'tp32' of
https://git-wip-us.apache.org/repos/asf/tinkerpop into tp32
Posted by sp...@apache.org.
Merge branch 'tp32' of https://git-wip-us.apache.org/repos/asf/tinkerpop into tp32
Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/fcbce509
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/fcbce509
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/fcbce509
Branch: refs/heads/master
Commit: fcbce509fc2957bae74ef585875dd872322a9b21
Parents: b440742 76c9aba
Author: Florian Hockmann <fh...@florian-hockmann.de>
Authored: Wed Oct 3 12:33:23 2018 +0200
Committer: Florian Hockmann <fh...@florian-hockmann.de>
Committed: Wed Oct 3 12:33:23 2018 +0200
----------------------------------------------------------------------
.../traversal/dsl/graph/GraphTraversal.java | 48 ++++++++++++--------
.../step/sideEffect/SideEffectCapStep.java | 4 +-
2 files changed, 30 insertions(+), 22 deletions(-)
----------------------------------------------------------------------
[2/9] tinkerpop git commit: TINKERPOP-2040 Hooked up Customizer for
TypeTranslator
Posted by sp...@apache.org.
TINKERPOP-2040 Hooked up Customizer for TypeTranslator
Enables the Groovy GremlinScriptEngine to use custom TypeTranslators
Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/e5c2e9cd
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/e5c2e9cd
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/e5c2e9cd
Branch: refs/heads/master
Commit: e5c2e9cdc18751e755a21add02a75261c169cf32
Parents: 67e2ee8
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Tue Sep 25 17:29:49 2018 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Mon Oct 1 16:18:28 2018 -0400
----------------------------------------------------------------------
.../gremlin/jsr223/TranslatorCustomizer.java | 38 ++++++++++++++++++++
.../groovy/jsr223/GroovyTranslatorTest.java | 23 +++++++++++-
.../jsr223/GremlinGroovyScriptEngine.java | 15 ++++++--
.../gremlin/groovy/jsr223/GroovyTranslator.java | 8 ++---
4 files changed, 76 insertions(+), 8 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/e5c2e9cd/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/TranslatorCustomizer.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/TranslatorCustomizer.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/TranslatorCustomizer.java
new file mode 100644
index 0000000..4468255
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/TranslatorCustomizer.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.jsr223;
+
+import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
+import org.apache.tinkerpop.gremlin.process.traversal.Translator;
+
+/**
+ * Provides a way to customize and override {@link Bytecode} to script translation. Not all {@link GremlinScriptEngine}
+ * will support this capability as translation is optional.
+ *
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public interface TranslatorCustomizer extends Customizer {
+
+ /**
+ * Construct a {@link Translator.ScriptTranslator.TypeTranslator} that will be used by a
+ * {@link Translator.ScriptTranslator} instance within the {@link GremlinScriptEngine} to translate
+ * {@link Bytecode} to a script.
+ */
+ public Translator.ScriptTranslator.TypeTranslator createTypeTranslator();
+}
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/e5c2e9cd/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslatorTest.java
----------------------------------------------------------------------
diff --git a/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslatorTest.java b/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslatorTest.java
index c224642..1622d3d 100644
--- a/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslatorTest.java
+++ b/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslatorTest.java
@@ -22,6 +22,7 @@ package org.apache.tinkerpop.gremlin.groovy.jsr223;
import org.apache.commons.configuration.MapConfiguration;
import org.apache.tinkerpop.gremlin.AbstractGremlinTest;
import org.apache.tinkerpop.gremlin.LoadGraphWith;
+import org.apache.tinkerpop.gremlin.jsr223.TranslatorCustomizer;
import org.apache.tinkerpop.gremlin.process.traversal.Order;
import org.apache.tinkerpop.gremlin.process.traversal.Pop;
import org.apache.tinkerpop.gremlin.process.traversal.Scope;
@@ -59,9 +60,11 @@ import java.util.List;
import java.util.UUID;
import java.util.function.Function;
+import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
/**
@@ -224,7 +227,7 @@ public class GroovyTranslatorTest extends AbstractGremlinTest {
}
@Test
- public void shouldIncludeCustomTypeTranslationForSomethingSilly() {
+ public void shouldIncludeCustomTypeTranslationForSomethingSilly() throws Exception {
final SillyClass notSillyEnough = SillyClass.from("not silly enough", 100);
final GraphTraversalSource g = graph.traversal();
@@ -241,6 +244,15 @@ public class GroovyTranslatorTest extends AbstractGremlinTest {
translate(g.inject(notSillyEnough).asAdmin().getBytecode());
assertEquals(String.format("g.inject(org.apache.tinkerpop.gremlin.groovy.jsr223.GroovyTranslatorTest.SillyClass.from('%s', (int) %s))", notSillyEnough.getX(), notSillyEnough.getY()), scriptGood);
assertThatScriptOk(scriptGood, "g", g);
+
+ final GremlinGroovyScriptEngine customEngine = new GremlinGroovyScriptEngine(new SillyClassTranslatorCustomizer());
+ final Bindings b = new SimpleBindings();
+ b.put("g", g);
+ final Traversal t = customEngine.eval(g.inject(notSillyEnough).asAdmin().getBytecode(), b, "g");
+ final SillyClass sc = (SillyClass) t.next();
+ assertEquals(notSillyEnough.getX(), sc.getX());
+ assertEquals(notSillyEnough.getY(), sc.getY());
+ assertThat(t.hasNext(), is(false));
}
@Test
@@ -344,4 +356,13 @@ public class GroovyTranslatorTest extends AbstractGremlinTest {
}
}
+ public static class SillyClassTranslatorCustomizer implements TranslatorCustomizer {
+
+ @Override
+ public Translator.ScriptTranslator.TypeTranslator createTypeTranslator() {
+ return x -> x instanceof SillyClass ?
+ new Translator.ScriptTranslator.Handled(String.format("org.apache.tinkerpop.gremlin.groovy.jsr223.GroovyTranslatorTest.SillyClass.from('%s', (int) %s)",
+ ((SillyClass) x).getX(), ((SillyClass) x).getY())) : x;
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/e5c2e9cd/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngine.java
----------------------------------------------------------------------
diff --git a/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngine.java b/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngine.java
index 381dd88..b96b8b9 100644
--- a/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngine.java
+++ b/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngine.java
@@ -30,7 +30,6 @@ import groovy.lang.MissingMethodException;
import groovy.lang.MissingPropertyException;
import groovy.lang.Script;
import groovy.lang.Tuple;
-import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.tinkerpop.gremlin.groovy.CompilerCustomizerProvider;
import org.apache.tinkerpop.gremlin.groovy.DefaultImportCustomizerProvider;
import org.apache.tinkerpop.gremlin.groovy.EmptyImportCustomizerProvider;
@@ -49,7 +48,9 @@ import org.apache.tinkerpop.gremlin.jsr223.GremlinScriptContext;
import org.apache.tinkerpop.gremlin.jsr223.GremlinScriptEngine;
import org.apache.tinkerpop.gremlin.jsr223.GremlinScriptEngineFactory;
import org.apache.tinkerpop.gremlin.jsr223.ImportCustomizer;
+import org.apache.tinkerpop.gremlin.jsr223.TranslatorCustomizer;
import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
+import org.apache.tinkerpop.gremlin.process.traversal.Translator;
import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource;
import org.codehaus.groovy.ast.ClassHelper;
@@ -241,6 +242,7 @@ public class GremlinGroovyScriptEngine extends GroovyScriptEngineImpl
private final Set<Artifact> artifactsToUse = new HashSet<>();
private final boolean interpreterModeEnabled;
private final long expectedCompilationTime;
+ private final Translator.ScriptTranslator.TypeTranslator typeTranslator;
/**
* Creates a new instance using the {@link DefaultImportCustomizerProvider}.
@@ -287,6 +289,12 @@ public class GremlinGroovyScriptEngine extends GroovyScriptEngineImpl
interpreterModeEnabled = groovyCustomizers.stream()
.anyMatch(p -> p.getClass().equals(InterpreterModeGroovyCustomizer.class));
+ final Optional<TranslatorCustomizer> translatorCustomizer = listOfCustomizers.stream().
+ filter(p -> p instanceof TranslatorCustomizer).
+ map(p -> (TranslatorCustomizer) p).findFirst();
+ typeTranslator = translatorCustomizer.isPresent() ? translatorCustomizer.get().createTypeTranslator() :
+ Translator.ScriptTranslator.TypeTranslator.identity();
+
// not using the old provider model so set that to empty list so that when createClassLoader is called
// it knows to use groovyCustomizers instead
customizerProviders = Collections.emptyList();
@@ -330,6 +338,9 @@ public class GremlinGroovyScriptEngine extends GroovyScriptEngineImpl
groovyCustomizers = Collections.emptyList();
importGroovyCustomizer = null;
+ // TypeTranslator can only be set by a Customizer - use this old deprecated stuff and you're outta luck
+ typeTranslator = Translator.ScriptTranslator.TypeTranslator.identity();
+
createClassLoader();
}
@@ -464,7 +475,7 @@ public class GremlinGroovyScriptEngine extends GroovyScriptEngineImpl
inner.putAll(bytecode.getBindings());
inner.put(HIDDEN_G, b);
- return (Traversal.Admin) this.eval(GroovyTranslator.of(HIDDEN_G).translate(bytecode), inner);
+ return (Traversal.Admin) this.eval(GroovyTranslator.of(HIDDEN_G, typeTranslator).translate(bytecode), inner);
}
/**
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/e5c2e9cd/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslator.java
----------------------------------------------------------------------
diff --git a/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslator.java b/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslator.java
index 9cd7791..949fcac 100644
--- a/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslator.java
+++ b/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslator.java
@@ -22,9 +22,7 @@ package org.apache.tinkerpop.gremlin.groovy.jsr223;
import groovy.json.StringEscapeUtils;
import org.apache.commons.configuration.ConfigurationConverter;
import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
-import org.apache.tinkerpop.gremlin.process.traversal.Order;
import org.apache.tinkerpop.gremlin.process.traversal.P;
-import org.apache.tinkerpop.gremlin.process.traversal.Pop;
import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions;
import org.apache.tinkerpop.gremlin.process.traversal.Translator;
import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
@@ -34,8 +32,6 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent
import org.apache.tinkerpop.gremlin.process.traversal.strategy.TraversalStrategyProxy;
import org.apache.tinkerpop.gremlin.process.traversal.util.ConnectiveP;
import org.apache.tinkerpop.gremlin.process.traversal.util.OrP;
-import org.apache.tinkerpop.gremlin.structure.Column;
-import org.apache.tinkerpop.gremlin.structure.Direction;
import org.apache.tinkerpop.gremlin.structure.Edge;
import org.apache.tinkerpop.gremlin.structure.Element;
import org.apache.tinkerpop.gremlin.structure.Vertex;
@@ -52,10 +48,12 @@ import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
-import java.util.function.UnaryOperator;
/**
+ * Converts bytecode to a Groovy string of Gremlin.
+ *
* @author Marko A. Rodriguez (http://markorodriguez.com)
+ * @author Stephen Mallette (http://stephen.genoprime.com)
*/
public final class GroovyTranslator implements Translator.ScriptTranslator {
[3/9] tinkerpop git commit: TINKERPOP-2040 Added more tests to cover
more GraphSON types
Posted by sp...@apache.org.
TINKERPOP-2040 Added more tests to cover more GraphSON types
Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/67e2ee85
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/67e2ee85
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/67e2ee85
Branch: refs/heads/master
Commit: 67e2ee85dd8048ca21a72889cf8a0218f2add081
Parents: 774371d
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Tue Sep 25 13:46:38 2018 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Mon Oct 1 16:18:28 2018 -0400
----------------------------------------------------------------------
.../groovy/jsr223/GroovyTranslatorTest.java | 30 ++++++++++++++++++++
.../gremlin/groovy/jsr223/GroovyTranslator.java | 4 +++
2 files changed, 34 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/67e2ee85/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslatorTest.java
----------------------------------------------------------------------
diff --git a/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslatorTest.java b/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslatorTest.java
index 686c7bd..c224642 100644
--- a/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslatorTest.java
+++ b/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslatorTest.java
@@ -22,6 +22,9 @@ package org.apache.tinkerpop.gremlin.groovy.jsr223;
import org.apache.commons.configuration.MapConfiguration;
import org.apache.tinkerpop.gremlin.AbstractGremlinTest;
import org.apache.tinkerpop.gremlin.LoadGraphWith;
+import org.apache.tinkerpop.gremlin.process.traversal.Order;
+import org.apache.tinkerpop.gremlin.process.traversal.Pop;
+import org.apache.tinkerpop.gremlin.process.traversal.Scope;
import org.apache.tinkerpop.gremlin.process.traversal.Translator;
import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
@@ -31,6 +34,8 @@ import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SubgraphStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.TranslationStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy;
+import org.apache.tinkerpop.gremlin.structure.Column;
+import org.apache.tinkerpop.gremlin.structure.Direction;
import org.apache.tinkerpop.gremlin.structure.Edge;
import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.apache.tinkerpop.gremlin.structure.util.ElementHelper;
@@ -185,6 +190,31 @@ public class GroovyTranslatorTest extends AbstractGremlinTest {
}
@Test
+ public void shouldHandleColumn() {
+ assertTranslation("Column.keys", Column.keys);
+ }
+
+ @Test
+ public void shouldHandleDirection() {
+ assertTranslation("Direction.BOTH", Direction.BOTH);
+ }
+
+ @Test
+ public void shouldHandleOrder() {
+ assertTranslation("Order.decr", Order.decr);
+ }
+
+ @Test
+ public void shouldHandlePop() {
+ assertTranslation("Pop.last", Pop.last);
+ }
+
+ @Test
+ public void shouldHandleScope() {
+ assertTranslation("Scope.local", Scope.local);
+ }
+
+ @Test
public void shouldOverrideDefaultTypeTranslationWithSomethingBonkers() {
final String thingToSuffixAllStringsWith = "-why-would-anyone-do-this";
final String script = GroovyTranslator.of("g", x -> x instanceof String ? x + thingToSuffixAllStringsWith : x).
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/67e2ee85/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslator.java
----------------------------------------------------------------------
diff --git a/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslator.java b/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslator.java
index 1d122c6..9cd7791 100644
--- a/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslator.java
+++ b/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslator.java
@@ -22,7 +22,9 @@ package org.apache.tinkerpop.gremlin.groovy.jsr223;
import groovy.json.StringEscapeUtils;
import org.apache.commons.configuration.ConfigurationConverter;
import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
+import org.apache.tinkerpop.gremlin.process.traversal.Order;
import org.apache.tinkerpop.gremlin.process.traversal.P;
+import org.apache.tinkerpop.gremlin.process.traversal.Pop;
import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions;
import org.apache.tinkerpop.gremlin.process.traversal.Translator;
import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
@@ -32,6 +34,8 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent
import org.apache.tinkerpop.gremlin.process.traversal.strategy.TraversalStrategyProxy;
import org.apache.tinkerpop.gremlin.process.traversal.util.ConnectiveP;
import org.apache.tinkerpop.gremlin.process.traversal.util.OrP;
+import org.apache.tinkerpop.gremlin.structure.Column;
+import org.apache.tinkerpop.gremlin.structure.Direction;
import org.apache.tinkerpop.gremlin.structure.Edge;
import org.apache.tinkerpop.gremlin.structure.Element;
import org.apache.tinkerpop.gremlin.structure.Vertex;
[4/9] tinkerpop git commit: TINKERPOP-2040 Provide improved type
handling for GroovyTranslator
Posted by sp...@apache.org.
TINKERPOP-2040 Provide improved type handling for GroovyTranslator
Refactored testing and added support for UUID, Date, Timestamp as well as a method to override standard type handling.
Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/774371dc
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/774371dc
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/774371dc
Branch: refs/heads/master
Commit: 774371dc38d2d73be142eaa69c958226ac660892
Parents: 0403156
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Thu Sep 20 11:53:07 2018 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Mon Oct 1 16:18:28 2018 -0400
----------------------------------------------------------------------
.../gremlin/process/traversal/Translator.java | 34 ++++
.../groovy/jsr223/GroovyTranslatorTest.java | 162 +++++++++++++++----
.../gremlin/groovy/jsr223/GroovyTranslator.java | 32 +++-
3 files changed, 195 insertions(+), 33 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/774371dc/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Translator.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Translator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Translator.java
index 7e97fb3..0346092 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Translator.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Translator.java
@@ -19,6 +19,8 @@
package org.apache.tinkerpop.gremlin.process.traversal;
+import java.util.function.UnaryOperator;
+
/**
* A Translator will translate {@link Bytecode} into another representation. That representation may be a
* Java instance via {@link StepTranslator} or a String script in some language via {@link ScriptTranslator}.
@@ -55,10 +57,42 @@ public interface Translator<S, T> {
///
+ /**
+ * Translates bytecode to a string representation.
+ */
public interface ScriptTranslator extends Translator<String, String> {
+ /**
+ * Provides a way to customize and override the standard translation process. A {@link ScriptTranslator}
+ * implementation can choose to expose a way to accept a {@code TypeTranslator} which will convert an incoming
+ * object to a different form which will then be normally processed or can return a {@link Handled} object
+ * with the already translated script.
+ */
+ public interface TypeTranslator extends UnaryOperator<Object> {
+ public static TypeTranslator identity() {
+ return t -> t;
+ }
+ }
+
+ /**
+ * Contains a completed type translation from the {@link TypeTranslator}.
+ */
+ public class Handled {
+ private final String translation;
+
+ public Handled(final String translation) {
+ this.translation = translation;
+ }
+
+ public String getTranslation() {
+ return translation;
+ }
+ }
}
+ /**
+ * Translates bytecode to actual steps.
+ */
public interface StepTranslator<S extends TraversalSource, T extends Traversal.Admin<?, ?>> extends Translator<S, T> {
}
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/774371dc/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslatorTest.java
----------------------------------------------------------------------
diff --git a/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslatorTest.java b/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslatorTest.java
index 942f1a5..686c7bd 100644
--- a/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslatorTest.java
+++ b/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslatorTest.java
@@ -22,6 +22,7 @@ package org.apache.tinkerpop.gremlin.groovy.jsr223;
import org.apache.commons.configuration.MapConfiguration;
import org.apache.tinkerpop.gremlin.AbstractGremlinTest;
import org.apache.tinkerpop.gremlin.LoadGraphWith;
+import org.apache.tinkerpop.gremlin.process.traversal.Translator;
import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
@@ -32,47 +33,56 @@ import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.Transl
import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy;
import org.apache.tinkerpop.gremlin.structure.Edge;
import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.util.ElementHelper;
import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedEdge;
import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex;
import org.apache.tinkerpop.gremlin.util.function.Lambda;
import org.junit.Test;
import javax.script.Bindings;
+import javax.script.ScriptException;
import javax.script.SimpleBindings;
+import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Calendar;
import java.util.Collections;
+import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
+import java.util.UUID;
import java.util.function.Function;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
/**
* @author Marko A. Rodriguez (http://markorodriguez.com)
*/
public class GroovyTranslatorTest extends AbstractGremlinTest {
+ private static final GremlinGroovyScriptEngine engine = new GremlinGroovyScriptEngine();
+
@Test
@LoadGraphWith(LoadGraphWith.GraphData.MODERN)
public void shouldHandleStrategies() throws Exception {
- GraphTraversalSource g = graph.traversal();
- g = g.withStrategies(SubgraphStrategy.create(new MapConfiguration(new HashMap<String, Object>() {{
+ final GraphTraversalSource g = graph.traversal().withStrategies(SubgraphStrategy.create(new MapConfiguration(new HashMap<String, Object>() {{
put(SubgraphStrategy.VERTICES, __.has("name", "marko"));
}})));
final Bindings bindings = new SimpleBindings();
bindings.put("g", g);
- Traversal.Admin<Vertex, Object> traversal = new GremlinGroovyScriptEngine().eval(g.V().values("name").asAdmin().getBytecode(), bindings, "g");
+ Traversal.Admin<Vertex, Object> traversal = engine.eval(g.V().values("name").asAdmin().getBytecode(), bindings, "g");
assertEquals("marko", traversal.next());
assertFalse(traversal.hasNext());
//
- traversal = new GremlinGroovyScriptEngine().eval(g.withoutStrategies(SubgraphStrategy.class).V().count().asAdmin().getBytecode(), bindings, "g");
+ traversal = engine.eval(g.withoutStrategies(SubgraphStrategy.class).V().count().asAdmin().getBytecode(), bindings, "g");
assertEquals(new Long(6), traversal.next());
assertFalse(traversal.hasNext());
//
- traversal = new GremlinGroovyScriptEngine().eval(g.withStrategies(SubgraphStrategy.create(new MapConfiguration(new HashMap<String, Object>() {{
+ traversal = engine.eval(g.withStrategies(SubgraphStrategy.create(new MapConfiguration(new HashMap<String, Object>() {{
put(SubgraphStrategy.VERTICES, __.has("name", "marko"));
}})), ReadOnlyStrategy.instance()).V().values("name").asAdmin().getBytecode(), bindings, "g");
assertEquals("marko", traversal.next());
@@ -81,10 +91,10 @@ public class GroovyTranslatorTest extends AbstractGremlinTest {
@Test
@LoadGraphWith(LoadGraphWith.GraphData.MODERN)
- public void shouldSupportStringSupplierLambdas() throws Exception {
+ public void shouldSupportStringSupplierLambdas() {
GraphTraversalSource g = graph.traversal();
g = g.withStrategies(new TranslationStrategy(g, GroovyTranslator.of("g")));
- GraphTraversal.Admin<Vertex, Integer> t = g.withSideEffect("lengthSum", 0).withSack(1)
+ final GraphTraversal.Admin<Vertex, Integer> t = g.withSideEffect("lengthSum", 0).withSack(1)
.V()
.filter(Lambda.predicate("it.get().label().equals('person')"))
.flatMap(Lambda.function("it.get().vertices(Direction.OUT)"))
@@ -130,25 +140,77 @@ public class GroovyTranslatorTest extends AbstractGremlinTest {
".order().by({a,b -> a <=> b})" +
".sack({ a,b -> a + b })",
script);
+ assertThatScriptOk(script, "g", g);
}
@Test
@LoadGraphWith(LoadGraphWith.GraphData.MODERN)
public void shouldHandleMaps() {
- final GraphTraversalSource g = graph.traversal();
final String script = GroovyTranslator.of("g").translate(g.V().id().is(new LinkedHashMap<Object,Object>() {{
put(3, "32");
put(Arrays.asList(1, 2, 3.1d), 4);
}}).asAdmin().getBytecode());
assertEquals("g.V().id().is([((int) 3):(\"32\"),([(int) 1, (int) 2, 3.1d]):((int) 4)])", script);
+ assertThatScriptOk(script, "g", g);
}
@Test
public void shouldHandleEmptyMaps() {
final Function identity = new Lambda.OneArgLambda("it.get()", "gremlin-groovy");
- final GraphTraversalSource g = graph.traversal();
final String script = GroovyTranslator.of("g").translate(g.inject(Collections.emptyMap()).map(identity).asAdmin().getBytecode());
assertEquals("g.inject([]).map({it.get()})", script);
+ assertThatScriptOk(script, "g", g);
+ }
+
+ @Test
+ public void shouldHandleDate() {
+ final Calendar c = Calendar.getInstance();
+ c.set(1975, Calendar.SEPTEMBER, 7);
+ final Date d = c.getTime();
+ assertTranslation(String.format("new java.util.Date(%s)", d.getTime()), d);
+ }
+
+ @Test
+ public void shouldHandleTimestamp() {
+ final Calendar c = Calendar.getInstance();
+ c.set(1975, Calendar.SEPTEMBER, 7);
+ final Timestamp t = new Timestamp(c.getTime().getTime());
+ assertTranslation(String.format("new java.sql.Timestamp(%s)", t.getTime()), t);
+ }
+
+ @Test
+ public void shouldHandleUuid() {
+ final UUID uuid = UUID.fromString("ffffffff-fd49-1e4b-0000-00000d4b8a1d");
+ assertTranslation(String.format("java.util.UUID.fromString('%s')", uuid), uuid);
+ }
+
+ @Test
+ public void shouldOverrideDefaultTypeTranslationWithSomethingBonkers() {
+ final String thingToSuffixAllStringsWith = "-why-would-anyone-do-this";
+ final String script = GroovyTranslator.of("g", x -> x instanceof String ? x + thingToSuffixAllStringsWith : x).
+ translate(g.inject("yyy", "xxx").asAdmin().getBytecode());
+ assertEquals(String.format("g.inject(\"yyy%s\",\"xxx%s\")", thingToSuffixAllStringsWith, thingToSuffixAllStringsWith), script);
+ assertThatScriptOk(script, "g", g);
+ }
+
+ @Test
+ public void shouldIncludeCustomTypeTranslationForSomethingSilly() {
+ final SillyClass notSillyEnough = SillyClass.from("not silly enough", 100);
+ final GraphTraversalSource g = graph.traversal();
+
+ // without type translation we get uglinesss
+ final String scriptBad = GroovyTranslator.of("g").
+ translate(g.inject(notSillyEnough).asAdmin().getBytecode());
+ assertEquals(String.format("g.inject(%s)", "not silly enough:100"), scriptBad);
+
+ // with type translation we get valid gremlin
+ final String scriptGood = GroovyTranslator.of("g",
+ x -> x instanceof SillyClass ?
+ new Translator.ScriptTranslator.Handled(String.format("org.apache.tinkerpop.gremlin.groovy.jsr223.GroovyTranslatorTest.SillyClass.from('%s', (int) %s)",
+ ((SillyClass) x).getX(), ((SillyClass) x).getY())) : x).
+ translate(g.inject(notSillyEnough).asAdmin().getBytecode());
+ assertEquals(String.format("g.inject(org.apache.tinkerpop.gremlin.groovy.jsr223.GroovyTranslatorTest.SillyClass.from('%s', (int) %s))", notSillyEnough.getX(), notSillyEnough.getY()), scriptGood);
+ assertThatScriptOk(scriptGood, "g", g);
}
@Test
@@ -158,20 +220,8 @@ public class GroovyTranslatorTest extends AbstractGremlinTest {
@Test
public void shouldEscapeStrings() {
- final GraphTraversalSource g = graph.traversal();
- final String script = GroovyTranslator.of("g").translate(g.addV("customer")
- .property("customer_id", 501L)
- .property("name", "Foo\u0020Bar")
- .property("age", 25)
- .property("special", "`~!@#$%^&*()-_=+[{]}\\|;:'\",<.>/?")
- .asAdmin().getBytecode());
-
- assertEquals("g.addV(\"customer\")" +
- ".property(\"customer_id\",501L)" +
- ".property(\"name\",\"Foo Bar\")" +
- ".property(\"age\",(int) 25)" +
- ".property(\"special\",\"\"\"`~!@#\\$%^&*()-_=+[{]}\\\\|;:'\\\",<.>/?\"\"\")",
- script);
+ assertTranslation("501L,\"Foo Bar\",(int) 25,\"\"\"`~!@#\\$%^&*()-_=+[{]}\\\\|;:'\\\",<.>/?\"\"\"",
+ 501L, "Foo\u0020Bar", 25, "`~!@#$%^&*()-_=+[{]}\\|;:'\",<.>/?");
}
@Test
@@ -181,33 +231,87 @@ public class GroovyTranslatorTest extends AbstractGremlinTest {
final Object id1 = "customer:10:foo\u0020bar\u0020\u0024100#90"; // customer:10:foo bar $100#90
final Vertex vertex1 = DetachedVertex.build().setLabel("customer").setId(id1)
.create();
- final String script1 = GroovyTranslator.of("g").translate(g.V(vertex1).asAdmin().getBytecode());
- assertEquals("g.V(new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex(" +
+ final String script1 = GroovyTranslator.of("g").translate(g.inject(vertex1).asAdmin().getBytecode());
+ assertEquals("g.inject(new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex(" +
"\"customer:10:foo bar \\$100#90\"," +
"\"customer\", Collections.emptyMap()))",
script1);
+ assertThatScriptOk(script1, "g", g);
final Object id2 = "user:20:foo\\u0020bar\\u005c\\u0022mr\\u005c\\u0022\\u00241000#50"; // user:20:foo\u0020bar\u005c\u0022mr\u005c\u0022\u00241000#50
final Vertex vertex2 = DetachedVertex.build().setLabel("user").setId(id2)
.create();
- final String script2 = GroovyTranslator.of("g").translate(g.V(vertex2).asAdmin().getBytecode());
- assertEquals("g.V(new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex(" +
+ final String script2 = GroovyTranslator.of("g").translate(g.inject(vertex2).asAdmin().getBytecode());
+ assertEquals("g.inject(new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex(" +
"\"user:20:foo\\\\u0020bar\\\\u005c\\\\u0022mr\\\\u005c\\\\u0022\\\\u00241000#50\"," +
"\"user\", Collections.emptyMap()))",
script2);
+ assertThatScriptOk(script2, "g", g);
final Object id3 = "knows:30:foo\u0020bar\u0020\u0024100:\\u0020\\u0024500#70";
final Edge edge = DetachedEdge.build().setLabel("knows").setId(id3)
.setOutV((DetachedVertex) vertex1)
.setInV((DetachedVertex) vertex2)
.create();
- final String script3 = GroovyTranslator.of("g").translate(g.E(edge).asAdmin().getBytecode());
- assertEquals("g.E(new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedEdge(" +
+ final String script3 = GroovyTranslator.of("g").translate(g.inject(edge).asAdmin().getBytecode());
+ assertEquals("g.inject(new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedEdge(" +
"\"knows:30:foo bar \\$100:\\\\u0020\\\\u0024500#70\"," +
"\"knows\",Collections.emptyMap()," +
"\"customer:10:foo bar \\$100#90\",\"customer\"," +
"\"user:20:foo\\\\u0020bar\\\\u005c\\\\u0022mr\\\\u005c\\\\u0022\\\\u00241000#50\",\"user\"))",
script3);
+ assertThatScriptOk(script3, "g", g);
+ }
+
+ public static Object eval(final String s, final Object... args) throws ScriptException {
+ return engine.eval(s, new SimpleBindings(ElementHelper.asMap(args)));
+ }
+
+ public static Object eval(final String s, final Bindings b) throws ScriptException {
+ return engine.eval(s, b);
+ }
+
+ private void assertTranslation(final String expectedTranslation, final Object... objs) {
+ final String script = GroovyTranslator.of("g").translate(g.inject(objs).asAdmin().getBytecode());
+ assertEquals(String.format("g.inject(%s)", expectedTranslation), script);
+ assertThatScriptOk(script, "g", g);
+ }
+
+ private void assertThatScriptOk(final String s, final Object... args) {
+ try {
+ assertNotNull(eval(s, args));
+ } catch (ScriptException se) {
+ se.printStackTrace();
+ fail("Script should have eval'd");
+ }
+ }
+
+ public static class SillyClass {
+
+ private final String x;
+ private final int y;
+
+ private SillyClass(final String x, final int y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ public static SillyClass from(final String x, final int y) {
+ return new SillyClass(x, y);
+ }
+
+ public String getX() {
+ return x;
+ }
+
+ public int getY() {
+ return y;
+ }
+
+ @Override
+ public String toString() {
+ return x + ":" + String.valueOf(y);
+ }
}
}
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/774371dc/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslator.java
----------------------------------------------------------------------
diff --git a/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslator.java b/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslator.java
index 0452e0b..1d122c6 100644
--- a/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslator.java
+++ b/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslator.java
@@ -39,11 +39,16 @@ import org.apache.tinkerpop.gremlin.structure.VertexProperty;
import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
import org.apache.tinkerpop.gremlin.util.function.Lambda;
+import java.sql.Timestamp;
import java.util.ArrayList;
+import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
+import java.util.UUID;
+import java.util.function.UnaryOperator;
/**
* @author Marko A. Rodriguez (http://markorodriguez.com)
@@ -53,13 +58,19 @@ public final class GroovyTranslator implements Translator.ScriptTranslator {
private static final boolean IS_TESTING = Boolean.valueOf(System.getProperty("is.testing", "false"));
private final String traversalSource;
+ private final TypeTranslator typeTranslator;
- private GroovyTranslator(final String traversalSource) {
+ private GroovyTranslator(final String traversalSource, final TypeTranslator typeTranslator) {
this.traversalSource = traversalSource;
+ this.typeTranslator = typeTranslator;
}
public static final GroovyTranslator of(final String traversalSource) {
- return new GroovyTranslator(traversalSource);
+ return of(traversalSource, TypeTranslator.identity());
+ }
+
+ public static final GroovyTranslator of(final String traversalSource, final TypeTranslator typeTranslator) {
+ return new GroovyTranslator(traversalSource, Optional.ofNullable(typeTranslator).orElse(TypeTranslator.identity()));
}
///////
@@ -108,8 +119,15 @@ public final class GroovyTranslator implements Translator.ScriptTranslator {
return traversalScript.toString();
}
- private String convertToString(final Object object) {
- if (object instanceof Bytecode.Binding)
+ private String convertToString(final Object o) {
+ // a TypeTranslator that returns Handled means that the typetranslator figure out how to convert the
+ // object to a string and it should be used as-is, otherwise it gets passed down the line through the normal
+ // process
+ final Object object = typeTranslator.apply(o);
+
+ if (object instanceof Handled)
+ return ((Handled) object).getTranslation();
+ else if (object instanceof Bytecode.Binding)
return ((Bytecode.Binding) object).variable();
else if (object instanceof Bytecode)
return this.internalTranslate("__", (Bytecode) object);
@@ -155,6 +173,12 @@ public final class GroovyTranslator implements Translator.ScriptTranslator {
return "(int) " + object;
else if (object instanceof Class)
return ((Class) object).getCanonicalName();
+ else if (object instanceof Timestamp)
+ return "new java.sql.Timestamp(" + ((Timestamp) object).getTime() + ")";
+ else if (object instanceof Date)
+ return "new java.util.Date(" + ((Date) object).getTime() + ")";
+ else if (object instanceof UUID)
+ return "java.util.UUID.fromString('" + object.toString() + "')";
else if (object instanceof P)
return convertPToString((P) object, new StringBuilder()).toString();
else if (object instanceof SackFunctions.Barrier)