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 2017/05/26 12:55:35 UTC

[25/49] tinkerpop git commit: TINKERPOP-786 Added support for anonymous traversal generation

TINKERPOP-786 Added support for anonymous traversal generation


Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/e0505d12
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/e0505d12
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/e0505d12

Branch: refs/heads/TINKERPOP-1618
Commit: e0505d1243f31789514ebc315ee19ee3568470a8
Parents: 5c7f0cb
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Tue May 9 16:43:00 2017 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Tue May 16 11:02:31 2017 -0400

----------------------------------------------------------------------
 docs/src/reference/the-traversal.asciidoc       |   1 +
 .../src/main/java/SocialTraversalDsl.java       |  10 ++
 .../src/test/java/SocialDslTest.java            |   6 +
 .../process/traversal/dsl/GremlinDsl.java       |   1 +
 .../traversal/dsl/GremlinDslProcessor.java      | 133 ++++++++++++++++++-
 5 files changed, 147 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/e0505d12/docs/src/reference/the-traversal.asciidoc
----------------------------------------------------------------------
diff --git a/docs/src/reference/the-traversal.asciidoc b/docs/src/reference/the-traversal.asciidoc
index 1be365d..7da4015 100644
--- a/docs/src/reference/the-traversal.asciidoc
+++ b/docs/src/reference/the-traversal.asciidoc
@@ -3027,6 +3027,7 @@ The annotation processor will generate several classes for the DSL:
 interfaces (such as `GraphTraversal`) to instead return a `SocialTraversal`
 * `DefaultSocialTraversal` - A default implementation of `SocialTraversal` (typically not used directly by the user)
 * `SocialTraversalSource` - Spawns `DefaultSocialTraversal` instances.
+* `__` - Spawns anonymous `DefaultSocialTraversal` instances.
 
 Using the DSL then just involves telling the `Graph` to use it:
 

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/e0505d12/gremlin-archetype/gremlin-archetype-dsl/src/main/resources/archetype-resources/src/main/java/SocialTraversalDsl.java
----------------------------------------------------------------------
diff --git a/gremlin-archetype/gremlin-archetype-dsl/src/main/resources/archetype-resources/src/main/java/SocialTraversalDsl.java b/gremlin-archetype/gremlin-archetype-dsl/src/main/resources/archetype-resources/src/main/java/SocialTraversalDsl.java
index af1f039..b7e4f07 100644
--- a/gremlin-archetype/gremlin-archetype-dsl/src/main/resources/archetype-resources/src/main/java/SocialTraversalDsl.java
+++ b/gremlin-archetype/gremlin-archetype-dsl/src/main/resources/archetype-resources/src/main/java/SocialTraversalDsl.java
@@ -22,6 +22,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.dsl.GremlinDsl;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.process.traversal.P;
 
 /**
  * This Social DSL is meant to be used with the TinkerPop "modern" toy graph.
@@ -54,4 +55,13 @@ public interface SocialTraversalDsl<S, E> extends GraphTraversal.Admin<S, E> {
     public default <E2 extends Number> GraphTraversal<S, E2> youngestFriendsAge() {
         return out("knows").hasLabel("person").values("age").min();
     }
+
+    /**
+     * Designed to be used as a filter for "person" vertices based on the number of "created" edges encountered.
+     *
+     * @param number the minimum number of projects a person created
+     */
+    public default GraphTraversal<S,Long> createdAtLeast(int number) {
+        return outE("created").count().is(P.gte(number));
+    }
 }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/e0505d12/gremlin-archetype/gremlin-archetype-dsl/src/main/resources/archetype-resources/src/test/java/SocialDslTest.java
----------------------------------------------------------------------
diff --git a/gremlin-archetype/gremlin-archetype-dsl/src/main/resources/archetype-resources/src/test/java/SocialDslTest.java b/gremlin-archetype/gremlin-archetype-dsl/src/main/resources/archetype-resources/src/test/java/SocialDslTest.java
index 5967244..7f76558 100644
--- a/gremlin-archetype/gremlin-archetype-dsl/src/main/resources/archetype-resources/src/test/java/SocialDslTest.java
+++ b/gremlin-archetype/gremlin-archetype-dsl/src/main/resources/archetype-resources/src/test/java/SocialDslTest.java
@@ -51,4 +51,10 @@ public class SocialDslTest {
         SocialTraversalSource social = graph.traversal(SocialTraversalSource.class);
         assertEquals(4, social.persons().count().next().intValue());
     }
