tinkerpop-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From spmalle...@apache.org
Subject [tinkerpop] 02/03: Merge branch 'tp33' into tp34
Date Mon, 23 Sep 2019 14:12:09 GMT
This is an automated email from the ASF dual-hosted git repository.

spmallette pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit 9f500eca9154d4af89caf09583093dd17a3ba350
Merge: 2e89be3 49bab07
Author: Stephen Mallette <spmva@genoprime.com>
AuthorDate: Mon Sep 23 08:47:16 2019 -0400

    Merge branch 'tp33' into tp34

 CHANGELOG.asciidoc                                 |  1 +
 docs/src/reference/gremlin-variants.asciidoc       |  8 ++++++
 .../tinkerpop/gremlin/util/function/Lambda.java    | 31 ++++++++++++++++++++++
 .../src/Gremlin.Net/Process/Traversal/Lambda.cs    |  4 +--
 .../Process/Traversal/StringBasedLambda.cs         | 21 ++++++++++++++-
 .../GraphTraversalSourceTests.cs                   | 12 +++++++++
 .../gremlin/groovy/jsr223/GroovyTranslator.java    | 31 ++++++++++++++++++++--
 .../groovy/jsr223/GroovyTranslatorTest.java        | 27 +++++++++++++++++++
 .../gremlin_python/structure/io/graphsonV2d0.py    |  8 ++++--
 .../gremlin_python/structure/io/graphsonV3d0.py    |  8 ++++--
 .../tests/driver/test_driver_remote_connection.py  | 11 ++++++++
 11 files changed, 153 insertions(+), 9 deletions(-)

