TINKERPOP-786 Added some initial documentation for DSLs

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

Branch: refs/heads/tp32-glv
Commit: 50f2dac9d897d5776a2cdd4ae3a7b56a4ed6339a
Parents: e661359
Author: Stephen Mallette <[email protected]>
Authored: Tue May 9 13:57:48 2017 -0400
Committer: Stephen Mallette <[email protected]>
Committed: Tue May 16 11:01:51 2017 -0400

----------------------------------------------------------------------
 docs/src/reference/the-traversal.asciidoc | 154 +++++++++++++++++++++++++
 1 file changed, 154 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/50f2dac9/docs/src/reference/the-traversal.asciidoc
----------------------------------------------------------------------
diff --git a/docs/src/reference/the-traversal.asciidoc 
b/docs/src/reference/the-traversal.asciidoc
index 2612309..1be365d 100644
--- a/docs/src/reference/the-traversal.asciidoc
+++ b/docs/src/reference/the-traversal.asciidoc
@@ -2939,3 +2939,157 @@ g.V().outE().inV().
     by().
     by('name')
 ----
+
+[[dsl]]
+Domain Specific Languages
+-------------------------
+
+Gremlin is a link:http://en.wikipedia.org/wiki/Domain-specific_language[domain 
specific language] (DSL) for traversing
+graphs. It operates in the language of vertices, edges and properties. 
Typically, applications built with Gremlin are
+not of the graph domain, but instead model their domain within a graph. For 
example, the "modern" toy graph models
+software and person domain objects with the relationships between them (i.e. a 
person "knows" another person and a
+person "created" software).
+
+image::tinkerpop-modern.png[width=350]
+
+An analyst who wanted to find all the people who "marko" knows could write the 
following Gremlin:
+
+[source,java]
+----
+g.V().hasLabel('person').has('name','marko').out('knows')
+----
+
+While this method achieves the desired answer, it requires the analyst to 
traverse the graph in the domain language
+of the graph rather than the domain language of the social network. A more 
natural way for the analyst to write this
+traversal might be:
+
+[source,java]
+----
+g.persons('marko').knows()
+----
+
+In the statement above, the traversal is written in the language of the 
domain, abstracting away the underlying
+graph structure from the query. The two traversal results are equivalent and, 
indeed, the "Social Network DSL" produces
+the same set of traversal steps as the "Graph DSL" thus producing equivalent 
strategy application and performance
+runtimes.
+
+The following sections explain how to develop application specific DSLs for 
different <<gremlin-variants,Gremlin Language Variants>>.
+
+[[gremlin-java-dsl]
+Gremlin-Java
+~~~~~~~~~~~~
+
+Creating a DSL in Java requires the `@GremlinDsl` Java annotation in 
`gremlin-core`. This annotation should be applied
+to a "DSL interface" that extends `GraphTraversal.Admin`.
+
+[source,java]
+----
+@GremlinDsl
+public interface SocialTraversalDsl<S, E> extends GraphTraversal.Admin<S, E> {
+}
+----
+
+IMPORTANT: The name of the DSL interface should be suffixed with 
"TraversalDSL". All characters in the interface name
+before that become the "name" of the DSL.
+
+In this interface, define the methods that the DSL will be composed of:
+
+[source,java]
+----
+@GremlinDsl
+public interface SocialTraversalDsl<S, E> extends GraphTraversal.Admin<S, E> {
+    public default GraphTraversal<S, Vertex> knows(String personName) {
+        return out("knows").hasLabel("person").has("name", personName);
+    }
+
+    public default <E2 extends Number> GraphTraversal<S, E2> 
youngestFriendsAge() {
+        return out("knows").hasLabel("person").values("age").min();
+    }
+}
+----
+
+The `@GremlinDsl` annotation is used by the 
link:https://docs.oracle.com/javase/8/docs/api/index.html?javax/annotation/processing/Processor.html[Java
 Annotation Processor]
+to generate the boilerplate class structure required to properly use the DSL 
within the TinkerPop framework. These
+classes can be generated and maintained by hand, but it would be time 
consuming, monotonous and error-prone to do so.
+Typically, the Java compilation process is automatically configured to detect 
annotation processors on the classpath
+and will automatically use them when found. If that does not happen, it may be 
necessary to make configuration changes
+to the build to allow for the compilation process to be aware of the following 
`javax.annotation.processing.Processor`
+implementation:
+
+[source,java]
+----
+org.apache.tinkerpop.gremlin.process.traversal.dsl.GremlinDslProcessor
+----
+
+The annotation processor will generate several classes for the DSL:
+
+* `SocialTraversal` - A `Traversal` interface that extends the 
`SocialTraversalDsl` proxying methods to its underlying
+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.
+
+Using the DSL then just involves telling the `Graph` to use it:
+
+[source,java]
+----
+SocialTraversalSource social = graph.traversal(SocialTraversalSource.class);
+social.V().has("name","marko").knows("josh");
+----
+
+The `SocialTraversalSource` can also be customized with DSL functions. As an 
additional step, include a class that
+extends from `GraphTraversalSource` and with a name that is suffixed with 
"TraversalSourceDsl". Include in this class,
+any custom methods required by the DSL:
+
+[source,java]
+----
+public class SocialTraversalSourceDsl extends GraphTraversalSource {
+
+    public SocialTraversalSourceDsl(final Graph graph, final 
TraversalStrategies traversalStrategies) {
+        super(graph, traversalStrategies);
+    }
+
+    public SocialTraversalSourceDsl(final Graph graph) {
+        super(graph);
+    }
+
+    public GraphTraversal<Vertex, Vertex> persons(String... names) {
+        GraphTraversalSource clone = this.clone();
+
+        // Manually add a "start" step for the traversal in this case the 
equivalent of V(). GraphStep is marked
+        // as a "start" step by passing "true" in the constructor.
+        clone.getBytecode().addStep(GraphTraversal.Symbols.V);
+        GraphTraversal<Vertex, Vertex> traversal = new 
DefaultGraphTraversal<>(clone);
+        traversal.asAdmin().addStep(new GraphStep<>(traversal.asAdmin(), 
Vertex.class, true));
+
+        traversal = traversal.hasLabel("person");
+        if (names.length > 0) traversal = traversal.has("name", 
P.within(names));
+
+        return traversal;
+    }
+}
+----
+
+Then, back in the `SocialTraversal` interface, update the `GremlinDsl` 
annotation with the `traversalSource` argument
+to point to the fully qualified class name of the `SocialTraversalSourceDsl`:
+
+[source,java]
+----
+@GremlinDsl(traversalSource = "com.company.SocialTraversalSourceDsl")
+public interface SocialTraversalDsl<S, E> extends GraphTraversal.Admin<S, E> {
+    ...
+}
+----
+
+It is then possible to use the `persons()` method to start traversals:
+
+[source,java]
+----
+SocialTraversalSource social = graph.traversal(SocialTraversalSource.class);
+social.persons().count();
+----
+
+NOTE: Using Maven, as shown in the `gremlin-archetype-dsl` module, makes 
developing DSLs with the annotation processor
+straightforward in that it sets up appropriate paths to the generated code 
automatically.
+
+Gremlin-Python
+~~~~~~~~~~~~~~

Reply via email to