You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by ok...@apache.org on 2016/06/20 17:26:51 UTC
tinkerpop git commit: Added Lambda interface which can be used by
Gremlin-Java and other strongly typed Gremlin variants. Lambda provides
methods for function, predicate, supplier, comparator,
etc. where the returned Lambda object has a getLambdaScript()
Repository: tinkerpop
Updated Branches:
refs/heads/TINKERPOP-1278 f5a28e804 -> 0cdb3cce0
Added Lambda interface which can be used by Gremlin-Java and other strongly typed Gremlin variants. Lambda provides methods for function, predicate, supplier, comparator, etc. where the returned Lambda object has a getLambdaScript() and can be introspected by a XXXTranslator accordingly. This solves the Lambda problem for Java/Scala/etc. While Groovy can use Lambda, it doesn't need to as it will assume all closures yield the lambda script string.
Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/0cdb3cce
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/0cdb3cce
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/0cdb3cce
Branch: refs/heads/TINKERPOP-1278
Commit: 0cdb3cce0adaf150c6844395690de9b4a7184457
Parents: f5a28e8
Author: Marko A. Rodriguez <ok...@gmail.com>
Authored: Mon Jun 20 11:26:45 2016 -0600
Committer: Marko A. Rodriguez <ok...@gmail.com>
Committed: Mon Jun 20 11:26:45 2016 -0600
----------------------------------------------------------------------
.../tinkerpop/gremlin/util/function/Lambda.java | 120 +++++++++++++++++++
.../gremlin/groovy/GroovyTranslatorTest.java | 59 ++++++---
.../gremlin/groovy/GroovyTranslator.java | 11 +-
.../gremlin/python/PythonTranslator.java | 11 +-
.../gremlin/python/PythonBypassTranslator.java | 4 +
.../gremlin/python/PythonTranslatorTest.java | 55 ++++++++-
6 files changed, 225 insertions(+), 35 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/0cdb3cce/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/function/Lambda.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/function/Lambda.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/function/Lambda.java
new file mode 100644
index 0000000..cdb4239
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/function/Lambda.java
@@ -0,0 +1,120 @@
+/*
+ * 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.util.function;
+
+import java.io.Serializable;
+import java.util.Comparator;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+
+/**
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ */
+public interface Lambda extends Serializable {
+
+ public String getLambdaScript();
+
+ public abstract static class AbstractLambda implements Lambda {
+ private final String lambdaSource;
+
+ private AbstractLambda(final String lambdaSource) {
+ this.lambdaSource = lambdaSource;
+ }
+
+ @Override
+ public String getLambdaScript() {
+ return this.lambdaSource;
+ }
+ }
+
+ public static class SimpleLambda<A, B> extends AbstractLambda implements Function<A, B>, Predicate<A>, Supplier<A>, Consumer<A>, Comparator<A> {
+ public SimpleLambda(final String lambdaSource) {
+ super(lambdaSource);
+ }
+
+ @Override
+ public B apply(final A a) {
+ return null;
+ }
+
+ @Override
+ public boolean test(final A a) {
+ return false;
+ }
+
+ @Override
+ public A get() {
+ return null;
+ }
+
+ @Override
+ public void accept(final A a) {
+
+ }
+
+ @Override
+ public int compare(final A first, final A second) {
+ return 0;
+ }
+ }
+
+ public static class ComplexLambda<A, B, C> extends AbstractLambda implements BiFunction<A, B, C> {
+
+ public ComplexLambda(final String lambdaSource) {
+ super(lambdaSource);
+ }
+
+ @Override
+ public C apply(final A a, final B b) {
+ return null;
+ }
+ }
+
+
+ ////
+
+ public static <A, B> Function<A, B> function(final String lambdaSource) {
+ return new SimpleLambda<>(lambdaSource);
+ }
+
+ public static <A> Predicate<A> predicate(final String lambdaSource) {
+ return new SimpleLambda<>(lambdaSource);
+ }
+
+ public static <A> Consumer<A> consumer(final String lambdaSource) {
+ return new SimpleLambda<>(lambdaSource);
+ }
+
+ public static <A> Supplier<A> supplier(final String lambdaSource) {
+ return new SimpleLambda<>(lambdaSource);
+ }
+
+ public static <A> Comparator<A> comparator(final String lambdaSource) {
+ return new SimpleLambda<>(lambdaSource);
+ }
+
+ public static <A, B, C> BiFunction<A, B, C> biFunction(final String lambdaSource) {
+ return new ComplexLambda<>(lambdaSource);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/0cdb3cce/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/GroovyTranslatorTest.java
----------------------------------------------------------------------
diff --git a/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/GroovyTranslatorTest.java b/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/GroovyTranslatorTest.java
index d7ff1a0..c477257 100644
--- a/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/GroovyTranslatorTest.java
+++ b/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/GroovyTranslatorTest.java
@@ -21,15 +21,19 @@ package org.apache.tinkerpop.gremlin.groovy;
import org.apache.tinkerpop.gremlin.AbstractGremlinTest;
import org.apache.tinkerpop.gremlin.LoadGraphWith;
+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.structure.Vertex;
+import org.apache.tinkerpop.gremlin.util.function.Lambda;
import org.junit.Test;
+import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
/**
* @author Marko A. Rodriguez (http://markorodriguez.com)
@@ -40,22 +44,45 @@ public class GroovyTranslatorTest extends AbstractGremlinTest {
@LoadGraphWith(LoadGraphWith.GraphData.MODERN)
public void shouldSupportStringSupplierLambdas() throws Exception {
final GraphTraversalSource g = graph.traversal().withTranslator(GroovyTranslator.of("g"));
- GraphTraversal.Admin<Vertex, Integer> t = (GraphTraversal.Admin) g.V().hasLabel("person").out().map(x -> "it.get().value('name').length()").asAdmin();
- List<Integer> lengths = t.toList();
+ GraphTraversal.Admin<Vertex, Integer> t = g.withSideEffect("lengthSum", 0).withSack(1)
+ .V()
+ .filter(Lambda.predicate("it.get().label().equals('person')"))
+ .flatMap(Lambda.<Traverser<Vertex>, Iterator<Vertex>>function("it.get().vertices(Direction.OUT)"))
+ .map(Lambda.<Traverser<Vertex>, 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.getEndStep().next();
+ sacks.add(traverser.sack());
+ lengths.add(traverser.get());
+ }
+ assertFalse(t.hasNext());
+ //
assertEquals(6, lengths.size());
- assertTrue(lengths.contains(3));
- assertTrue(lengths.contains(4));
- assertTrue(lengths.contains(5));
- assertTrue(lengths.contains(6));
- assertEquals(24, g.V().hasLabel("person").out().map(x -> "it.get().value('name').length()").sum().next().intValue());
+ 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());
+ }
- /*t = g.V().hasLabel("person").out().filter(x -> "{ x.sideEffects('lengthSum', x.get().value('name').length()").asAdmin();
- lengths = t.toList();
- assertEquals(6, lengths.size());
- assertTrue(lengths.contains(3));
- assertTrue(lengths.contains(4));
- assertTrue(lengths.contains(5));
- assertTrue(lengths.contains(6));
- assertEquals(24, g.V().hasLabel("person").out().map(x -> "it.get().value('name').length()").sum().next().intValue());*/
+ @Test
+ public void shouldHaveValidToString() {
+ assertEquals("translator[h:gremlin-java->gremlin-groovy]", GroovyTranslator.of("h").toString());
}
}
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/0cdb3cce/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/GroovyTranslator.java
----------------------------------------------------------------------
diff --git a/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/GroovyTranslator.java b/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/GroovyTranslator.java
index b17692e..8584067 100644
--- a/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/GroovyTranslator.java
+++ b/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/GroovyTranslator.java
@@ -33,10 +33,10 @@ import org.apache.tinkerpop.gremlin.process.traversal.util.TranslatorHelper;
import org.apache.tinkerpop.gremlin.structure.Element;
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.util.ArrayList;
import java.util.List;
-import java.util.function.Function;
/**
* @author Marko A. Rodriguez (http://markorodriguez.com)
@@ -147,12 +147,9 @@ public final class GroovyTranslator implements Translator {
return convertToString(((Element) object).id()); // hack
else if (object instanceof Computer) { // TODO: blow out
return "";
- } else if (object instanceof Function) {
- try {
- return "{" + ((Function) object).apply(null).toString() + "}";
- } catch (final Exception e) {
- return object.toString(); // TODO: hack for testing
- }
+ } else if (object instanceof Lambda) {
+ final String lambdaString = ((Lambda) object).getLambdaScript();
+ return lambdaString.startsWith("{") ? lambdaString : "{" + lambdaString + "}";
} else if (object instanceof Traversal) {
final TranslationStrategy strategy = (TranslationStrategy) ((Traversal.Admin) object).getStrategies().toList()
.stream()
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/0cdb3cce/gremlin-variant/src/main/java/org/apache/tinkerpop/gremlin/python/PythonTranslator.java
----------------------------------------------------------------------
diff --git a/gremlin-variant/src/main/java/org/apache/tinkerpop/gremlin/python/PythonTranslator.java b/gremlin-variant/src/main/java/org/apache/tinkerpop/gremlin/python/PythonTranslator.java
index 734396a..79eee72 100644
--- a/gremlin-variant/src/main/java/org/apache/tinkerpop/gremlin/python/PythonTranslator.java
+++ b/gremlin-variant/src/main/java/org/apache/tinkerpop/gremlin/python/PythonTranslator.java
@@ -36,6 +36,7 @@ import org.apache.tinkerpop.gremlin.structure.Element;
import org.apache.tinkerpop.gremlin.structure.T;
import org.apache.tinkerpop.gremlin.structure.VertexProperty;
import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
+import org.apache.tinkerpop.gremlin.util.function.Lambda;
import org.apache.tinkerpop.gremlin.util.iterator.ArrayIterator;
import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
@@ -45,7 +46,6 @@ import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
-import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -187,12 +187,9 @@ public class PythonTranslator implements Translator {
return strategy.getTranslator().getTraversalScript();
} else if (object instanceof Computer) {
return "";
- } else if (object instanceof Function) {
- try {
- return "lambda: \"" + ((Function) object).apply(null).toString() + "\"";
- } catch (final Exception e) {
- return object.toString(); // TODO: hack for testing
- }
+ } else if (object instanceof Lambda) {
+ final String lambdaString = ((Lambda) object).getLambdaScript();
+ return lambdaString.startsWith("lambda") ? "\"" + lambdaString + "\"" : "lambda: \"" + lambdaString + "\"";
} else
return null == object ? "" : object.toString();
}
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/0cdb3cce/gremlin-variant/src/test/java/org/apache/tinkerpop/gremlin/python/PythonBypassTranslator.java
----------------------------------------------------------------------
diff --git a/gremlin-variant/src/test/java/org/apache/tinkerpop/gremlin/python/PythonBypassTranslator.java b/gremlin-variant/src/test/java/org/apache/tinkerpop/gremlin/python/PythonBypassTranslator.java
index 8eb2d23..a3b11bc 100644
--- a/gremlin-variant/src/test/java/org/apache/tinkerpop/gremlin/python/PythonBypassTranslator.java
+++ b/gremlin-variant/src/test/java/org/apache/tinkerpop/gremlin/python/PythonBypassTranslator.java
@@ -39,6 +39,10 @@ class PythonBypassTranslator extends PythonTranslator {
super(alias, importStatics);
}
+ public static PythonBypassTranslator of(final String alias) {
+ return new PythonBypassTranslator(alias, false);
+ }
+
public static PythonBypassTranslator of(final String alias, final boolean importStatics) {
return new PythonBypassTranslator(alias, importStatics);
}
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/0cdb3cce/gremlin-variant/src/test/java/org/apache/tinkerpop/gremlin/python/PythonTranslatorTest.java
----------------------------------------------------------------------
diff --git a/gremlin-variant/src/test/java/org/apache/tinkerpop/gremlin/python/PythonTranslatorTest.java b/gremlin-variant/src/test/java/org/apache/tinkerpop/gremlin/python/PythonTranslatorTest.java
index 6102dd8..27a43bd 100644
--- a/gremlin-variant/src/test/java/org/apache/tinkerpop/gremlin/python/PythonTranslatorTest.java
+++ b/gremlin-variant/src/test/java/org/apache/tinkerpop/gremlin/python/PythonTranslatorTest.java
@@ -19,14 +19,22 @@
package org.apache.tinkerpop.gremlin.python;
-import org.apache.tinkerpop.gremlin.groovy.GroovyTranslator;
+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.strategy.creation.TranslationStrategy;
import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerFactory;
+import org.apache.tinkerpop.gremlin.util.function.Lambda;
import org.junit.Test;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
/**
* @author Marko A. Rodriguez (http://markorodriguez.com)
*/
@@ -38,10 +46,47 @@ public class PythonTranslatorTest {
@Test
public void shouldSupportStringSupplierLambdas() throws Exception {
- final GraphTraversalSource g = TinkerFactory.createModern().traversal().withTranslator(GroovyTranslator.of("g"));
- GraphTraversal.Admin<Vertex, Number> t = (GraphTraversal.Admin) g.V().hasLabel("person").out().map(x -> "it.get().value('name').length()").asAdmin();
- System.out.println(t.getStrategies().getStrategy(TranslationStrategy.class).get().getTranslator().getTraversalScript());
- System.out.print(t.toList());
+ final GraphTraversalSource g = TinkerFactory.createModern().traversal().withTranslator(PythonBypassTranslator.of("g",true));
+ GraphTraversal.Admin<Vertex, Integer> t = g.withSideEffect("lengthSum", 0).withSack(1)
+ .V()
+ .filter(Lambda.predicate("it.get().label().equals('person')"))
+ .flatMap(Lambda.<Traverser<Vertex>, Iterator<Vertex>>function("it.get().vertices(Direction.OUT)"))
+ .map(Lambda.<Traverser<Vertex>, 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.getEndStep().next();
+ 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());
+ }
+
+ @Test
+ public void shouldHaveValidToString() {
+ assertEquals("translator[h:gremlin-java->jython]", PythonTranslator.of("h").toString());
}
}