diff --cc docs/src/reference/gremlin-variants.asciidoc
index d54493c,d141333..20b1000
--- a/docs/src/reference/gremlin-variants.asciidoc
+++ b/docs/src/reference/gremlin-variants.asciidoc
@@@ -779,245 -312,120 +779,249 @@@ g.V().out().map(lambda: "x: len(x.get()
  <7> The default lambda language is changed back to Gremlin-Python.
  <8> If the `lambda`-prefix is not provided, then it is appended automatically in order
to give a more natural look to the expression.
  
+ TIP: When running into situations where Groovy cannot properly discern a method signature
based on the `Lambda`
+ instance created, it will help to fully define the closure in the lambda expression - so
rather than
+ `lambda: ("it.get().value("name')","gremlin-groovy")`, prefer `lambda: ("x -> x.get().value("name"),"gremlin-groovy")`.
+ 
 -=== Limitations
 +Finally, Gremlin `Bytecode` that includes lambdas requires that the traversal be processed
by the
 +`ScriptEngine`. To avoid continued recompilation costs, it supports the encoding of bindings,
which allow a remote
 +engine to to cache traversals that will be reused over and over again save that some parameterization
may change. Thus,
 +instead of translating, compiling, and then executing each submitted bytecode, it is possible
to simply execute.
  
 -* Traversals that return a `Set` *might* be coerced to a `List` in Python. In the case of
Python, number equality
 -is different from JVM languages which produces different `Set` results when those types
are in use. When this case
 -is detected during deserialization, the `Set` is coerced to a `List` so that traversals
return consistent
 -results within a collection across different languages. If a `Set` is needed then convert
`List` results
 -to `Set` manually.
 +[gremlin-python,modern]
 +----
 +g.V(Bindings.of('id',1)).out('created').map(lambda: ("it.get().value('name').length()",
"gremlin-groovy")).sum().toList()
 +g.V(Bindings.of('id',4)).out('created').map(lambda: ("it.get().value('name').length()",
"gremlin-groovy")).sum().toList()
 +----
  
 -[[gremlin-DotNet]]
 -== Gremlin.Net
 +==== Native Python Lambdas
  
 -image:gremlin-dotnet-logo.png[width=371,float=right] Apache TinkerPop's Gremlin.Net implements
Gremlin within the C# language. It targets .NET Standard and can
 -therefore be used on different operating systems and with different .NET frameworks, such
as .NET Framework
 -and link:https://www.microsoft.com/net/core[.NET Core]. Since the C# syntax is very similar
to that of Java, it should be very easy to switch between
 -Gremlin-Java and Gremlin.Net. The only major syntactical difference is that all method names
in Gremlin.Net
 -use PascalCase as opposed to camelCase in Gremlin-Java in order to comply with .NET conventions.
 +To process lambdas in Python, the `GremlinJythonScriptEngine` must be enabled on the remote
end. If that remote is
 +Gremlin Server, then these instructions can help configuration it. As an example, the
 +`conf/gremlin-server-modern-py.yaml` configuration maintains a `GremlinJythonScriptEngine`.
  
 -[source,powershell]
 -nuget install Gremlin.Net
 +[source,bash]
 +----
 +$ bin/gremlin-server.sh install org.apache.tinkerpop gremlin-python x.y.z
 +$ bin/gremlin-server.sh conf/gremlin-server-modern-py.yaml
 +[INFO] GremlinServer -
 +       \,,,/
 +       (o o)
 +---oOOo-(3)-oOOo---
  
 -In Gremlin.Net there exists `GraphTraversalSource`, `GraphTraversal`, and `__` which mirror
the respective classes
 -in Gremlin-Java. The `GraphTraversalSource` requires a driver in order to communicate with
<<gremlin-server,GremlinServer>> (or any
 -RemoteConnection-enabled server).
 +[INFO] GremlinServer - Configuring Gremlin Server from conf/gremlin-server-modern-py.yaml
 +[INFO] MetricManager - Configured Metrics Slf4jReporter configured with interval=180000ms
and loggerName=org.apache.tinkerpop.gremlin.server.Settings$Slf4jReporterMetrics
 +[INFO] GraphManager - Graph [graph] was successfully configured via [conf/tinkergraph-empty.properties].
 +[INFO] ServerGremlinExecutor - Initialized Gremlin thread pool.  Threads in pool named with
pattern gremlin-*
 +[INFO] ScriptEngines - Loaded gremlin-jython ScriptEngine
 +[INFO] ScriptEngines - Loaded gremlin-python ScriptEngine
 +[INFO] ScriptEngines - Loaded gremlin-groovy ScriptEngine
 +[INFO] GremlinExecutor - Initialized gremlin-groovy ScriptEngine with scripts/generate-modern.groovy
 +[INFO] ServerGremlinExecutor - Initialized GremlinExecutor and configured ScriptEngines.
 +[INFO] ServerGremlinExecutor - A GraphTraversalSource is now bound to [g] with graphtraversalsource[tinkergraph[vertices:0
edges:0], standard]
 +[INFO] OpLoader - Adding the standard OpProcessor.
 +[INFO] OpLoader - Adding the session OpProcessor.
 +[INFO] OpLoader - Adding the traversal OpProcessor.
 +[INFO] TraversalOpProcessor - Initialized cache for TraversalOpProcessor with size 1000
and expiration time of 600000 ms
 +[INFO] GremlinServer - Executing start up LifeCycleHook
 +[INFO] Logger$info - Loading 'modern' graph data.
 +[WARN] AbstractChannelizer - The org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0
serialization class is deprecated.
 +[INFO] AbstractChannelizer - Configured application/vnd.gremlin-v3.0+gryo with org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0
 +[WARN] AbstractChannelizer - The org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0
serialization class is deprecated.
 +[INFO] AbstractChannelizer - Configured application/vnd.gremlin-v3.0+gryo-stringd with org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0
 +[INFO] AbstractChannelizer - Configured application/vnd.gremlin-v3.0+json with org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV3d0
 +[INFO] AbstractChannelizer - Configured application/json with org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV3d0
 +[INFO] AbstractChannelizer - Configured application/vnd.graphbinary-v1.0 with org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1
 +[INFO] AbstractChannelizer - Configured application/vnd.graphbinary-v1.0-stringd with org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1
 +[INFO] GremlinServer$1 - Gremlin Server configured with worker thread pool of 1, gremlin
pool of 8 and boss thread pool of 1.
 +[INFO] GremlinServer$1 - Channel started at port 8182.
 +----
  
 -The `Gremlin.Net.Driver.Remote.DriverRemoteConnection` is provided as part of Apache TinkerPop’s
Gremlin.Net.
 +NOTE: The command to use `install` need only be executed once to gather `gremlin-python`
dependencies into Gremlin Servers'
 +path. Future starts of Gremlin Server will not require that command.
  
 -IMPORTANT: For developers wishing to provide another driver implementation, be sure to implement
`IRemoteConnection` in
 -`Gremlin.Net.Process.Remote` so it can then be used by Gremlin.Net’s `GraphTraversal`.
 +WARNING: As explained throughout the documentation, when possible <<a-note-on-lambdas,avoid>>
lambdas. If lambdas
 +must be used, then consider submitting Groovy lambdas as opposed to Python-based ones. The
`GremlinGroovyScriptEngine`
 +is far more featured and performant than its Jython sibling and will likely yield better
results.
  
 -When Gremlin Server is running, Gremlin.Net can communicate with Gremlin Server by sending
traversals serialized as `Bytecode`.
 +=== Submitting Scripts
  
 -IMPORTANT: Gremlin.Net is not compatible with GraphSON 1.0.
 +WARNING: TinkerPop does not recommend submitting script-based requests and generally continues
to support this feature
 +for legacy reasons and corner use cases which are still not completely addressed by the
Gremlin language. Please
 +consider using bytecode-based requests instead when possible.
  
 -A traversal source can be spawned anonymously using an `AnonymousTraversalSource` which
can be statically imported as
 -follows:
 +The `Client` class implementation/interface is based on the Java Driver, with some restrictions.
Most notably,
 +Gremlin-Python does not yet implement the `Cluster` class. Instead, `Client` is instantiated
directly.
 +Usage is as follows:
  
 -[source,csharp]
 +[source,python]
  ----
 -using static Gremlin.Net.Process.Traversal.AnonymousTraversalSource;
 +from gremlin_python.driver import client <1>
 +client = client.Client('ws://localhost:8182/gremlin', 'g') <2>
  ----
  
 -which will expose a static `Traversal()` method which can be used as follows to yield a
`GraphTraversalSource` assigned
 -to "g" and configured to connect to Gremlin Server at "localhost:8182":
 +<1> Import the Gremlin-Python `client` module.
 +<2> Opens a reference to `localhost` - note that there are various configuration options
that can be passed
 +to the `Client` object upon instantiation as keyword arguments.
  
 -[source,csharp]
 +Once a `Client` instance is ready, it is possible to issue some Gremlin:
 +
 +[source,python]
  ----
 -var remoteConnection = new DriverRemoteConnection(new GremlinClient(new GremlinServer("localhost",
8182)));
 -var g = Traversal().WithRemote(remoteConnection);
 +result_set = client.submit("[1,2,3,4]")  <1>
 +future_results = result_set.all()  <2>
 +results = future_results.result() <3>
 +assert results == [1, 2, 3, 4] <4>
 +
 +future_result_set = client.submitAsync("[1,2,3,4]") <5>
 +result_set = future_result_set.result() <6>
 +result = result_set.one() <7>
 +assert results == [1, 2, 3, 4] <8>
 +assert result_set.done.done() <9>
 +
 +client.close() <10>
  ----
  
 -When a traversal from the `GraphTraversalSource` is iterated, the traversal’s `Bytecode`
is sent over the wire via the registered
 -`IRemoteConnection`. The bytecode is used to construct the equivalent traversal at the remote
traversal source.
 -Moreover, typically the bytecode is analyzed to determine which language the bytecode should
be translated to. If the traversal
 -does not contain lambdas, the remote location (e.g. Gremlin Server) will typically
 -use Gremlin-Java. If it has lambdas written in Groovy, it will use Gremlin-Groovy (e.g.
`GremlinGroovyScriptEngine`).
 -Likewise, if it has lambdas represented in Python, it will use Gremlin-Python (e.g. `GremlinJythonScriptEngine`).
 +<1> Submit a script that simply returns a `List` of integers.  This method blocks
until the request is written to
 +the server and a `ResultSet` is constructed.
 +<2> Even though the `ResultSet` is constructed, it does not mean that the server has
sent back the results (or even
 +evaluated the script potentially).  The `ResultSet` is just a holder that is awaiting the
results from the server. The `all` method
 +returns a `concurrent.futures.Future` that resolves to a list when it is complete.
 +<3> Block until the the script is evaluated and results are sent back by the server.
 +<4> Verify the result.
 +<5> Submit the same script to the server but don't block.
 +<6> Wait until request is written to the server and `ResultSet` is constructed.
 +<7> Read a single result off the result stream.
 +<8> Again, verify the result.
 +<9> Verify that the all results have been read and stream is closed.
 +<10> Close client and underlying pool connections.
  
 -IMPORTANT: Gremlin.Net’s `ITraversal` interface supports the standard Gremlin methods
such as `Next()`, `NextTraverser()`, `ToSet()`,
 -`ToList()`, etc. Such "terminal" methods trigger the evaluation of the traversal.
 +[[gremlin-python-dsl]]
 +=== Domain Specific Languages
  
 -=== RemoteConnection Submission
 +Writing a Gremlin <<dsl,Domain Specific Language>> (DSL) in Python simply requires
direct extension of several classes:
  
 -Very similar to Gremlin-Python and Gremlin-Java, there are various ways to submit a traversal
to a `IRemoteConnection` using
 -terminal/action methods off of `ITraversal`.
 +* `GraphTraversal` - which exposes the various steps used in traversal writing
 +* `__` - which spawns anonymous traversals from steps
 +* `GraphTraversalSource` - which spawns `GraphTraversal` instances
  
 -* `ITraversal.Next()`
 -* `ITraversal.NextTraverser()`
 -* `ITraversal.ToList()`
 -* `ITraversal.ToSet()`
 -* `ITraversal.Iterate()`
 +The Social DSL based on the link:http://tinkerpop.apache.org/docs/current/images/tinkerpop-modern.png["modern"
toy graph]
 +might look like this:
  
 -=== Configuration
 +[source,python]
 +----
 +class SocialTraversal(GraphTraversal):
  
 -The following sections describe how the Gremlin.Net driver can be configured.
 +    def knows(self, person_name):
 +        return self.out("knows").hasLabel("person").has("name", person_name)
  
 -==== Gremlin Server
 +    def youngestFriendsAge(self):
 +        return self.out("knows").hasLabel("person").values("age").min()
  
 -The connection properties for the Gremlin.Net driver can be passed to the `GremlinServer`