+
+    @Test
+    public void shouldFindAllPersonsWithTwoOrMoreProjects() {
+        SocialTraversalSource social = graph.traversal(SocialTraversalSource.class);
+        assertEquals(1, social.persons().filter(__.createdAtLeast(2)).count().next().intValue());
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/e0505d12/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/GremlinDsl.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/GremlinDsl.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/GremlinDsl.java
index df96007..d3a807f 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/GremlinDsl.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/GremlinDsl.java
@@ -38,6 +38,7 @@ import java.lang.annotation.Target;
  *     <li>{@code SocialTraversal} - an interface that is an extension to {@code SocialTraversalDsl}</li>
  *     <li>{@code DefaultSocialTraversal} - an implementation of the {@code SocialTraversal}</li>
  *     <li>{@code SocialTraversalSource} - an extension of {@link GraphTraversalSource} which spawns {@code DefaultSocialTraversal} instances</li>
+ *     <li>{@code __} - which spawns anonymous {@code DefaultSocialTraversal} instances</li>
  * </ul>
  *
  * Together these generated classes provide all the infrastructure required to properly Gremlin traversals enhanced

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/e0505d12/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/GremlinDslProcessor.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/GremlinDslProcessor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/GremlinDslProcessor.java
index e246765..04e59b4 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/GremlinDslProcessor.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/GremlinDslProcessor.java
@@ -29,6 +29,7 @@ import com.squareup.javapoet.TypeVariableName;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies;
 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.step.map.AddVertexStartStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.GraphStep;
 import org.apache.tinkerpop.gremlin.process.traversal.util.DefaultTraversal;
@@ -53,6 +54,7 @@ import javax.lang.model.element.VariableElement;
 import javax.lang.model.type.DeclaredType;
 import javax.lang.model.type.TypeKind;
 import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVariable;
 import javax.lang.model.util.Elements;
 import javax.lang.model.util.Types;
 import javax.tools.Diagnostic;
@@ -104,6 +106,9 @@ public class GremlinDslProcessor extends AbstractProcessor {
                 // create the "TraversalSource" class which is used to spawn traversals from a Graph instance. It will
                 // spawn instances of the "DefaultTraversal" generated above.
                 generateTraversalSource(ctx);
+
+                // create anonymous traversal for DSL
+                generateAnonymousTraversal(ctx);
             }
         } catch (Exception ex) {
             messager.printMessage(Diagnostic.Kind.ERROR, ex.getMessage());
@@ -112,6 +117,126 @@ public class GremlinDslProcessor extends AbstractProcessor {
         return true;
     }
 
+    private void generateAnonymousTraversal(final Context ctx) throws IOException {
+        final TypeSpec.Builder anonymousClass = TypeSpec.classBuilder("__")
+                .addModifiers(Modifier.PUBLIC, Modifier.FINAL);
+
+        // this class is just static methods - it should not be instantiated
+        anonymousClass.addMethod(MethodSpec.constructorBuilder()
+                .addModifiers(Modifier.PRIVATE)
+                .build());
+
+        // add start() method
+        anonymousClass.addMethod(MethodSpec.methodBuilder("start")
+                .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
+                .addTypeVariable(TypeVariableName.get("A"))
+                .addStatement("return new $N<>()", ctx.defaultTraversalClazz)
+                .returns(ParameterizedTypeName.get(ctx.traversalClassName, TypeVariableName.get("A"), TypeVariableName.get("A")))
+                .build());
+
+        // process the methods of the GremlinDsl annotated class
+        for (Element element : ctx.annotatedDslType.getEnclosedElements()) {
+            if (element.getKind() != ElementKind.METHOD) continue;
+
+            final ExecutableElement templateMethod = (ExecutableElement) element;
+            final String methodName = templateMethod.getSimpleName().toString();
+
+            final TypeName returnType = getReturnTypeDefinition(ctx.traversalClassName, templateMethod);
+            final MethodSpec.Builder methodToAdd = MethodSpec.methodBuilder(methodName)
+                    .addModifiers(Modifier.STATIC, Modifier.PUBLIC)
+                    .addExceptions(templateMethod.getThrownTypes().stream().map(TypeName::get).collect(Collectors.toList()))
+                    .returns(returnType);
+
+            templateMethod.getTypeParameters().forEach(tp -> methodToAdd.addTypeVariable(TypeVariableName.get(tp)));
+
+            // might have to deal with an "S" (in __ it's usually an "A") - how to make this less bound to that convention?
+            final DeclaredType returnTypeMirror = (DeclaredType) templateMethod.getReturnType();
+            final List<? extends TypeMirror> returnTypeArguments = returnTypeMirror.getTypeArguments();
+            returnTypeArguments.stream().filter(rtm -> rtm instanceof TypeVariable).forEach(rtm -> {
+                if (((TypeVariable) rtm).asElement().getSimpleName().contentEquals("S"))
+                    methodToAdd.addTypeVariable(TypeVariableName.get(((TypeVariable) rtm).asElement().getSimpleName().toString()));
+            });
+
+            boolean added = false;
+            final List<? extends VariableElement> parameters = templateMethod.getParameters();
+            String body = "return __.<S>start().$L(";
+            for (VariableElement param : parameters) {
+                methodToAdd.addParameter(ParameterSpec.get(param));
+
+                body = body + param.getSimpleName() + ",";
+                added = true;
+            }
+
+            // treat a final array as a varargs param
+            if (!parameters.isEmpty() && parameters.get(parameters.size() - 1).asType().getKind() == TypeKind.ARRAY)
+                methodToAdd.varargs(true);
+
+            if (added) body = body.substring(0, body.length() - 1);
+
+            body = body + ")";
+
+            methodToAdd.addStatement(body, methodName);
+
+            anonymousClass.addMethod(methodToAdd.build());
+        }
+
+        // use methods from __ to template them into the DSL __
+        final Element anonymousTraversal = elementUtils.getTypeElement(__.class.getCanonicalName());
+        for (Element element : anonymousTraversal.getEnclosedElements()) {
+            if (element.getKind() != ElementKind.METHOD) continue;
+
+            final ExecutableElement templateMethod = (ExecutableElement) element;
+            final String methodName = templateMethod.getSimpleName().toString();
+
+            // ignore start() from __ - that's not proxied
+            if (methodName.equals("start")) continue;
+
+            final TypeName returnType = getReturnTypeDefinition(ctx.traversalClassName, templateMethod);
+            final MethodSpec.Builder methodToAdd = MethodSpec.methodBuilder(methodName)
+                    .addModifiers(Modifier.STATIC, Modifier.PUBLIC)
+                    .addExceptions(templateMethod.getThrownTypes().stream().map(TypeName::get).collect(Collectors.toList()))
+                    .returns(returnType);
+
+            templateMethod.getTypeParameters().forEach(tp -> methodToAdd.addTypeVariable(TypeVariableName.get(tp)));
+
+            boolean added = false;
+            final List<? extends VariableElement> parameters = templateMethod.getParameters();
+            String body;
+            if (methodName.equals("__")) {
+                for (VariableElement param : parameters) {
+                    methodToAdd.addParameter(ParameterSpec.get(param));
+                }
+
+                methodToAdd.varargs(true);
+
+                body = "return inject(starts)";
+            } else {
+                body = "return __.<A>start().$L(";
+                for (VariableElement param : parameters) {
+                    methodToAdd.addParameter(ParameterSpec.get(param));
+
+                    body = body + param.getSimpleName() + ",";
+                    added = true;
+                }
+
+                // treat a final array as a varargs param
+                if (!parameters.isEmpty() && parameters.get(parameters.size() - 1).asType().getKind() == TypeKind.ARRAY)
+                    methodToAdd.varargs(true);
+
+                if (added) body = body.substring(0, body.length() - 1);
+
+                body = body + ")";
+            }
+
+            methodToAdd.addStatement(body, methodName);
+
+            anonymousClass.addMethod(methodToAdd.build());
+        }
+
+        final JavaFile traversalSourceJavaFile = JavaFile.builder(ctx.packageName, anonymousClass.build()).build();
+        traversalSourceJavaFile.writeTo(filer);
+    }
+
     private void generateTraversalSource(final Context ctx) throws IOException {
         final TypeElement graphTraversalSourceElement = ctx.traversalSourceDslType;
         final TypeSpec.Builder traversalSourceClass = TypeSpec.classBuilder(ctx.traversalSourceClazz)
@@ -132,7 +257,7 @@ public class GremlinDslProcessor extends AbstractProcessor {
                 .build());
 
         // override methods to return a the DSL TraversalSource. find GraphTraversalSource class somewhere in the hierarchy
-        final Element tinkerPopsGraphTraversalSource = findTinkerPopsGraphTraversalSource(graphTraversalSourceElement);
+        final Element tinkerPopsGraphTraversalSource = findClassAsElement(graphTraversalSourceElement, GraphTraversalSource.class);
         for (Element elementOfGraphTraversalSource : tinkerPopsGraphTraversalSource.getEnclosedElements()) {
             // first copy/override methods that return a GraphTraversalSource so that we can instead return
             // the DSL TraversalSource class.
@@ -226,13 +351,13 @@ public class GremlinDslProcessor extends AbstractProcessor {
         traversalSourceJavaFile.writeTo(filer);
     }
 
-    private Element findTinkerPopsGraphTraversalSource(final Element element) {
-        if (element.getSimpleName().contentEquals(GraphTraversalSource.class.getSimpleName())) {
+    private Element findClassAsElement(final Element element, final Class<?> clazz) {
+        if (element.getSimpleName().contentEquals(clazz.getSimpleName())) {
             return element;
         }
 
         final List<? extends TypeMirror> supertypes = typeUtils.directSupertypes(element.asType());
-        return findTinkerPopsGraphTraversalSource(typeUtils.asElement(supertypes.get(0)));
+        return findClassAsElement(typeUtils.asElement(supertypes.get(0)), clazz);
     }
 
     private void generateDefaultTraversal(final Context ctx) throws IOException {