instance as keyword arguments:
 +    def createdAtLeast(self, number):
 +        return self.outE("created").count().is_(P.gte(number))
  
 -[width="100%",cols="3,10,^2",options="header"]
 -|=========================================================
 -|Key |Description |Default
 -|hostname |The hostname that the driver will connect to. |localhost
 -|port |The port on which Gremlin Server can be reached. |8182
 -|enableSsl |Determines if SSL should be enabled or not. If enabled on the server then it
must be enabled on the client. |false
 -|username |The username to submit on requests that require authentication. |_none_
 -|password |The password to submit on requests that require authentication. |_none_
 -|=========================================================
 +class __(AnonymousTraversal):
  
 -==== GraphSON Serialization
 +    graph_traversal = SocialTraversal
  
 -The Gremlin.Net driver uses by default GraphSON 3.0 but it is also possible to use GraphSON
2.0 which can be necessary
 -when the server does not support GraphSON 3.0 yet:
 +    @classmethod
 +    def knows(cls, *args):
 +        return cls.graph_traversal(None, None, Bytecode()).knows(*args)
  
 -[source,csharp]
 +    @classmethod
 +    def youngestFriendsAge(cls, *args):
 +        return cls.graph_traversal(None, None, Bytecode()).youngestFriendsAge(*args)
 +
 +    @classmethod
 +    def createdAtLeast(cls, *args):
 +        return cls.graph_traversal(None, None, Bytecode()).createdAtLeast(*args)
 +
 +
 +class SocialTraversalSource(GraphTraversalSource):
 +
 +    def __init__(self, *args, **kwargs):
 +        super(SocialTraversalSource, self).__init__(*args, **kwargs)
 +        self.graph_traversal = SocialTraversal
 +
 +    def persons(self, *args):
 +        traversal = self.get_graph_traversal()
 +        traversal.bytecode.add_step("V")
 +        traversal.bytecode.add_step("hasLabel", "person")
 +
 +        if len(args) > 0:
 +            traversal.bytecode.add_step("has", "name", P.within(args))
 +
 +        return traversal
 +----
 +
 +NOTE: The `AnonymousTraversal` class above is just an alias for `+__+` as in
 +`+from gremlin_python.process.graph_traversal import __ as AnonymousTraversal+`
 +
 +Using the DSL is straightforward and just requires that the graph instance know the `SocialTraversalSource`
should
 +be used:
 +
 +[source,python]
  ----
 -var client = new GremlinClient(new GremlinServer("localhost", 8182), new GraphSON2Reader(),
 -    new GraphSON2Writer(), GremlinClient.GraphSON2MimeType);
 +social = Graph().traversal(SocialTraversalSource).withRemote(DriverRemoteConnection('ws://localhost:8182/gremlin','g'))
 +social.persons("marko").knows("josh")
 +social.persons("marko").youngestFriendsAge()
 +social.persons().filter(__.createdAtLeast(2)).count()
  ----
  
 -=== Static Enums and Methods
 +=== Syntactic Sugar
  
 -Gremlin has various tokens (e.g. `T`, `P`, `Order`, `Operator`, etc.) that are represented
in Gremlin.Net as classes.
 +Python supports meta-programming and operator overloading. There are three uses of these
techniques in Gremlin-Python
 +that makes traversals a bit more concise.
  
 -These can be used analogously to how they are used in Gremlin-Java.
 +[gremlin-python,modern]
 +----
 +g.V().both()[1:3].toList()
 +g.V().both()[1].toList()
 +g.V().both().name.toList()
 +----
  
 -[source,csharp]
 -g.V().HasLabel("person").Has("age",P.Gt(30)).Order().By("age",Order.desc).ToList()
 +[[gremlin-python-differences]]
 +=== Differences
 +
 +In situations where Python reserved words and global functions overlap with standard Gremlin
steps and tokens, those
 +bits of conflicting Gremlin get an underscore appended as a suffix:
  
 -Moreover, the class prefixes can be omitted with a `using static`.
 +*Steps* - <<and-step,and_()>>, <<as-step,as_()>>, <<from-step,from_()>>,
<<is-step,is_()>>, <<in-step,in_()>>,
 +<<not-step,not_()>>, <<or-step,or_()>>, <<with-step,with_()>>
 +
 +*Tokens* - <<a-note-on-scopes,Scope.global_>>
 +
 +=== Limitations
 +
 +* Traversals that return a `Set` *might* be coerced to a `List` in Python. In the case of
Python, number equality
 +is different from JVM languages which produces different `Set` results when those types
are in use. When this case
 +is detected during deserialization, the `Set` is coerced to a `List` so that traversals
return consistent
 +results within a collection across different languages. If a `Set` is needed then convert
`List` results
 +to `Set` manually.
 +* Gremlin is capable of returning `Dictionary` results that use non-hashable keys (e.g.
Dictionary as a key) and Python
 +does not support that at a language level. Gremlin that returns such results will need to
be re-written to avoid that.
 +
 +anchor:gremlin-DotNet[]
 +[[gremlin-dotnet]]
 +== Gremlin.Net
 +
 +image:gremlin-dotnet-logo.png[width=371,float=right] Apache TinkerPop's Gremlin.Net implements
Gremlin within the C#
 +language. It targets .NET Standard and can therefore be used on different operating systems
and with different .NET
 +frameworks, such as .NET Framework and link:https://www.microsoft.com/net/core[.NET Core].
Since the C# syntax is very
 +similar to that of Java, it should be very easy to switch between Gremlin-Java and Gremlin.Net.
The only major
 +syntactical difference is that all method names in Gremlin.Net use PascalCase as opposed
to camelCase in Gremlin-Java
 +in order to comply with .NET conventions.
 +
 +[source,powershell]
 +nuget install Gremlin.Net
 +
 +=== Connecting
 +
 +The pattern for connecting is described in <<connecting-gremlin,Connecting Gremlin>>
and it basically distills down to
 +creating a `GraphTraversalSource`. A `GraphTraversalSource` is created from the `AnonymousTraversalSource.traversal()`
 +method where the "g" provided to the `DriverRemoteConnection` corresponds to the name of
a `GraphTraversalSource` on
 +the remote end.
  
  [source,csharp]
  ----
@@@ -1107,82 -508,10 +1111,86 @@@ g.V().Out().Map<int>(Lambda.Python("lam
  The `ILambda` interface returned by these two methods inherits interfaces like `IFunction`
and `IPredicate` that mirror
  their Java counterparts which makes it possible to use lambdas with Gremlin.Net for the
same steps as in Gremlin-Java.
  
+ TIP: When running into situations where Groovy cannot properly discern a method signature
based on the `Lambda`
+ instance created, it will help to fully define the closure in the lambda expression - so
rather than
+ `Lambda.Groovy("it.get().value('name'))`, prefer `Lambda.Groovy("x -> x.get().value('name'))`.
+ 
 +=== Submitting Scripts
 +
 +WARNING: TinkerPop does not recommend submitting script-based requests and generally continues
to support this feature
 +for legacy reasons and corner use cases which are still not completely addressed by the
Gremlin language. Please
 +consider using bytecode-based requests instead when possible.
 +
 +Gremlin scripts are sent to the server from a `IGremlinClient` instance.  A `IGremlinClient`
is created as follows:
 +
 +[source,csharp]
 +----
 +include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=submittingScripts]
 +----
 +
 +If the remote system has authentication and SSL enabled, then the `GremlinServer` object
can be configured as follows:
 +
 +[source,csharp]
 +----
 +include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=submittingScriptsWithAuthentication]
 +----
 +
 +[[gremlin-net-dsl]]
 +=== Domain Specific Languages
 +
 +Developing a <<dsl,Domain Specific Language>> (DSL) for .Net is most easily
implemented using
 +link:https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods[Extension
Methods]
 +as they don't require direct extension of classes in the TinkerPop hierarchy. Extension
Method classes simply need to
 +be constructed for the `GraphTraversal` and the `GraphTraversalSource`. Unfortunately, anonymous
traversals (spawned
 +from `+__+`) can't use the Extension Method approach as they do not work for static classes
and static classes can't be
 +extended. The only option is to re-implement the methods of `+__+` as a wrapper in the anonymous
traversal for the DSL
 +or to simply create a static class for the DSL and use the two anonymous traversals creators
independently. The
 +following example uses the latter approach as it saves a lot of boilerplate code with the
minor annoyance of having a
 +second static class to deal with when writing traversals rather than just calling `+__+`
for everything.
 +
 +[source,csharp]
 +----
 +include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsDsl.cs[tags=dsl]
 +----
 +
 +Note the creation of `__Social` as the Social DSL's "extension" to the available ways in
which to spawn anonymous
 +traversals. The use of the double underscore prefix in the name is just a convention to
consider using and is not a
 +requirement. To use the DSL, bring it into scope with the `using` directive:
 +
 +[source,csharp]
 +----
 +include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsDslTests.cs[tags=dslUsing]
 +----
 +
 +and then it can be called from the application as follows:
 +
 +[source,csharp]
 +----
 +include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsDslTests.cs[tags=dslExamples]
 +----
 +
 +anchor:gremlin-dotnet-template[]
 +[[dotnet-application-examples]]
 +=== Application Examples
 +
 +This link:https://docs.microsoft.com/dotnet/core/tools/custom-templates[dotnet template]
helps getting started with
 +<<gremlin-dotnet,Gremlin.Net>>. It creates a new C# console project that shows
how to connect to a
 +<<gremlin-server,Gremlin Server>> with Gremlin.Net.
 +
 +You can install the template with the dotnet CLI tool:
 +[source,shell]
 +dotnet new -i Gremlin.Net.Template
 +
 +After the template is installed, a new project based on this template can be installed:
 +
 +[source,shell]
 +dotnet new gremlin
 +
 +Specify the output directory for the new project which will then also be used as the name
of the created project:
 +
 +[source,shell]
 +dotnet new gremlin -o MyFirstGremlinProject
 +
  [[gremlin-javascript]]
  == Gremlin-JavaScript
  
diff --cc gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslator.java
index b961821,ba14996..505f88a
--- 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
@@@ -24,9 -24,9 +24,10 @@@ import org.apache.commons.configuration
  import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
  import org.apache.tinkerpop.gremlin.process.traversal.P;
  import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions;
 +import org.apache.tinkerpop.gremlin.process.traversal.TextP;
  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.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
  import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent;
  import org.apache.tinkerpop.gremlin.process.traversal.strategy.TraversalStrategyProxy;
@@@ -96,158 -98,170 +100,181 @@@ public final class GroovyTranslator imp
          return this.traversalSource;
      }
  
 -    ///////
 +    /**
 +     * Performs standard type translation for the TinkerPop types to Groovy.
 +     */
 +    public static class DefaultTypeTranslator implements TypeTranslator {
  
 -    private String internalTranslate(final String start, final Bytecode bytecode) {
 -        final StringBuilder traversalScript = new StringBuilder(start);
 -        for (final Bytecode.Instruction instruction : bytecode.getInstructions()) {
 -            final String methodName = instruction.getOperator();
 -            if (0 == instruction.getArguments().length)
 -                traversalScript.append(".").append(methodName).append("()");
 -            else {
 -                traversalScript.append(".");
 -                String temp = methodName + "(";
 +        @Override
 +        public Object apply(final String traversalSource, final Object o) {
 +            if (o instanceof Bytecode)
 +                return internalTranslate(traversalSource, (Bytecode) o);
 +            else
 +                return convertToString(o);
 +        }
  
 -                // have to special case withSack() for Groovy because UnaryOperator and
BinaryOperator signatures
 -                // make it impossible for the interpreter to figure out which function to
call. specifically we need
 -                // to discern between:
 -                //     withSack(A initialValue, UnaryOperator<A> splitOperator)
 -                //     withSack(A initialValue, BinaryOperator<A> splitOperator)
 -                // and:
 -                //     withSack(Supplier<A> initialValue, UnaryOperator<A> mergeOperator)
 -                //     withSack(Supplier<A> initialValue, BinaryOperator<A>
mergeOperator)
 -                if (methodName.equals(TraversalSource.Symbols.withSack) &&
 -                        instruction.getArguments().length == 2 && instruction.getArguments()[1]
instanceof Lambda) {
 -                    final String castFirstArgTo = instruction.getArguments()[0] instanceof
Lambda ?
 -                            Supplier.class.getName() : "";
 -                    final Lambda secondArg = (Lambda) instruction.getArguments()[1];
 -                    final String castSecondArgTo = secondArg.getLambdaArguments() == 1 ?
UnaryOperator.class.getName() :
 -                            BinaryOperator.class.getName();
 -                    if (!castFirstArgTo.isEmpty())
 -                        temp = temp + String.format("(%s) ", castFirstArgTo);
 -                    temp = temp + String.format("%s, (%s) %s,",
 -                            convertToString(instruction.getArguments()[0]), castSecondArgTo,
 -                                    convertToString(instruction.getArguments()[1]));
 -                } else {
 -                    for (final Object object : instruction.getArguments()) {
 -                        temp = temp + convertToString(object) + ",";
 -                    }
 +        protected String convertToString(final Object object) {
 +            if (object instanceof Bytecode.Binding)
 +                return ((Bytecode.Binding) object).variable();
 +            else if (object instanceof Bytecode)
 +                return internalTranslate("__", (Bytecode) object);
 +            else if (object instanceof Traversal)
 +                return convertToString(((Traversal) object).asAdmin().getBytecode());
 +            else if (object instanceof String) {
 +                return (((String) object).contains("\"") ? "\"\"\"" + StringEscapeUtils.escapeJava((String)
object) + "\"\"\"" : "\"" + StringEscapeUtils.escapeJava((String) object) + "\"")
 +                        .replace("$", "\\$");
 +            } else if (object instanceof Set) {
 +                final Set<String> set = new HashSet<>(((Set) object).size());
 +                for (final Object item : (Set) object) {
 +                    set.add(convertToString(item));
 +                }
 +                return set.toString() + " as Set";
 +            } else if (object instanceof List) {
 +                final List<String> list = new ArrayList<>(((List) object).size());
 +                for (final Object item : (List) object) {
 +                    list.add(convertToString(item));
 +                }
 +                return list.toString();
 +            } else if (object instanceof Map) {
 +                final StringBuilder map = new StringBuilder("[");
 +                for (final Map.Entry<?, ?> entry : ((Map<?, ?>) object).entrySet())
{
 +                    map.append("(").
 +                            append(convertToString(entry.getKey())).
 +                            append("):(").
 +                            append(convertToString(entry.getValue())).
 +                            append("),");
                  }
 -                traversalScript.append(temp.substring(0, temp.length() - 1)).append(")");
 -            }
 -        }
 -        return traversalScript.toString();
 -    }
  
 -    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);
 +                // only need to remove this last bit if entries were added
 +                if (!((Map<?, ?>) object).isEmpty())
 +                    map.deleteCharAt(map.length() - 1);
  
 -        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);
 -        else if (object instanceof Traversal)
 -            return convertToString(((Traversal) object).asAdmin().getBytecode());
 -        else if (object instanceof String) {
 -            return (((String) object).contains("\"") ? "\"\"\"" + StringEscapeUtils.escapeJava((String)
object) + "\"\"\"" : "\"" + StringEscapeUtils.escapeJava((String) object) + "\"")
 -                    .replace("$", "\\$");
 -        } else if (object instanceof Set) {
 -            final Set<String> set = new HashSet<>(((Set) object).size());
 -            for (final Object item : (Set) object) {
 -                set.add(convertToString(item));
 -            }
 -            return set.toString() + " as Set";
 -        } else if (object instanceof List) {
 -            final List<String> list = new ArrayList<>(((List) object).size());
 -            for (final Object item : (List) object) {
 -                list.add(convertToString(item));
 -            }
 -            return list.toString();
 -        } else if (object instanceof Map) {
 -            final StringBuilder map = new StringBuilder("[");
 -            for (final Map.Entry<?, ?> entry : ((Map<?, ?>) object).entrySet())
{
 -                map.append("(").
 -                        append(convertToString(entry.getKey())).
 -                        append("):(").
 -                        append(convertToString(entry.getValue())).
 -                        append("),");
 -            }
 +                return map.append("]").toString();
 +            } else if (object instanceof Long)
 +                return object + "L";
 +            else if (object instanceof Double)
 +                return object + "d";
 +            else if (object instanceof Float)
 +                return object + "f";
 +            else if (object instanceof Integer)
 +                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)
 +                return "SackFunctions.Barrier." + object.toString();
 +            else if (object instanceof VertexProperty.Cardinality)
 +                return "VertexProperty.Cardinality." + object.toString();
 +            else if (object instanceof TraversalOptionParent.Pick)
 +                return "TraversalOptionParent.Pick." + object.toString();
 +            else if (object instanceof Enum)
 +                return ((Enum) object).getDeclaringClass().getSimpleName() + "." + object.toString();
 +            else if (object instanceof Element) {
 +                if (object instanceof Vertex) {
 +                    final Vertex vertex = (Vertex) object;
 +                    return "new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex("
+
 +                            convertToString(vertex.id()) + "," +
 +                            convertToString(vertex.label()) + ", Collections.emptyMap())";
 +                } else if (object instanceof Edge) {
 +                    final Edge edge = (Edge) object;
 +                    return "new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedEdge("
+
 +                            convertToString(edge.id()) + "," +
 +                            convertToString(edge.label()) + "," +
 +                            "Collections.emptyMap()," +
 +                            convertToString(edge.outVertex().id()) + "," +
 +                            convertToString(edge.outVertex().label()) + "," +
 +                            convertToString(edge.inVertex().id()) + "," +
 +                            convertToString(edge.inVertex().label()) + ")";
 +                } else {// VertexProperty
 +                    final VertexProperty vertexProperty = (VertexProperty) object;
 +                    return "new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertexProperty("
+
 +                            convertToString(vertexProperty.id()) + "," +
 +                            convertToString(vertexProperty.label()) + "," +
 +                            convertToString(vertexProperty.value()) + "," +
 +                            "Collections.emptyMap()," +
 +                            convertToString(vertexProperty.element()) + ")";
 +                }
 +            } else if (object instanceof Lambda) {
 +                final String lambdaString = ((Lambda) object).getLambdaScript().trim();
 +                return lambdaString.startsWith("{") ? lambdaString : "{" + lambdaString
+ "}";
 +            } else if (object instanceof TraversalStrategyProxy) {
 +                final TraversalStrategyProxy proxy = (TraversalStrategyProxy) object;
 +                if (proxy.getConfiguration().isEmpty())
 +                    return proxy.getStrategyClass().getCanonicalName() + ".instance()";
 +                else
 +                    return proxy.getStrategyClass().getCanonicalName() + ".create(new org.apache.commons.configuration.MapConfiguration("
+ convertToString(ConfigurationConverter.getMap(proxy.getConfiguration())) + "))";
 +            } else if (object instanceof TraversalStrategy) {
 +                return convertToString(new TraversalStrategyProxy(((TraversalStrategy) object)));
 +            } else
 +                return null == object ? "null" : object.toString();
 +        }
  
 -            // only need to remove this last bit if entries were added
 -            if (!((Map<?, ?>) object).isEmpty())
 -                map.deleteCharAt(map.length() - 1);
 +        protected String internalTranslate(final String start, final Bytecode bytecode)
{
 +            final StringBuilder traversalScript = new StringBuilder(start);
 +            for (final Bytecode.Instruction instruction : bytecode.getInstructions()) {
 +                final String methodName = instruction.getOperator();
 +                if (0 == instruction.getArguments().length)
 +                    traversalScript.append(".").append(methodName).append("()");
 +                else {
 +                    traversalScript.append(".");
 +                    String temp = methodName + "(";
-                     for (final Object object : instruction.getArguments()) {
-                         temp = temp + convertToString(object) + ",";
+ 
 -            return map.append("]").toString();
 -        } else if (object instanceof Long)
 -            return object + "L";
 -        else if (object instanceof Double)
 -            return object + "d";
 -        else if (object instanceof Float)
 -            return object + "f";
 -        else if (object instanceof Integer)
 -            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)
 -            return "SackFunctions.Barrier." + object.toString();
 -        else if (object instanceof VertexProperty.Cardinality)
 -            return "VertexProperty.Cardinality." + object.toString();
 -        else if (object instanceof TraversalOptionParent.Pick)
 -            return "TraversalOptionParent.Pick." + object.toString();
 -        else if (object instanceof Enum)
 -            return ((Enum) object).getDeclaringClass().getSimpleName() + "." + object.toString();
 -        else if (object instanceof Element) {
 -            if (object instanceof Vertex) {
 -                final Vertex vertex = (Vertex) object;
 -                return "new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex("
+
 -                        convertToString(vertex.id()) + "," +
 -                        convertToString(vertex.label()) + ", Collections.emptyMap())";
 -            } else if (object instanceof Edge) {
 -                final Edge edge = (Edge) object;
 -                return "new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedEdge("
+
 -                        convertToString(edge.id()) + "," +
 -                        convertToString(edge.label()) + "," +
 -                        "Collections.emptyMap()," +
 -                        convertToString(edge.outVertex().id()) + "," +
 -                        convertToString(edge.outVertex().label()) + "," +
 -                        convertToString(edge.inVertex().id()) + "," +
 -                        convertToString(edge.inVertex().label()) + ")";
 -            } else {// VertexProperty
 -                final VertexProperty vertexProperty = (VertexProperty) object;
 -                return "new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertexProperty("
+
 -                        convertToString(vertexProperty.id()) + "," +
 -                        convertToString(vertexProperty.label()) + "," +
 -                        convertToString(vertexProperty.value()) + "," +
 -                        "Collections.emptyMap()," +
 -                        convertToString(vertexProperty.element()) + ")";
++                    // have to special case withSack() for Groovy because UnaryOperator
and BinaryOperator signatures
++                    // make it impossible for the interpreter to figure out which function
to call. specifically we need
++                    // to discern between:
++                    //     withSack(A initialValue, UnaryOperator<A> splitOperator)
++                    //     withSack(A initialValue, BinaryOperator<A> splitOperator)
++                    // and:
++                    //     withSack(Supplier<A> initialValue, UnaryOperator<A>
mergeOperator)
++                    //     withSack(Supplier<A> initialValue, BinaryOperator<A>
mergeOperator)
++                    if (methodName.equals(TraversalSource.Symbols.withSack) &&
++                            instruction.getArguments().length == 2 && instruction.getArguments()[1]
instanceof Lambda) {
++                        final String castFirstArgTo = instruction.getArguments()[0] instanceof
Lambda ?
++                                Supplier.class.getName() : "";
++                        final Lambda secondArg = (Lambda) instruction.getArguments()[1];
++                        final String castSecondArgTo = secondArg.getLambdaArguments() ==
1 ? UnaryOperator.class.getName() :
++                                BinaryOperator.class.getName();
++                        if (!castFirstArgTo.isEmpty())
++                            temp = temp + String.format("(%s) ", castFirstArgTo);
++                        temp = temp + String.format("%s, (%s) %s,",
++                                convertToString(instruction.getArguments()[0]), castSecondArgTo,
++                                convertToString(instruction.getArguments()[1]));
++                    } else {
++                        for (final Object object : instruction.getArguments()) {
++                            temp = temp + convertToString(object) + ",";
++                        }
 +                    }
 +                    traversalScript.append(temp.substring(0, temp.length() - 1)).append(")");
 +                }
              }
 -        } else if (object instanceof Lambda) {
 -            final String lambdaString = ((Lambda) object).getLambdaScript().trim();
 -            return lambdaString.startsWith("{") ? lambdaString : "{" + lambdaString + "}";
 -        } else if (object instanceof TraversalStrategyProxy) {
 -            final TraversalStrategyProxy proxy = (TraversalStrategyProxy) object;
 -            if (proxy.getConfiguration().isEmpty())
 -                return proxy.getStrategyClass().getCanonicalName() + ".instance()";
 -            else
 -                return proxy.getStrategyClass().getCanonicalName() + ".create(new org.apache.commons.configuration.MapConfiguration("
+ convertToString(ConfigurationConverter.getMap(proxy.getConfiguration())) + "))";
 -        } else if (object instanceof TraversalStrategy) {
 -            return convertToString(new TraversalStrategyProxy(((TraversalStrategy) object)));
 -        } else
 -            return null == object ? "null" : object.toString();
 -    }
 +            return traversalScript.toString();
 +        }
  
 -    private StringBuilder convertPToString(final P p, final StringBuilder current) {
 -        if (p instanceof ConnectiveP) {
 -            final List<P<?>> list = ((ConnectiveP) p).getPredicates();
 -            for (int i = 0; i < list.size(); i++) {
 -                convertPToString(list.get(i), current);
 -                if (i < list.size() - 1)
 -                    current.append(p instanceof OrP ? ".or(" : ".and(");
 -            }
 -            current.append(")");
 -        } else
 -            current.append("P.").append(p.getBiPredicate().toString()).append("(").append(convertToString(p.getValue())).append(")");
 -        return current;
 +        protected StringBuilder convertPToString(final P p, final StringBuilder current)
{
 +            if (p instanceof TextP) return convertTextPToString((TextP) p, current);
 +            if (p instanceof ConnectiveP) {
 +                final List<P<?>> list = ((ConnectiveP) p).getPredicates();
 +                for (int i = 0; i < list.size(); i++) {
 +                    convertPToString(list.get(i), current);
 +                    if (i < list.size() - 1)
 +                        current.append(p instanceof OrP ? ".or(" : ".and(");
 +                }
 +                current.append(")");
 +            } else
 +                current.append("P.").append(p.getBiPredicate().toString()).append("(").append(convertToString(p.getValue())).append(")");
 +            return current;
 +        }
 +
 +        protected StringBuilder convertTextPToString(final TextP p, final StringBuilder
current) {
 +            current.append("TextP.").append(p.getBiPredicate().toString()).append("(").append(convertToString(p.getValue())).append(")");
 +            return current;
 +        }
      }
  }


Mime
View raw message