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 2023/01/10 18:36:10 UTC

[tinkerpop] branch master updated (f9fbd98742 -> a80bba5781)

This is an automated email from the ASF dual-hosted git repository.

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


    from f9fbd98742 Merge branch '3.6-dev'
     new b8e6b2827d Alphabetize variants CTR
     new 097d3f7103 Merge branch '3.5-dev' into 3.6-dev
     new a80bba5781 Merge branch '3.6-dev'

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 docs/src/reference/gremlin-variants.asciidoc | 2784 +++++++++++++-------------
 1 file changed, 1392 insertions(+), 1392 deletions(-)


[tinkerpop] 01/03: Alphabetize variants CTR

Posted by sp...@apache.org.
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 b8e6b2827d68bfbc73205df00f201a0e75bd7ca2
Author: Stephen Mallette <st...@amazon.com>
AuthorDate: Tue Jan 10 13:33:34 2023 -0500

    Alphabetize variants CTR
---
 docs/src/reference/gremlin-variants.asciidoc | 2726 +++++++++++++-------------
 1 file changed, 1363 insertions(+), 1363 deletions(-)

diff --git a/docs/src/reference/gremlin-variants.asciidoc b/docs/src/reference/gremlin-variants.asciidoc
index 5e46d9be1e..30590dcd87 100644
--- a/docs/src/reference/gremlin-variants.asciidoc
+++ b/docs/src/reference/gremlin-variants.asciidoc
@@ -67,1388 +67,1515 @@ image::gremlin-variant-architecture.png[width=650]
 The following sections describe each language variant and driver that is officially TinkerPop a part of the project,
 providing more detailed information about usage, configuration and known limitations.
 
-[[gremlin-groovy]]
-== Gremlin-Groovy
-
-image:gremlin-groovy-drawing.png[width=130,float=right] Apache TinkerPop's Gremlin-Groovy implements Gremlin within the
-link:http://groovy.apache.org[Apache Groovy] language. As a JVM-based language variant, Gremlin-Groovy is backed by
-<<gremlin-java,Gremlin-Java>> constructs. Moreover, given its scripting nature, Gremlin-Groovy serves as the language of
-<<gremlin-console,Gremlin Console>> and <<gremlin-server,Gremlin Server>>.
-
-[source,groovy]
-----
-compile group: 'org.apache.tinkerpop', name: 'gremlin-core', version: 'x.y.z'
-compile group: 'org.apache.tinkerpop', name: 'gremlin-driver', version: 'x.y.z'
-----
-
-[[gremlin-groovy-differences]]
-=== Differences
-
-In Groovy, `as`, `in`, and `not` are reserved words. Gremlin-Groovy does not allow these steps to be called
-statically from the anonymous traversal `+__+` and therefore, must always be prefixed with `+__.+` For instance:
-`+g.V().as('a').in().as('b').where(__.not(__.as('a').out().as('b')))+`
-
-Since Groovy has access to the full JVM as Java does, it is possible to construct `Date`-like objects directly, but
-the Gremlin language does offer a `datetime()` function that is exposed in the Gremlin Console and as a function for
-Gremlin scripts sent to Gremlin Server. The function accepts the following forms of dates and times using a default
-time zone offset of UTC(+00:00):
-
-* `2018-03-22`
-* `2018-03-22T00:35:44`
-* `2018-03-22T00:35:44Z`
-* `2018-03-22T00:35:44.741`
-* `2018-03-22T00:35:44.741Z`
-* `2018-03-22T00:35:44.741+1600`
+[[gremlin-go]]
+== Gremlin-Go
 
-anchor:connecting-via-remotegraph[]
-anchor:connecting-via-java[]
-[[gremlin-java]]
-== Gremlin-Java
+image:gremlin-go.png[width=130,float=right] Apache TinkerPop's Gremlin-Go implements Gremlin within the link:https://go.dev/[Go] language and can therefore be used on different operating systems. Go's syntax has the similar constructs as Java including
+"dot notation" for function chaining (`a.b.c`) and round bracket function arguments (`a(b,c)`). Something unlike Java is that Gremlin-Go requires a
+`gremlingo` prefix when using the namespace (`a(b())` vs `gremlingo.a(gremlingo.T__.b())`). Anyone familiar with Gremlin-Java will be able to work
+with Gremlin-Go with relative ease. Moreover, there are a few added constructs to Gremlin-Go that make traversals a bit more
+succinct.
 
-image:gremlin-java-drawing.png[width=130,float=right] Apache TinkerPop's Gremlin-Java implements Gremlin within the
-Java language and can be used by any Java Virtual Machine. Gremlin-Java is considered the canonical, reference
-implementation of Gremlin and serves as the foundation by which all other Gremlin language variants should emulate.
-As the Gremlin Traversal Machine that processes Gremlin queries is also written in Java, it can be used in all three
-connection methods described in the <<connecting-gremlin,Connecting Gremlin>> Section.
+To install the Gremlin-Go as a dependency for your project, run the following in the root directory of your project that contains your `go.mod` file:
 
-[source,xml]
+[source,bash]
 ----
-<dependency>
-   <groupId>org.apache.tinkerpop</groupId>
-   <artifactId>gremlin-core</artifactId>
-   <version>x.y.z</version>
-</dependency>
-
-<!-- when using Gremlin Server or Remote Gremlin Provider a driver is required -->
-<dependency>
-   <groupId>org.apache.tinkerpop</groupId>
-   <artifactId>gremlin-driver</artifactId>
-   <version>x.y.z</version>
-</dependency>
-
-<!--
-alternatively the driver is packaged as an uberjar with shaded non-optional dependencies including gremlin-core and
-tinkergraph-gremlin which are not shaded.
--->
-<dependency>
-   <groupId>org.apache.tinkerpop</groupId>
-   <artifactId>gremlin-driver</artifactId>
-   <version>x.y.z</version>
-   <classifier>shaded</classifier>
-   <!-- The shaded JAR uses the original POM, therefore conflicts may still need resolution -->
-   <exclusions>
-      <exclusion>
-         <groupId>io.netty</groupId>
-         <artifactId>*</artifactId>
-      </exclusion>
-   </exclusions>
-</dependency>
+go get github.com/apache/tinkerpop/gremlin-go/v3[optionally append @<version>, such as @v3.5.3]
 ----
 
-[[gremlin-java-connecting]]
+[[gremlin-go-connecting]]
 === Connecting
 
-The pattern for connecting is described in <<connecting-gremlin,Connecting Gremlin>> and it basically distills down
-to creating a `GraphTraversalSource`. For <<connecting-embedded,embedded>> mode, this involves first creating a
-`Graph` and then spawning the `GraphTraversalSource`:
+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 anonymous `Traversal_()`.
 
-[source,java]
+[source,go]
 ----
-Graph graph = ...;
-GraphTraversalSource g = traversal().withEmbedded(graph);
+remote, err := gremlingo.NewDriverRemoteConnection("ws://localhost:8182/gremlin")
+g := gremlingo.Traversal_().WithRemote(remote)
 ----
 
-Using "g" it is then possible to start writing Gremlin. The "g" allows for the setting of many configuration options
-which affect traversal execution. The <<traversal, Traversal>> Section describes some of these options and some are
-only suitable with <<connecting-embedded,embedded>> style usage. For remote options however there are some added
-configurations to consider and this section looks to address those.
-
-When connecting to <<connecting-gremlin-server,Gremlin Server>> or <<connecting-rgp,Remote Gremlin Providers>>  it
-is possible to configure the `DriverRemoteConnection` manually as shown in earlier examples where the host and port
-are provided as follows:
+If you need to additional parameters to connection setup, you can pass in a configuration function.
 
-[source,java]
+[source,go]
 ----
-GraphTraversalSource g = traversal().withRemote(DriverRemoteConnection.using("localhost",8182,"g"));
+remote, err := gremlingo.NewDriverRemoteConnection("ws://localhost:8182/gremlin",
+  func(settings *DriverRemoteConnectionSettings) {
+    settings.TraversalSource = "gmodern"
+  })
 ----
 
-It is also possible to create it from a configuration. The most basic way to do so involves the following line of code:
+Gremlin-go supports plain text authentication. It can be set in the connection function.
 
-[source,java]
+[source,go]
 ----
-GraphTraversalSource g = traversal().withRemote('conf/remote-graph.properties');
+remote, err := gremlingo.NewDriverRemoteConnection("ws://localhost:8182/gremlin",
+  func(settings *DriverRemoteConnectionSettings) {
+    settings.TlsConfig = &tls.Config{InsecureSkipVerify: true}
+    settings.AuthInfo = gremlingo.BasicAuthInfo("login", "password")
+  })
 ----
 
-The `remote-graph.properties` file simply provides connection information to the `GraphTraversalSource` which is used
-to configure a `RemoteConnection`. That file looks like this:
+If you authenticate to a remote <<connecting-gremlin-server,Gremlin Server>> or
+<<connecting-rgp,Remote Gremlin Provider>>, this server normally has SSL activated and the websockets url will start
+with 'wss://'.
 
-[source,text]
+Some connection options can also be set on individual requests made through the using `With()` step on the
+`TraversalSource`. For instance to set request timeout to 500 milliseconds:
+
+[source,go]
 ----
-gremlin.remote.remoteConnectionClass=org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteConnection
-gremlin.remote.driver.clusterFile=conf/remote-objects.yaml
-gremlin.remote.driver.sourceName=g
+results, err := g.With("evaluationTimeout", 500).V().Out("knows").ToList()
 ----
 
-The `RemoteConnection` is an interface that provides the transport mechanism for "g" and makes it possible to for
-that mechanism to be altered (typically by graph providers who have their own protocols). TinkerPop provides one such
-implementation called the `DriverRemoteConnection` which enables transport over Gremlin Server protocols using the
-TinkerPop driver. The driver is configured by the specified `gremlin.remote.driver.clusterFile` and the local "g" is
-bound to the `GraphTraversalSource` on the remote end with `gremlin.remote.driver.sourceName` which in this case is
-also "g".
-
-There are other ways to configure the traversal using `withRemote()` as it has other overloads. It can take an
-Apache Commons `Configuration` object which would have keys similar to those shown in the properties file and it
-can also take a `RemoteConnection` instance directly. The latter is interesting in that it means it is possible to
-programmatically construct all aspects of the `RemoteConnection`. For TinkerPop usage, that might mean directly
-constructing the `DriverRemoteConnection` and the driver instance that supplies the transport mechanism. For example,
-the command shown above could be re-written using programmatic construction as follows:
+The following options are allowed on a per-request basis in this fashion: `batchSize`, `requestId`, `userAgent` and
+`evaluationTimeout`.
 
-[source,java]
-----
-Cluster cluster = Cluster.open();
-GraphTraversalSource g = traversal().withRemote(DriverRemoteConnection.using(cluster, "g"));
-----
+anchor:go-imports[]
+[[gremlin-go-imports]]
+=== Common Imports
 
-Please consider the following example:
+There are a number of classes, functions and tokens that are typically used with Gremlin. The following import
+provide most of the typical functionality required to use Gremlin:
 
-[gremlin-groovy]
+[source,go]
 ----
-g = traversal().withRemote('conf/remote-graph.properties')
-g.V().elementMap()
-g.close()
+import (
+	"github.com/apache/tinkerpop/gremlin-go/driver"
+)
 ----
 
-[source,java]
+These can be used analogously to how they are used in Gremlin-Java.
+
+[source,go]
 ----
-GraphTraversalSource g = traversal().withRemote("conf/remote-graph.properties");
-List<Map> list = g.V().elementMap();
-g.close();
+results, err := g.V().HasLabel("person").Has("age", gremlingo.T__.Is(gremlingo.P.Gt(30))).Order().By("age", gremlingo.Desc).ToList()
+[v[6], v[4]]
 ----
 
-Note the call to `close()` above. The call to `withRemote()` internally instantiates a connection via the driver that
-can only be released by "closing" the `GraphTraversalSource`. It is important to take that step to release network
-resources associated with `g`.
+anchor:go-configuration[]
+[[gremlin-go-configuration]]
+=== Configuration
 
-If working with multiple remote `TraversalSource` instances it is more efficient to construct `Cluster` and `Client`
-objects and then re-use them.
+The following table describes the various configuration options for the Gremlin-go Driver. They
+can be passed to the `NewClient` or `NewDriverRemoteConnection` functions as configuration function arguments:
 
-[gremlin-groovy]
-----
-cluster = Cluster.open('conf/remote-objects.yaml')
-client = cluster.connect()
-g = traversal().withRemote(DriverRemoteConnection.using(client, "g"))
-g.V().elementMap()
-g.close()
-client.close()
-cluster.close()
-----
+[width="100%",cols="3,10,^2",options="header"]
+|=========================================================
+|Key |Description |Default
+|TraversalSource |Traversal source. |"g"
+|TransporterType |Transporter type. |Gorilla
+|LogVerbosity |Log verbosity.|gremlingo.INFO
+|Logger |Instance of logger. |log
+|Language |Language used for logging messages. |language.English
+|AuthInfo |Authentification info, can be build with BasicAuthInfo() or HeaderAuthInfo(). |empty
+|TlsConfig |TLS configuration. |empty
+|KeepAliveInterval |Keep connection alive interval. |5 seconds
+|WriteDeadline |Write deadline. |3 seconds
+|ConnectionTimeout | Timeout for establishing connection. |45 seconds
+|NewConnectionThreshold | Minimum amount of concurrent active traversals on a connection to trigger creation of a new connection. |4
+|MaximumConcurrentConnections | Maximum number of concurrent connections. |number of runtime processors
+|EnableCompression |Flag to enable compression. |false
+|ReadBufferSize |Specify I/O buffer sizes in bytes. If a buffer size is zero, then a useful default size is used |0
+|WriteBufferSize |Specify I/O buffer sizes in bytes. If a buffer size is zero, then a useful default size is used |0
+|Session |Session ID. |""
+|EnableUserAgentOnConnect |Enables sending a user agent to the server during connection requests.
+More details can be found in provider docs
+link:https://tinkerpop.apache.org/docs/x.y.z/dev/provider/#_graph_driver_provider_requirements[here].|true
+|=========================================================
 
-If the `Client` instance is supplied externally, as is shown above, then it is not closed implicitly by the close of
-"g".  Closing "g" will have no effect on "client" or "cluster". When supplying them externally, the `Client` and
-`Cluster` objects must also be closed explicitly. It's worth noting that the close of a `Cluster` will close all
-`Client` instances spawned by the `Cluster`.
+[[gremlin-go-strategies]]
+=== Traversal Strategies
 
-Some connection options can also be set on individual requests made through the Java driver using `with()` step
-on the `TraversalSource`. For instance to set request timeout to 500 milliseconds:
+In order to add and remove <<traversalstrategy,traversal strategies>> from a traversal source, Gremlin-Go has a
+`TraversalStrategy` interface along with a collection of functions that mirror the standard Gremlin-Java strategies.
 
-[source,java]
+[source,go]
 ----
-GraphTraversalSource g = traversal().withRemote(conf);
-List<Vertex> vertices = g.with(Tokens.ARGS_EVAL_TIMEOUT, 500L).V().out("knows").toList()
+promise := g.WithStrategies(gremlingo.ReadOnlyStrategy()).AddV("person").Property("name", "foo").Iterate()
 ----
 
-The following options are allowed on a per-request basis in this fashion: `batchSize`, `requestId`, `userAgent` and
-`evaluationTimeout` (formerly `scriptEvaluationTimeout` which is also supported but now deprecated). Use of `Tokens`
-to reference these options is preferred.
+NOTE: Many of the `TraversalStrategy` classes in Gremlin-Go are proxies to the respective strategy on
+Apache TinkerPop's JVM-based Gremlin traversal machine. As such, their `apply(Traversal)` method does nothing. However,
+the strategy is encoded in the Gremlin-Go bytecode and transmitted to the Gremlin traversal machine for
+re-construction machine-side.
 
-anchor:java-imports[]
-[[gremlin-java-imports]]
-=== Common Imports
+[[gremlin-go-transactions]]
+=== Transactions
 
-There are a number of classes, functions and tokens that are typically used with Gremlin. The following imports
-provide most of the common functionality required to use Gremlin:
+To get a full understanding of this section, it would be good to start by reading the <<transactions,Transactions>>
+section of this documentation, which discusses transactions in the general context of TinkerPop itself. This section
+builds on that content by demonstrating the transactional syntax for Go.
 
-[source,java]
+[source,go]
 ----
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
-import org.apache.tinkerpop.gremlin.process.traversal.IO;
-import static org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource.traversal;
-import static org.apache.tinkerpop.gremlin.process.traversal.Operator.*;
-import static org.apache.tinkerpop.gremlin.process.traversal.Order.*;
-import static org.apache.tinkerpop.gremlin.process.traversal.P.*;
-import static org.apache.tinkerpop.gremlin.process.traversal.Pop.*;
-import static org.apache.tinkerpop.gremlin.process.traversal.SackFunctions.*;
-import static org.apache.tinkerpop.gremlin.process.traversal.Scope.*;
-import static org.apache.tinkerpop.gremlin.process.traversal.TextP.*;
-import static org.apache.tinkerpop.gremlin.structure.Column.*;
-import static org.apache.tinkerpop.gremlin.structure.Direction.*;
-import static org.apache.tinkerpop.gremlin.structure.T.*;
-import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.*;
-----
-
-[[gremlin-java-configuration]]
-=== Configuration
-
-The following table describes the various configuration options for the Gremlin Driver:
-
-[width="100%",cols="3,10,^2",options="header"]
-|=========================================================
-|Key |Description |Default
-|connectionPool.channelizer |The fully qualified classname of the client `Channelizer` that defines how to connect to the server. |`Channelizer.WebSocketChannelizer`
-|connectionPool.enableSsl |Determines if SSL should be enabled or not. If enabled on the server then it must be enabled on the client. |false
-|connectionPool.keepAliveInterval |Length of time in milliseconds to wait on an idle connection before sending a keep-alive request. Set to zero to disable this feature. |180000
-|connectionPool.keyStore |The private key in JKS or PKCS#12 format. |_none_
-|connectionPool.keyStorePassword |The password of the `keyStore` if it is password-protected. |_none_
-|connectionPool.keyStoreType |`JKS` (Java 8 default) or `PKCS12` (Java 9+ default)|_none_
-|connectionPool.maxContentLength |The maximum length in bytes that a message can be sent to the server. This number can be no greater than the setting of the same name in the server configuration. |65536
-|connectionPool.maxInProcessPerConnection |The maximum number of in-flight requests that can occur on a connection. |4
-|connectionPool.maxSimultaneousUsagePerConnection |The maximum number of times that a connection can be borrowed from the pool simultaneously. |16
-|connectionPool.maxSize |The maximum size of a connection pool for a host. |8
-|connectionPool.maxWaitForConnection |The amount of time in milliseconds to wait for a new connection before timing out. |3000
-|connectionPool.maxWaitForClose |The amount of time in milliseconds to wait for pending messages to be returned from the server before closing the connection. |3000
-|connectionPool.minInProcessPerConnection |The minimum number of in-flight requests that can occur on a connection. |1
-|connectionPool.minSimultaneousUsagePerConnection |The maximum number of times that a connection can be borrowed from the pool simultaneously. |8
-|connectionPool.minSize |The minimum size of a connection pool for a host. |2
-|connectionPool.reconnectInterval |The amount of time in milliseconds to wait before trying to reconnect to a dead host. |1000
-|connectionPool.resultIterationBatchSize |The override value for the size of the result batches to be returned from the server. |64
-|connectionPool.sslCipherSuites |The list of JSSE ciphers to support for SSL connections. If specified, only the ciphers that are listed and supported will be enabled. If not specified, the JVM default is used.  |_none_
-|connectionPool.sslEnabledProtocols |The list of SSL protocols to support for SSL connections. If specified, only the protocols that are listed and supported will be enabled. If not specified, the JVM default is used.  |_none_
-|connectionPool.sslSkipCertValidation |Configures the `TrustManager` to trust all certs without any validation. Should not be used in production.|false
-|connectionPool.trustStore |File location for a SSL Certificate Chain to use when SSL is enabled. If this value is not provided and SSL is enabled, the default `TrustManager` will be used. |_none_
-|connectionPool.trustStorePassword |The password of the `trustStore` if it is password-protected |_none_
-|connectionPool.validationRequest |A script that is used to test server connectivity. A good script to use is one that evaluates quickly and returns no data. The default simply returns an empty string, but if a graph is required by a particular provider, a good traversal might be `g.inject()`. |_''_
-|connectionPool.connectionSetupTimeoutMillis | Duration of time in milliseconds provided for connection setup to complete which includes WebSocket protocol handshake and SSL handshake. |15000
-|hosts |The list of hosts that the driver will connect to. |localhost
-|jaasEntry |Sets the `AuthProperties.Property.JAAS_ENTRY` properties for authentication to Gremlin Server. |_none_
-|nioPoolSize |Size of the pool for handling request/response operations. |available processors
-|password |The password to submit on requests that require authentication. |_none_
-|path |The URL path to the Gremlin Server. |_/gremlin_
-|port |The port of the Gremlin Server to connect to. The same port will be applied for all hosts. |8192
-|protocol |Sets the `AuthProperties.Property.PROTOCOL` properties for authentication to Gremlin Server. |_none_
-|serializer.className |The fully qualified class name of the `MessageSerializer` that will be used to communicate with the server. Note that the serializer configured on the client should be supported by the server configuration. |_none_
-|serializer.config |A `Map` of configuration settings for the serializer. |_none_
-|username |The username to submit on requests that require authentication. |_none_
-|workerPoolSize |Size of the pool for handling background work. |available processors * 2
-|enableUserAgentOnConnect |Enables sending a user agent to the server during connection requests. More details can be found in provider docs link:https://tinkerpop.apache.org/docs/x.y.z/dev/provider/#_graph_driver_provider_requirements[here].|true
-|=========================================================
-
-Please see the link:https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/driver/Cluster.Builder.html[Cluster.Builder javadoc] to get more information on these settings.
-
-[[gremlin-java-transactions]]
-=== Transactions
+remote, err := NewDriverRemoteConnection("ws://localhost:8182/gremlin")
+g := gremlingo.Traversal_().WithRemote(remote)
 
-Transactions with Java are best described in <<transactions,The Traversal - Transactions>> section of this
-documentation as Java covers both embedded and remote use cases.
+// Create a Transaction.
+tx := g.Tx()
 
-[[gremlin-java-serialization]]
-=== Serialization
+// Spawn a new GraphTraversalSource, binding all traversals established from it to tx.
+gtx, _ := tx.Begin()
 
-Remote systems like Gremlin Server and Remote Gremlin Providers respond to requests made in a particular serialization
-format and respond by serializing results to some format to be interpreted by the client. For JVM-based languages,
-there are three options for serialization: Gryo, GraphSON and GraphBinary. It is important that the client and server
-have the same serializers configured in the same way or else one or the other will experience serialization exceptions
-and fail to always communicate. Discrepancy in serializer registration between client and server can happen fairly
-easily as different graph systems may automatically include serializers on the server-side, thus leaving the client
-to be configured manually. As an example:
+// Execute a traversal within the transaction.
+promise := g.AddV("person").Property("name", "Lyndon").Iterate()
+err := <-promise
 
-[source,java]
-----
-IoRegistry registry = ...; // an IoRegistry instance exposed by a specific graph provider
-TypeSerializerRegistry typeSerializerRegistry = TypeSerializerRegistry.build().addRegistry(registry).create();
-MessageSerializer serializer = new GraphBinaryMessageSerializerV1(typeSerializerRegistry);
-Cluster cluster = Cluster.build().
-                          serializer(serializer).
-                          create();
-Client client = cluster.connect();
-GraphTraversalSource g = traversal().withRemote(DriverRemoteConnection.using(client, "g"));
+if err != nil {
+  // Rollback the transaction if an error occurs.
+  tx.rollback()
+} else {
+  // Commit the transaction. The transaction can no longer be used and cannot be re-used.
+  // A new transaction can be spawned through g.Tx().
+  tx.Commit()
+}
 ----
 
-The `IoRegistry` tells the serializer what classes from the graph provider to auto-register during serialization.
-Gremlin Server roughly uses this same approach when it configures its serializers, so using this same model will
-ensure compatibility when making requests. Obviously, it is possible to switch to GraphSON or Gryo by using
-the appropriate `MessageSerializer` (e.g. `GraphSONMessageSerializerV3d0` or `GryoMessageSerializerV3d0` respectively)
-in the same way and building that into the `Cluster` object.
-
-NOTE: Gryo is no longer the preferred binary serialization format for Gremlin Server - please prefer GraphBinary.
-
-[[gremlin-java-lambda]]
+[[gremlin-go-lambda]]
 === The Lambda Solution
 
 Supporting link:https://en.wikipedia.org/wiki/Anonymous_function[anonymous functions] across languages is difficult as
-most languages do not support lambda introspection and thus, code analysis. In Gremlin-Java and with
-<<connecting-embedded,embedded>> usage, lambdas can be leveraged directly:
+most languages do not support lambda introspection and thus, code analysis. In Gremlin-Go, a Gremlin lambda should
+be represented as a zero-arg callable that returns a string representation of the lambda expected for use in the
+traversal. The lambda should be written as a `Gremlin-Groovy` string. When the lambda is represented in `Bytecode` its
+language is encoded such that the remote connection host can infer which translator and ultimate execution engine to
+use.
 
-[source,java]
+[source,go]
 ----
-g.V().out("knows").map(t -> t.get().value("name") + " is the friend name") <1>
-g.V().out("knows").sideEffect(System.out::println) <2>
-g.V().as("a").out("knows").as("b").select("b").by((Function<Vertex, Integer>) v -> v.<String>value("name").length()) <3>
+r, err := g.V().Out().Map(&gremlingo.Lambda{Script: "it.get().value('name').length()", Language: ""}).Sum().ToList()
 ----
 
-<1> A Java `Function` is used to map a `Traverser<S>` to an object `E`.
-<2> Gremlin steps that take consumer arguments can be passed Java method references.
-<3> Gremlin-Java may sometimes require explicit lambda typing when types can not be automatically inferred.
-
-When sending traversals remotely to <<connecting-gremlin-server,Gremlin Server>> or
-<<connecting-rgp,Remote Gremlin Providers>>, the static methods of `Lambda` should be used and should denote a
-particular JSR-223 `ScriptEngine` that is available on the remote end (typically, this is Groovy). `Lambda` creates a
-string-based lambda that is  then converted into a lambda/closure/anonymous-function/etc. by the respective lambda
-language's JSR-223 `ScriptEngine` implementation.
-
-[source,java]
-----
-g.V().out("knows").map(Lambda.function("it.get().value('name') + ' is the friend name'"))
-g.V().out("knows").sideEffect(Lambda.consumer("println it"))
-g.V().as("a").out("knows").as("b").select("b").by(Lambda.<Vertex,Integer>function("it.value('name').length()"))
-----
+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
+`Script: "it.get().value('name')", Language: "gremlin-groovy"`, prefer `Script: "x -> x.get().value('name')", Language: "gremlin-groovy"`.
 
 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 Gremlin
-Server 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 request, it is possible to simply
-execute. To express bindings in Java, use `Bindings`.
+`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.
 
-[source,java]
+[source,go]
 ----
-b = Bindings.instance()
-g.V(b.of('id',1)).out('created').values('name').map{t -> "name: " + t.get() }
-g.V(b.of('id',4)).out('created').values('name').map{t -> "name: " + t.get() }
-g.V(b.of('id',4)).out('created').values('name').getBytecode()
-g.V(b.of('id',4)).out('created').values('name').getBytecode().getBindings()
-cluster.close()
+r, err := g.V((&gremlingo.Bindings{}).Of("x", 1)).Out("created").Map(&gremlingo.Lambda{Script: "it.get().value('name').length()", Language: ""}).Sum().ToList()
+// 3
+r, err := g.V((&gremlingo.Bindings{}).Of("x", 4)).Out("created").Map(&gremlingo.Lambda{Script: "it.get().value('name').length()", Language: ""}).Sum().ToList()
+// 9
 ----
 
-Both traversals are abstractly defined as `g.V(id).out('created').values('name').map{t -> "name: " + t.get() }` and
-thus, the first submission can be cached for faster evaluation on the next submission.
-
-WARNING: It is generally advised to avoid lambda usage. Please consider <<a-note-on-lambdas,A Note On Lambdas>> for
-more information.
+WARNING: As explained throughout the documentation, when possible <<a-note-on-lambdas,avoid>> lambdas.
 
-[[gremlin-java-scripts]]
+[[gremlin-go-scripts]]
 === Submitting Scripts
 
-image:gremlin-java.png[width=175,float=left] TinkerPop comes equipped with a reference client for Java-based
-applications.  It is referred to as `gremlin-driver`, which enables applications to send requests to Gremlin Server
-and get back results.
-
-Gremlin scripts are sent to the server from a `Client` instance.  A `Client` is created as follows:
+The `Client` class implementation/interface is based on the Java Driver, with some restrictions. Most notably,
+Gremlin-go does not yet implement the `Cluster` class. Instead, `Client` is instantiated directly.
+Usage is as follows:
 
-[source,java]
+[source,go]
 ----
-Cluster cluster = Cluster.open();  <1>
-Client client = cluster.connect(); <2>
+import "github.com/apache/tinkerpop/gremlin-go/v3/driver" <1>
+client, err := gremlingo.NewClient("ws://localhost:8182/gremlin") <2>
 ----
 
-<1> Opens a reference to `localhost` - note that there are many configuration options available in defining a `Cluster` object.
-<2> Creates a `Client` given the configuration options of the `Cluster`.
+<1> Import the Gremlin-Go 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.
 
-Once a `Client` instance is ready, it is possible to issue some Gremlin Groovy scripts:
+Once a `Client` instance is ready, it is possible to issue some Gremlin:
 
-[source,java]
+[source,go]
 ----
-ResultSet results = client.submit("[1,2,3,4]");  <1>
-results.stream().map(i -> i.get(Integer.class) * 2);       <2>
-
-CompletableFuture<List<Result>> results = client.submit("[1,2,3,4]").all();  <3>
-
-CompletableFuture<ResultSet> future = client.submitAsync("[1,2,3,4]"); <4>
-
-Map<String,Object> params = new HashMap<>();
-params.put("x",4);
-client.submit("[1,2,3,x]", params); <5>
+resultSet, err := client.Submit("g.V().count()") <1>
+result, err := resultSet.All() <2>
+fmt.Println(result[0].GetString()) <3>
 ----
 
-<1> Submits 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.
-In this case, they are streamed from the server as they arrive.
-<3> Submit a script, get a `ResultSet`, then return a `CompletableFuture` that will be called when all results have been returned.
-<4> Submit a script asynchronously without waiting for the request to be written to the server.
-<5> Parameterized request are considered the most efficient way to send Gremlin to the server as they can be cached,
-which will boost performance and reduce resources required on the server.
+<1> Submit a script that simply returns a Count of vertexes.
+<2> Get results from resultSet. Block until the the script is evaluated and results are sent back by the server.
+<3> Use the result.
 
 ==== Per Request Settings
 
-There are a number of overloads to `Client.submit()` that accept a `RequestOptions` object. The `RequestOptions`
-provide a way to include options that are specific to the request made with the call to `submit()`. A good use-case for
-this feature is to set a per-request override to the `evaluationTimeout` so that it only applies to the current
-request.
+The `client.Submit()` functions accept a `bindings` which expects a map. The `bindings` provide a way to include options
+that are specific to the request made with the call to `Submit()`. A good use-case for this feature is to set a per-request
+override to the `evaluationTimeout` so that it only applies to the current request.
 
-[source,java]
+[source,go]
 ----
-Cluster cluster = Cluster.open();
-Client client = cluster.connect();
-RequestOptions options = RequestOptions.build().timeout(500).create();
-List<Result> result = client.submit("g.V().repeat(both()).times(100)", options).all().get();
+resultSet, err := client.Submit("g.V().repeat(both()).times(100)", map[string]interface{}{"evaluationTimeout": 5000})
 ----
 
-The preferred method for setting a per-request timeout for scripts is demonstrated above, but those familiar with
-bytecode may try `g.with(EVALUATION_TIMEOUT, 500)` within a script. Gremlin Server will respect timeouts set this way
-in scripts as well. With scripts of course, it is possible to send multiple traversals at once in the same script.
-In such events, the timeout for the request is interpreted as a sum of all timeouts identified in the script.
+The following options are allowed on a per-request basis in this fashion: `batchSize`, `requestId`, `userAgent` and
+`evaluationTimeout`.
 
-[source,java]
+IMPORTANT: The preferred method for setting a per-request timeout for scripts is demonstrated above, but those familiar
+with bytecode may try `g.with("evaluationTimeout", 500)` within a script. Scripts with multiple traversals and multiple
+timeouts will be interpreted as a sum of all timeouts identified in the script for that request.
+
+[source,go]
 ----
-RequestOptions options = RequestOptions.build().timeout(500).create();
-List<Result> result = client.submit("g.with(EVALUATION_TIMEOUT, 500).addV().iterate();" +
-                                    "g.addV().iterate();" + 
-                                    "g.with(EVALUATION_TIMEOUT, 500).addV();", options).all().get();
+resultSet, err := client.Submit("g.with('evaluationTimeout', 500).addV().iterate();"+
+  "g.addV().iterate();"+
+  "g.with('evaluationTimeout', 500).addV();", map[string]interface{}{"evaluationTimeout": 500})
+results, err := resultSet.All()
 ----
 
-In the above example, `RequestOptions` defines a timeout of 500 milliseconds, but the script has three traversals with
+In the above example, defines a timeout of 500 milliseconds, but the script has three traversals with
 two internal settings for the timeout using `with()`. The request timeout used by the server will therefore be 1000
 milliseconds (overriding the 500 which itself was an override for whatever configuration was on the server).
 
-==== Aliases
+[[gremlin-go-dsl]]
+=== Domain Specific Languages
 
-Scripts submitted to Gremlin Server automatically have the globally configured `Graph` and `TraversalSource` instances
-made available to them.  Therefore, if Gremlin Server configures two `TraversalSource` instances called "g1" and "g2"
-a script can simply reference them directly as:
+Writing a Gremlin <<dsl,Domain Specific Language>> (DSL) in Go requires embedding of several structs and interfaces:
 
-[source,java]
-----
-client.submit("g1.V()")
-client.submit("g2.V()")
-----
+* `GraphTraversal` - which exposes the various steps used in traversal writing
+* `GraphTraversalSource` - which spawns `GraphTraversal` instances
+* `AnonymousTraversal` - which spawns anonymous traversals from steps
 
-While this is an acceptable way to submit scripts, it has the downside of forcing the client to encode the server-side
-variable name directly into the script being sent.  If the server configuration ever changed such that "g1" became
-"g100", the client-side code might have to see a significant amount of change.  Decoupling the script code from the
-server configuration can be managed by the `alias` method on `Client` as follows:
+The Social DSL based on the link:https://tinkerpop.apache.org/docs/x.y.z/images/tinkerpop-modern.png["modern" toy graph]
+might look like this:
 
-[source,java]
-----
-Client g1Client = client.alias("g1")
-Client g2Client = client.alias("g2")
-g1Client.submit("g.V()")
-g2Client.submit("g.V()")
+[source,go]
 ----
+// Optional syntactic sugar.
+var __ = gremlingo.T__
+var P = gremlingo.P
+var gt = gremlingo.P.Gt
+// Optional alias for import convenience.
+type GraphTraversal = gremlingo.GraphTraversal
+type GraphTraversalSource = gremlingo.GraphTraversalSource
+type AnonymousTraversal = gremlingo.AnonymousTraversal
 
-The above code demonstrates how the `alias` method can be used such that the script need only contain a reference
-to "g" and "g1" and "g2" are automatically rebound into "g" on the server-side.
-
-[[gremlin-java-dsl]]
-=== Domain Specific Languages
+// Embed Graph traversal inside custom traversal struct to add custom traversal functions.
+// In go, capitalizing the first letter exports (makes public) the struct/method to outside of package, for this example
+// we have defined everything package private. In actual usage, please see fit to your application.
+type socialTraversal struct {
+	*GraphTraversal
+}
 
-Creating a <<dsl,Domain Specific Language>> (DSL) in Java requires the `@GremlinDsl` Java annotation in `gremlin-core`.
-This annotation should be applied to a "DSL interface" that extends `GraphTraversal.Admin`:
+func (s *socialTraversal) knows(personName string) *socialTraversal {
+	return &socialTraversal{s.Out("knows").HasLabel("person").Has("name", personName)}
+}
 
-[source,java]
-----
-@GremlinDsl
-public interface SocialTraversalDsl<S, E> extends GraphTraversal.Admin<S, E> {
+func (s *socialTraversal) youngestFriendsAge() *socialTraversal {
+	return &socialTraversal{s.Out("knows").HasLabel("person").Values("age").Min()}
 }
-----
 
-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.
+func (s *socialTraversal) createdAtLeast(number int) *socialTraversal {
+	return &socialTraversal{s.OutE("created").Count().Is(gt(number))}
+}
 
-In this interface, define the methods that the DSL will be composed of:
+// Add custom social traversal source to spaw custom traversals.
+type socialTraversalSource struct {
+	*GraphTraversalSource
+}
 
-[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);
-    }
+// Define the source step function by adding steps to the bytecode.
+func (sts *socialTraversalSource) persons(personNames ...interface{}) *socialTraversal {
+	t := sts.GetGraphTraversal()
+	t.Bytecode.AddStep("V")
+	t.Bytecode.AddStep("hasLabel", "person")
+	if personNames != nil {
+		t.Bytecode.AddStep("has", "name", P.Within(personNames...))
+	}
+	return &socialTraversal{t}
+}
 
-    public default <E2 extends Number> GraphTraversal<S, E2> youngestFriendsAge() {
-        return out("knows").hasLabel("person").values("age").min();
-    }
 
-    public default GraphTraversal<S, Long> createdAtLeast(int number) {
-        return outE("created").count().is(P.gte(number));
-    }
+// Create the social anonymous traversal interface to embed and extend the anonymous traversal functions.
+type iSocialAnonymousTraversal interface {
+	AnonymousTraversal
+	knows(personName string) *GraphTraversal
+	youngestFriendsAge() *GraphTraversal
+	createdAtLeast(number int) *GraphTraversal
 }
-----
 
-IMPORTANT: Follow the TinkerPop convention of using `<S,E>` in naming generics as those conventions are taken into
-account when generating the anonymous traversal class. The processor attempts to infer the appropriate type parameters
-when generating the anonymous traversal class. If it cannot do it correctly, it is possible to avoid the inference by
-using the `GremlinDsl.AnonymousMethod` annotation on the DSL method. It allows explicit specification of the types to
-use.
+// Add the struct to implement the iSocialAnonymousTraversal interface.
+type socialAnonymousTraversal struct {
+	AnonymousTraversal
+	socialTraversal func() *socialTraversal
+}
 
-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:
+// Add the variable s__ to call anonymous traversal step functions in place of __.
+var s__ iSocialAnonymousTraversal = &socialAnonymousTraversal{
+	__,
+	func() *socialTraversal {
+		return &socialTraversal{gremlingo.NewGraphTraversal(nil, gremlingo.NewBytecode(nil), nil)}
+	},
+}
 
-[source,java]
-----
-org.apache.tinkerpop.gremlin.process.traversal.dsl.GremlinDslProcessor
-----
+// Extended anonymous traversal functions need to return GraphTraversal for serialization purposes
+func (sat *socialAnonymousTraversal) knows(personName string) *GraphTraversal {
+	return sat.socialTraversal().knows(personName).GraphTraversal
+}
 
-The annotation processor will generate several classes for the DSL:
+func (sat *socialAnonymousTraversal) youngestFriendsAge() *GraphTraversal {
+	return sat.socialTraversal().youngestFriendsAge().GraphTraversal
+}
 
-* `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.
-* `__` - Spawns anonymous `DefaultSocialTraversal` instances.
+func (sat *socialAnonymousTraversal) createdAtLeast(number int) *GraphTraversal {
+	return sat.socialTraversal().createdAtLeast(number).GraphTraversal
+}
+----
 
-Using the DSL then just involves telling the `Graph` to use it:
+Using the DSL requires a social traversal source to be created from the default traversal source:
 
-[source,java]
-----
-SocialTraversalSource social = traversal(SocialTraversalSource.class).withEmbedded(graph);
-social.V().has("name","marko").knows("josh");
+[source,go]
 ----
+// Creating the driver remote connection as regular.
+driverRemoteConnection, _ := gremlingo.NewDriverRemoteConnection("ws://localhost:8182/gremlin",
+	func(settings *gremlingo.DriverRemoteConnectionSettings) {
+		settings.TraversalSource = "gmodern"
+	})
+defer driverRemoteConnection.Close()
 
-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:
+// Create social traversal source from graph traversal source.
+social := &socialTraversalSource{gremlingo.Traversal_().WithRemote(driverRemoteConnection)}
 
-[source,java]
-----
-public class SocialTraversalSourceDsl extends GraphTraversalSource {
+// We can now use the social traversal source as well as traversal steps
+resBool, _ := social.persons("marko", "stephen").knows("josh").HasNext()
+fmt.Println(resBool)
 
-    public SocialTraversalSourceDsl(Graph graph, TraversalStrategies traversalStrategies) {
-        super(graph, traversalStrategies);
-    }
+// Using the createdAtLeast step.
+resCreated, _ := social.persons().createdAtLeast(1).Next()
+fmt.Println(resCreated.GetString())
 
-    public SocialTraversalSourceDsl(Graph graph) {
-        super(graph);
-    }
+// Using the social anonymous traversal.
+resAnon, _ := social.persons().Filter(s__.createdAtLeast(1)).Count().Next()
+fmt.Println(resAnon.GetString())
 
-    public SocialTraversalSourceDsl(RemoteConnection connection) {
-        super(connection);
-    }
+// Note that error handling has been omitted with _ from the above examples.
+----
 
-    public GraphTraversal<Vertex, Vertex> persons(String... names) {
-        GraphTraversalSource clone = this.clone();
+[[gremlin-go-differences]]
+=== Differences
 
-        // 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));
+In situations where Go reserved words and global functions overlap with standard Gremlin steps and tokens, those
+bits of conflicting Gremlin get an underscore appended as a suffix. In addition, all function names start with a
+capital letter in order to be public:
 
-        traversal = traversal.hasLabel("person");
-        if (names.length > 0) traversal = traversal.has("name", P.within(names));
+*Steps* - <<and-step,And()>>, <<as-step,As()>>, <<filter-step,Filter()>>, <<from-step,From()>>, <<id-step,Id()>>,
+<<is-step,Is()>>, <<in-step,In()>>, <<max-step,Max()>>, <<min-step,Min()>>, <<not-step,Not()>>, <<or-step,Or()>>,
+<<range-step,Range()>>, <<sum-step,Sum()>>, <<with-step,With()>>
 
-        return traversal;
-    }
-}
-----
+*Tokens* - <<a-note-on-scopes,Scope.Global>>, <<a-note-on-scopes,Scope.Local>>
 
-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`:
+[[gremlin-go-aliases]]
+=== Aliases
+To make the code more readable and close to the Gremlin query language), you can use aliases. These aliases can be named with capital letters to be consistent with non-aliased steps but will result in exported variables which could be problematic if not being used in a top-level program (i.e. not a redistributable package).
+[source,go]
+----
+	var __ = gremlingo.T__
+	var gt = gremlingo.P.Gt
+	var order = gremlingo.Order
 
-[source,java]
+	results, err := g.V().HasLabel("person").Has("age", __.Is(gt(30))).Order().By("age", order.Desc).ToList()
 ----
-@GremlinDsl(traversalSource = "com.company.SocialTraversalSourceDsl")
-public interface SocialTraversalDsl<S, E> extends GraphTraversal.Admin<S, E> {
-    ...
-}
+
+==== List of useful aliases
+[source,go]
 ----
+	// common
+	var __ = gremlingo.T__
+	var TextP = gremlingo.TextP
 
-It is then possible to use the `persons()` method to start traversals:
+	// predicates
+	var between = gremlingo.P.Between
+	var eq = gremlingo.P.Eq
+	var gt = gremlingo.P.Gt
+	var gte = gremlingo.P.Gte
+	var inside = gremlingo.P.Inside
+	var lt = gremlingo.P.Lt
+	var lte = gremlingo.P.Lte
+	var neq = gremlingo.P.Neq
+	var not = gremlingo.P.Not
+	var outside = gremlingo.P.Outside
+	var test = gremlingo.P.Test
+	var within = gremlingo.P.Within
+	var without = gremlingo.P.Without
+	var and = gremlingo.P.And
+	var or = gremlingo.P.Or
 
-[source,java]
-----
-SocialTraversalSource social = traversal(SocialTraversalSource.class).withEmbedded(graph);
-social.persons("marko").knows("josh");
+	// sorting
+	var order = gremlingo.Order
 ----
 
-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-go-limitations]]
+=== Limitations
 
-[[gremlin-java-troubleshooting]]
-=== Troubleshooting
+* There is no default `set` type in Go. Any set type code from server will be deserialized into slices with the list
+type implementation. To input a set into Gremlin-Go, a custom struct which implements the `gremlingo.Set` interface
+will be serialized as a set. `gremlingo.NewSimpleSet` is a basic implementation of a set that is provided by Gremlin-Go
+that can be used to fulfill the `gremlingo.Set` interface if desired.
 
-*Max frame length of 65536 has been exceeded*
+[[gremlin-go-examples]]
+=== Application Examples
 
-This error occurs when the driver attempts to process a request/response that exceeds the configured maximum size.
-The most direct way to fix this problem is to increase the `maxContentLength` setting in the driver. Ideally, the
-`maxContentLength` set for the driver should match the setting defined on the server.
+The TinkerPop source code contains a simple Go script that shows a basic example of how gremlin-go works. It
+can be found in GitHub link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-go/example/example.go[here]
+and is designed to work best with a running <<gremlin-server,Gremlin Server>> configured with the default
+`conf/gremlin-server.yaml` file as included with the standard release packaging.
 
-*TimeoutException*
+[source,shell]
+----
+go run example.go
+----
 
-A `TimeoutException` is thrown by the driver when the time limit assigned by the `maxWaitForConnection` is exceeded
-when trying to borrow a connection from the connection pool for a particular host. There are generally two scenarios
-where this occurs:
+[[gremlin-groovy]]
+== Gremlin-Groovy
 
-1. The server has actually reached its maximum capacity or the driver has just learned that the server is unreachable.
-2. The client is throttling requests when the pool is exhausted.
+image:gremlin-groovy-drawing.png[width=130,float=right] Apache TinkerPop's Gremlin-Groovy implements Gremlin within the
+link:http://groovy.apache.org[Apache Groovy] language. As a JVM-based language variant, Gremlin-Groovy is backed by
+<<gremlin-java,Gremlin-Java>> constructs. Moreover, given its scripting nature, Gremlin-Groovy serves as the language of
+<<gremlin-console,Gremlin Console>> and <<gremlin-server,Gremlin Server>>.
 
-The latter of the two can be addressed from the driver side in the following ways:
+[source,groovy]
+----
+compile group: 'org.apache.tinkerpop', name: 'gremlin-core', version: 'x.y.z'
+compile group: 'org.apache.tinkerpop', name: 'gremlin-driver', version: 'x.y.z'
+----
 
-* Increase the `maxWaitForConnection` allowing the client to wait a bit longer for a connection to become available.
-* Increase the number of requests allowed per connection by increasing the `maxSimultaneousUsagePerConnection` and
-`maxInProcessPerConnection` settings.
-* Increase the number of connections available in the connection pool by increasing the `maxConnectionPoolSize`.
+[[gremlin-groovy-differences]]
+=== Differences
 
-The exception and logs (assuming they are enabled) should contain information about the state of the connection pool
-along with its connections which can help shed more light on which of these scenarios caused the problem. Some examples
-of these messages and their meaning are shown below:
+In Groovy, `as`, `in`, and `not` are reserved words. Gremlin-Groovy does not allow these steps to be called
+statically from the anonymous traversal `+__+` and therefore, must always be prefixed with `+__.+` For instance:
+`+g.V().as('a').in().as('b').where(__.not(__.as('a').out().as('b')))+`
 
-_The server is unavailable_
+Since Groovy has access to the full JVM as Java does, it is possible to construct `Date`-like objects directly, but
+the Gremlin language does offer a `datetime()` function that is exposed in the Gremlin Console and as a function for
+Gremlin scripts sent to Gremlin Server. The function accepts the following forms of dates and times using a default
+time zone offset of UTC(+00:00):
 
-[source,text]
+* `2018-03-22`
+* `2018-03-22T00:35:44`
+* `2018-03-22T00:35:44Z`
+* `2018-03-22T00:35:44.741`
+* `2018-03-22T00:35:44.741Z`
+* `2018-03-22T00:35:44.741+1600`
+
+anchor:connecting-via-remotegraph[]
+anchor:connecting-via-java[]
+[[gremlin-java]]
+== Gremlin-Java
+
+image:gremlin-java-drawing.png[width=130,float=right] Apache TinkerPop's Gremlin-Java implements Gremlin within the
+Java language and can be used by any Java Virtual Machine. Gremlin-Java is considered the canonical, reference
+implementation of Gremlin and serves as the foundation by which all other Gremlin language variants should emulate.
+As the Gremlin Traversal Machine that processes Gremlin queries is also written in Java, it can be used in all three
+connection methods described in the <<connecting-gremlin,Connecting Gremlin>> Section.
+
+[source,xml]
 ----
-Timed-out (500 MILLISECONDS) waiting for connection on Host{address=localhost/127.0.0.1:45940, hostUri=ws://localhost:45940/gremlin}. Potential Cause: Connection refused: no further information
-> ConnectionPool (Host{address=localhost/127.0.0.1:45940, hostUri=ws://localhost:45940/gremlin})- no connections in pool
+<dependency>
+   <groupId>org.apache.tinkerpop</groupId>
+   <artifactId>gremlin-core</artifactId>
+   <version>x.y.z</version>
+</dependency>
+
+<!-- when using Gremlin Server or Remote Gremlin Provider a driver is required -->
+<dependency>
+   <groupId>org.apache.tinkerpop</groupId>
+   <artifactId>gremlin-driver</artifactId>
+   <version>x.y.z</version>
+</dependency>
+
+<!--
+alternatively the driver is packaged as an uberjar with shaded non-optional dependencies including gremlin-core and
+tinkergraph-gremlin which are not shaded.
+-->
+<dependency>
+   <groupId>org.apache.tinkerpop</groupId>
+   <artifactId>gremlin-driver</artifactId>
+   <version>x.y.z</version>
+   <classifier>shaded</classifier>
+   <!-- The shaded JAR uses the original POM, therefore conflicts may still need resolution -->
+   <exclusions>
+      <exclusion>
+         <groupId>io.netty</groupId>
+         <artifactId>*</artifactId>
+      </exclusion>
+   </exclusions>
+</dependency>
 ----
 
-_Client is likely issuing more requests than the pool size can handle_
+[[gremlin-java-connecting]]
+=== Connecting
 
-[source,text]
+The pattern for connecting is described in <<connecting-gremlin,Connecting Gremlin>> and it basically distills down
+to creating a `GraphTraversalSource`. For <<connecting-embedded,embedded>> mode, this involves first creating a
+`Graph` and then spawning the `GraphTraversalSource`:
+
+[source,java]
 ----
-Timed-out (150 MILLISECONDS) waiting for connection on Host{address=localhost/127.0.0.1:45940, hostUri=ws://localhost:45940/gremlin}. Potential Cause: Number of active requests exceeds pool size. Consider increasing the value for maxConnectionPoolSize.
-ConnectionPool (Host{address=localhost/127.0.0.1:45940, hostUri=ws://localhost:45940/gremlin})
-Connection Pool Status (size=1 max=1 min=1 toCreate=0 bin=0)
-> Connection{channel=5a859d62 isDead=false borrowed=1 pending=1 markedReplaced=false closing=false created=2022-12-19T21:08:21.569613100Z thread=gremlin-driver-conn-scheduler-1}
--- bin --
+Graph graph = ...;
+GraphTraversalSource g = traversal().withEmbedded(graph);
 ----
 
-_Network traffic is slow and the websocket handshake does not complete in time_
+Using "g" it is then possible to start writing Gremlin. The "g" allows for the setting of many configuration options
+which affect traversal execution. The <<traversal, Traversal>> Section describes some of these options and some are
+only suitable with <<connecting-embedded,embedded>> style usage. For remote options however there are some added
+configurations to consider and this section looks to address those.
+
+When connecting to <<connecting-gremlin-server,Gremlin Server>> or <<connecting-rgp,Remote Gremlin Providers>>  it
+is possible to configure the `DriverRemoteConnection` manually as shown in earlier examples where the host and port
+are provided as follows:
+
+[source,java]
+----
+GraphTraversalSource g = traversal().withRemote(DriverRemoteConnection.using("localhost",8182,"g"));
+----
+
+It is also possible to create it from a configuration. The most basic way to do so involves the following line of code:
+
+[source,java]
+----
+GraphTraversalSource g = traversal().withRemote('conf/remote-graph.properties');
+----
+
+The `remote-graph.properties` file simply provides connection information to the `GraphTraversalSource` which is used
+to configure a `RemoteConnection`. That file looks like this:
 
 [source,text]
 ----
-Timed-out (250 MILLISECONDS) waiting for connection on Host{address=localhost/127.0.0.1:45940, hostUri=ws://localhost:45940/gremlin}. Potential Cause: WebSocket handshake not completed in stipulated time=[100]ms
-ConnectionPool (Host{address=localhost/127.0.0.1:45940, hostUri=ws://localhost:45940/gremlin})
-Connection Pool Status (size=1 max=5 min=1 toCreate=0 bin=0)
-> Connection{channel=205fc8d2 isDead=false borrowed=1 pending=1 markedReplaced=false closing=false created=2022-12-19T21:10:04.692921600Z thread=gremlin-driver-conn-scheduler-1}
--- bin --
+gremlin.remote.remoteConnectionClass=org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteConnection
+gremlin.remote.driver.clusterFile=conf/remote-objects.yaml
+gremlin.remote.driver.sourceName=g
 ----
 
-anchor:java-application-examples[]
-anchor:gremlin-archetypes[]
-[[gremlin-java-examples]]
-=== Application Examples
+The `RemoteConnection` is an interface that provides the transport mechanism for "g" and makes it possible to for
+that mechanism to be altered (typically by graph providers who have their own protocols). TinkerPop provides one such
+implementation called the `DriverRemoteConnection` which enables transport over Gremlin Server protocols using the
+TinkerPop driver. The driver is configured by the specified `gremlin.remote.driver.clusterFile` and the local "g" is
+bound to the `GraphTraversalSource` on the remote end with `gremlin.remote.driver.sourceName` which in this case is
+also "g".
 
-The available link:https://maven.apache.org/guides/introduction/introduction-to-archetypes.html[Maven archetypes] are
-as follows:
+There are other ways to configure the traversal using `withRemote()` as it has other overloads. It can take an
+Apache Commons `Configuration` object which would have keys similar to those shown in the properties file and it
+can also take a `RemoteConnection` instance directly. The latter is interesting in that it means it is possible to
+programmatically construct all aspects of the `RemoteConnection`. For TinkerPop usage, that might mean directly
+constructing the `DriverRemoteConnection` and the driver instance that supplies the transport mechanism. For example,
+the command shown above could be re-written using programmatic construction as follows:
 
-* `gremlin-archetype-dsl` - An example project that demonstrates how to build Domain Specific Languages with Gremlin
-in Java.
-* `gremlin-archetype-server` - An example project that demonstrates the basic structure of a
-<<gremlin-server,Gremlin Server>> project, how to connect with the Gremlin Driver, and how to embed Gremlin Server in
-a testing framework.
-* `gremlin-archetype-tinkergraph` - A basic example of how to structure a TinkerPop project with Maven.
+[source,java]
+----
+Cluster cluster = Cluster.open();
+GraphTraversalSource g = traversal().withRemote(DriverRemoteConnection.using(cluster, "g"));
+----
 
-Use Maven to generate these example projects with a command like:
+Please consider the following example:
 
-[source,shell]
-$ mvn archetype:generate -DarchetypeGroupId=org.apache.tinkerpop -DarchetypeArtifactId=gremlin-archetype-server \
-      -DarchetypeVersion=x.y.z -DgroupId=com.my -DartifactId=app -Dversion=0.1 -DinteractiveMode=false
+[gremlin-groovy]
+----
+g = traversal().withRemote('conf/remote-graph.properties')
+g.V().elementMap()
+g.close()
+----
 
-This command will generate a new Maven project in a directory called "app" with a `pom.xml` specifying a `groupId` of
-`com.my`. Please see the `README.asciidoc` in the root of each generated project for information on how to build and
-execute it.
+[source,java]
+----
+GraphTraversalSource g = traversal().withRemote("conf/remote-graph.properties");
+List<Map> list = g.V().elementMap();
+g.close();
+----
 
-[[gremlin-javascript]]
-== Gremlin-JavaScript
+Note the call to `close()` above. The call to `withRemote()` internally instantiates a connection via the driver that
+can only be released by "closing" the `GraphTraversalSource`. It is important to take that step to release network
+resources associated with `g`.
 
-image:gremlin-js.png[width=130,float=right] Apache TinkerPop's Gremlin-JavaScript implements Gremlin within the
-JavaScript language. It targets Node.js runtime and can be used on different operating systems on any Node.js 6 or
-above. Since the JavaScript naming conventions are very similar to that of Java, it should be very easy to switch
-between Gremlin-Java and Gremlin-JavaScript.
+If working with multiple remote `TraversalSource` instances it is more efficient to construct `Cluster` and `Client`
+objects and then re-use them.
 
-[source,bash]
-npm install gremlin
+[gremlin-groovy]
+----
+cluster = Cluster.open('conf/remote-objects.yaml')
+client = cluster.connect()
+g = traversal().withRemote(DriverRemoteConnection.using(client, "g"))
+g.V().elementMap()
+g.close()
+client.close()
+cluster.close()
+----
 
-[[gremlin-javascript-connecting]]
-=== Connecting
+If the `Client` instance is supplied externally, as is shown above, then it is not closed implicitly by the close of
+"g".  Closing "g" will have no effect on "client" or "cluster". When supplying them externally, the `Client` and
+`Cluster` objects must also be closed explicitly. It's worth noting that the close of a `Cluster` will close all
+`Client` instances spawned by the `Cluster`.
 
-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.
+Some connection options can also be set on individual requests made through the Java driver using `with()` step
+on the `TraversalSource`. For instance to set request timeout to 500 milliseconds:
 
-[source,javascript]
+[source,java]
 ----
-const g = traversal().withRemote(new DriverRemoteConnection('ws://localhost:8182/gremlin'));
+GraphTraversalSource g = traversal().withRemote(conf);
+List<Vertex> vertices = g.with(Tokens.ARGS_EVAL_TIMEOUT, 500L).V().out("knows").toList()
 ----
 
-Gremlin-JavaScript supports plain text SASL authentication, you can set it on the connection options.
+The following options are allowed on a per-request basis in this fashion: `batchSize`, `requestId`, `userAgent` and
+`evaluationTimeout` (formerly `scriptEvaluationTimeout` which is also supported but now deprecated). Use of `Tokens`
+to reference these options is preferred.
 
-[source,javascript]
+anchor:java-imports[]
+[[gremlin-java-imports]]
+=== Common Imports
+
+There are a number of classes, functions and tokens that are typically used with Gremlin. The following imports
+provide most of the common functionality required to use Gremlin:
+
+[source,java]
 ----
-const authenticator = new gremlin.driver.auth.PlainTextSaslAuthenticator('myuser', 'mypassword');
-const g = traversal().withRemote(new DriverRemoteConnection('ws://localhost:8182/gremlin', { authenticator });
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.IO;
+import static org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource.traversal;
+import static org.apache.tinkerpop.gremlin.process.traversal.Operator.*;
+import static org.apache.tinkerpop.gremlin.process.traversal.Order.*;
+import static org.apache.tinkerpop.gremlin.process.traversal.P.*;
+import static org.apache.tinkerpop.gremlin.process.traversal.Pop.*;
+import static org.apache.tinkerpop.gremlin.process.traversal.SackFunctions.*;
+import static org.apache.tinkerpop.gremlin.process.traversal.Scope.*;
+import static org.apache.tinkerpop.gremlin.process.traversal.TextP.*;
+import static org.apache.tinkerpop.gremlin.structure.Column.*;
+import static org.apache.tinkerpop.gremlin.structure.Direction.*;
+import static org.apache.tinkerpop.gremlin.structure.T.*;
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.*;
 ----
 
-Given that I/O operations in Node.js are asynchronous by default, <<terminal-steps,Terminal Steps>> return a `Promise`:
+[[gremlin-java-configuration]]
+=== Configuration
 
-* `Traversal.toList()`: Returns a `Promise` with an `Array` as result value.
-* `Traversal.next()`: Returns a `Promise` with a `{ value, done }` tuple as result value, according to the
-link:https://github.com/tc39/proposal-async-iteration[async iterator proposal].
-* `Traversal.iterate()`: Returns a `Promise` without a value.
+The following table describes the various configuration options for the Gremlin Driver:
 
-For example:
+[width="100%",cols="3,10,^2",options="header"]
+|=========================================================
+|Key |Description |Default
+|connectionPool.channelizer |The fully qualified classname of the client `Channelizer` that defines how to connect to the server. |`Channelizer.WebSocketChannelizer`
+|connectionPool.enableSsl |Determines if SSL should be enabled or not. If enabled on the server then it must be enabled on the client. |false
+|connectionPool.keepAliveInterval |Length of time in milliseconds to wait on an idle connection before sending a keep-alive request. Set to zero to disable this feature. |180000
+|connectionPool.keyStore |The private key in JKS or PKCS#12 format. |_none_
+|connectionPool.keyStorePassword |The password of the `keyStore` if it is password-protected. |_none_
+|connectionPool.keyStoreType |`JKS` (Java 8 default) or `PKCS12` (Java 9+ default)|_none_
+|connectionPool.maxContentLength |The maximum length in bytes that a message can be sent to the server. This number can be no greater than the setting of the same name in the server configuration. |65536
+|connectionPool.maxInProcessPerConnection |The maximum number of in-flight requests that can occur on a connection. |4
+|connectionPool.maxSimultaneousUsagePerConnection |The maximum number of times that a connection can be borrowed from the pool simultaneously. |16
+|connectionPool.maxSize |The maximum size of a connection pool for a host. |8
+|connectionPool.maxWaitForConnection |The amount of time in milliseconds to wait for a new connection before timing out. |3000
+|connectionPool.maxWaitForClose |The amount of time in milliseconds to wait for pending messages to be returned from the server before closing the connection. |3000
+|connectionPool.minInProcessPerConnection |The minimum number of in-flight requests that can occur on a connection. |1
+|connectionPool.minSimultaneousUsagePerConnection |The maximum number of times that a connection can be borrowed from the pool simultaneously. |8
+|connectionPool.minSize |The minimum size of a connection pool for a host. |2
+|connectionPool.reconnectInterval |The amount of time in milliseconds to wait before trying to reconnect to a dead host. |1000
+|connectionPool.resultIterationBatchSize |The override value for the size of the result batches to be returned from the server. |64
+|connectionPool.sslCipherSuites |The list of JSSE ciphers to support for SSL connections. If specified, only the ciphers that are listed and supported will be enabled. If not specified, the JVM default is used.  |_none_
+|connectionPool.sslEnabledProtocols |The list of SSL protocols to support for SSL connections. If specified, only the protocols that are listed and supported will be enabled. If not specified, the JVM default is used.  |_none_
+|connectionPool.sslSkipCertValidation |Configures the `TrustManager` to trust all certs without any validation. Should not be used in production.|false
+|connectionPool.trustStore |File location for a SSL Certificate Chain to use when SSL is enabled. If this value is not provided and SSL is enabled, the default `TrustManager` will be used. |_none_
+|connectionPool.trustStorePassword |The password of the `trustStore` if it is password-protected |_none_
+|connectionPool.validationRequest |A script that is used to test server connectivity. A good script to use is one that evaluates quickly and returns no data. The default simply returns an empty string, but if a graph is required by a particular provider, a good traversal might be `g.inject()`. |_''_
+|connectionPool.connectionSetupTimeoutMillis | Duration of time in milliseconds provided for connection setup to complete which includes WebSocket protocol handshake and SSL handshake. |15000
+|hosts |The list of hosts that the driver will connect to. |localhost
+|jaasEntry |Sets the `AuthProperties.Property.JAAS_ENTRY` properties for authentication to Gremlin Server. |_none_
+|nioPoolSize |Size of the pool for handling request/response operations. |available processors
+|password |The password to submit on requests that require authentication. |_none_
+|path |The URL path to the Gremlin Server. |_/gremlin_
+|port |The port of the Gremlin Server to connect to. The same port will be applied for all hosts. |8192
+|protocol |Sets the `AuthProperties.Property.PROTOCOL` properties for authentication to Gremlin Server. |_none_
+|serializer.className |The fully qualified class name of the `MessageSerializer` that will be used to communicate with the server. Note that the serializer configured on the client should be supported by the server configuration. |_none_
+|serializer.config |A `Map` of configuration settings for the serializer. |_none_
+|username |The username to submit on requests that require authentication. |_none_
+|workerPoolSize |Size of the pool for handling background work. |available processors * 2
+|enableUserAgentOnConnect |Enables sending a user agent to the server during connection requests. More details can be found in provider docs link:https://tinkerpop.apache.org/docs/x.y.z/dev/provider/#_graph_driver_provider_requirements[here].|true
+|=========================================================
 
-[source,javascript]
+Please see the link:https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/driver/Cluster.Builder.html[Cluster.Builder javadoc] to get more information on these settings.
+
+[[gremlin-java-transactions]]
+=== Transactions
+
+Transactions with Java are best described in <<transactions,The Traversal - Transactions>> section of this
+documentation as Java covers both embedded and remote use cases.
+
+[[gremlin-java-serialization]]
+=== Serialization
+
+Remote systems like Gremlin Server and Remote Gremlin Providers respond to requests made in a particular serialization
+format and respond by serializing results to some format to be interpreted by the client. For JVM-based languages,
+there are three options for serialization: Gryo, GraphSON and GraphBinary. It is important that the client and server
+have the same serializers configured in the same way or else one or the other will experience serialization exceptions
+and fail to always communicate. Discrepancy in serializer registration between client and server can happen fairly
+easily as different graph systems may automatically include serializers on the server-side, thus leaving the client
+to be configured manually. As an example:
+
+[source,java]
 ----
-g.V().hasLabel('person').values('name').toList()
-  .then(names => console.log(names));
+IoRegistry registry = ...; // an IoRegistry instance exposed by a specific graph provider
+TypeSerializerRegistry typeSerializerRegistry = TypeSerializerRegistry.build().addRegistry(registry).create();
+MessageSerializer serializer = new GraphBinaryMessageSerializerV1(typeSerializerRegistry);
+Cluster cluster = Cluster.build().
+                          serializer(serializer).
+                          create();
+Client client = cluster.connect();
+GraphTraversalSource g = traversal().withRemote(DriverRemoteConnection.using(client, "g"));
 ----
 
-When using `async` functions it is possible to `await` the promises:
+The `IoRegistry` tells the serializer what classes from the graph provider to auto-register during serialization.
+Gremlin Server roughly uses this same approach when it configures its serializers, so using this same model will
+ensure compatibility when making requests. Obviously, it is possible to switch to GraphSON or Gryo by using
+the appropriate `MessageSerializer` (e.g. `GraphSONMessageSerializerV3d0` or `GryoMessageSerializerV3d0` respectively)
+in the same way and building that into the `Cluster` object.
+
+NOTE: Gryo is no longer the preferred binary serialization format for Gremlin Server - please prefer GraphBinary.
+
+[[gremlin-java-lambda]]
+=== The Lambda Solution
+
+Supporting link:https://en.wikipedia.org/wiki/Anonymous_function[anonymous functions] across languages is difficult as
+most languages do not support lambda introspection and thus, code analysis. In Gremlin-Java and with
+<<connecting-embedded,embedded>> usage, lambdas can be leveraged directly:
+
+[source,java]
+----
+g.V().out("knows").map(t -> t.get().value("name") + " is the friend name") <1>
+g.V().out("knows").sideEffect(System.out::println) <2>
+g.V().as("a").out("knows").as("b").select("b").by((Function<Vertex, Integer>) v -> v.<String>value("name").length()) <3>
+----
+
+<1> A Java `Function` is used to map a `Traverser<S>` to an object `E`.
+<2> Gremlin steps that take consumer arguments can be passed Java method references.
+<3> Gremlin-Java may sometimes require explicit lambda typing when types can not be automatically inferred.
+
+When sending traversals remotely to <<connecting-gremlin-server,Gremlin Server>> or
+<<connecting-rgp,Remote Gremlin Providers>>, the static methods of `Lambda` should be used and should denote a
+particular JSR-223 `ScriptEngine` that is available on the remote end (typically, this is Groovy). `Lambda` creates a
+string-based lambda that is  then converted into a lambda/closure/anonymous-function/etc. by the respective lambda
+language's JSR-223 `ScriptEngine` implementation.
+
+[source,java]
+----
+g.V().out("knows").map(Lambda.function("it.get().value('name') + ' is the friend name'"))
+g.V().out("knows").sideEffect(Lambda.consumer("println it"))
+g.V().as("a").out("knows").as("b").select("b").by(Lambda.<Vertex,Integer>function("it.value('name').length()"))
+----
+
+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 Gremlin
+Server 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 request, it is possible to simply
+execute. To express bindings in Java, use `Bindings`.
+
+[source,java]
+----
+b = Bindings.instance()
+g.V(b.of('id',1)).out('created').values('name').map{t -> "name: " + t.get() }
+g.V(b.of('id',4)).out('created').values('name').map{t -> "name: " + t.get() }
+g.V(b.of('id',4)).out('created').values('name').getBytecode()
+g.V(b.of('id',4)).out('created').values('name').getBytecode().getBindings()
+cluster.close()
+----
+
+Both traversals are abstractly defined as `g.V(id).out('created').values('name').map{t -> "name: " + t.get() }` and
+thus, the first submission can be cached for faster evaluation on the next submission.
+
+WARNING: It is generally advised to avoid lambda usage. Please consider <<a-note-on-lambdas,A Note On Lambdas>> for
+more information.
+
+[[gremlin-java-scripts]]
+=== Submitting Scripts
+
+image:gremlin-java.png[width=175,float=left] TinkerPop comes equipped with a reference client for Java-based
+applications.  It is referred to as `gremlin-driver`, which enables applications to send requests to Gremlin Server
+and get back results.
+
+Gremlin scripts are sent to the server from a `Client` instance.  A `Client` is created as follows:
 
-[source,javascript]
+[source,java]
 ----
-const names = await g.V().hasLabel('person').values('name').toList();
-console.log(names);
+Cluster cluster = Cluster.open();  <1>
+Client client = cluster.connect(); <2>
 ----
 
-Some connection options can also be set on individual requests made through the using `with()` step on the
-`TraversalSource`. For instance to set request timeout to 500 milliseconds:
+<1> Opens a reference to `localhost` - note that there are many configuration options available in defining a `Cluster` object.
+<2> Creates a `Client` given the configuration options of the `Cluster`.
 
-[source,javascript]
+Once a `Client` instance is ready, it is possible to issue some Gremlin Groovy scripts:
+
+[source,java]
 ----
-const vertices = await g.with_('evaluationTimeout', 500).V().out('knows').toList()
+ResultSet results = client.submit("[1,2,3,4]");  <1>
+results.stream().map(i -> i.get(Integer.class) * 2);       <2>
+
+CompletableFuture<List<Result>> results = client.submit("[1,2,3,4]").all();  <3>
+
+CompletableFuture<ResultSet> future = client.submitAsync("[1,2,3,4]"); <4>
+
+Map<String,Object> params = new HashMap<>();
+params.put("x",4);
+client.submit("[1,2,3,x]", params); <5>
 ----
 
-The following options are allowed on a per-request basis in this fashion: `batchSize`, `requestId`, `userAgent` and
-`evaluationTimeout` (formerly `scriptEvaluationTimeout` which is also supported but now deprecated).
+<1> Submits 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.
+In this case, they are streamed from the server as they arrive.
+<3> Submit a script, get a `ResultSet`, then return a `CompletableFuture` that will be called when all results have been returned.
+<4> Submit a script asynchronously without waiting for the request to be written to the server.
+<5> Parameterized request are considered the most efficient way to send Gremlin to the server as they can be cached,
+which will boost performance and reduce resources required on the server.
 
-[[gremlin-javascript-imports]]
-=== Common Imports
+==== Per Request Settings
 
-There are a number of classes, functions and tokens that are typically used with Gremlin. The following imports
-provide most of the typical functionality required to use Gremlin:
+There are a number of overloads to `Client.submit()` that accept a `RequestOptions` object. The `RequestOptions`
+provide a way to include options that are specific to the request made with the call to `submit()`. A good use-case for
+this feature is to set a per-request override to the `evaluationTimeout` so that it only applies to the current
+request.
 
-[source,javascript]
+[source,java]
 ----
-const gremlin = require('gremlin');
-const traversal = gremlin.process.AnonymousTraversalSource.traversal;
-const __ = gremlin.process.statics;
-const DriverRemoteConnection = gremlin.driver.DriverRemoteConnection;
-const column = gremlin.process.column
-const direction = gremlin.process.direction
-const p = gremlin.process.P
-const textp = gremlin.process.TextP
-const pick = gremlin.process.pick
-const pop = gremlin.process.pop
-const order = gremlin.process.order
-const scope = gremlin.process.scope
-const t = gremlin.process.t
+Cluster cluster = Cluster.open();
+Client client = cluster.connect();
+RequestOptions options = RequestOptions.build().timeout(500).create();
+List<Result> result = client.submit("g.V().repeat(both()).times(100)", options).all().get();
 ----
 
-By defining these imports it becomes possible to write Gremlin in the more shorthand, canonical style that is
-demonstrated in most examples found here in the documentation:
+The preferred method for setting a per-request timeout for scripts is demonstrated above, but those familiar with
+bytecode may try `g.with(EVALUATION_TIMEOUT, 500)` within a script. Gremlin Server will respect timeouts set this way
+in scripts as well. With scripts of course, it is possible to send multiple traversals at once in the same script.
+In such events, the timeout for the request is interpreted as a sum of all timeouts identified in the script.
 
-[source,javascript]
+[source,java]
 ----
-const { P: { gt } } = gremlin.process;
-const { order: { desc } } = gremlin.process;
-g.V().hasLabel('person').has('age',gt(30)).order().by('age',desc).toList()
+RequestOptions options = RequestOptions.build().timeout(500).create();
+List<Result> result = client.submit("g.with(EVALUATION_TIMEOUT, 500).addV().iterate();" +
+                                    "g.addV().iterate();" + 
+                                    "g.with(EVALUATION_TIMEOUT, 500).addV();", options).all().get();
 ----
 
-[[gremlin-javascript-configuration]]
-=== Configuration
-The following table describes the various configuration options for the Gremlin-Javascript Driver. They
-can be passed in the constructor of a new `Client` or `DriverRemoteConnection` :
-
-[width="100%",cols="3,3,10,^2",options="header"]
-|=========================================================
-|Key |Type |Description |Default
-|url |String |The resource uri. |None
-|options |Object |The connection options. |{}
-|options.ca |Array |Trusted certificates. |undefined
-|options.cert |String/Array/Buffer |The certificate key. |undefined
-|options.mimeType |String |The mime type to use. |'application/vnd.gremlin-v3.0+json'
-|options.pfx |String/Buffer |The private key, certificate, and CA certs. |undefined
-|options.reader |GraphSONReader/GraphBinaryReader |The reader to use. |select reader according to mimeType
-|options.writer |GraphSONWriter |The writer to use. |select writer according to mimeType
-|options.rejectUnauthorized |Boolean |Determines whether to verify or not the server certificate. |undefined
-|options.traversalSource |String |The traversal source. |'g'
-|options.authenticator |Authenticator |The authentication handler to use. |undefined
-|options.processor |String |The name of the opProcessor to use, leave it undefined or set 'session' when session mode. |undefined
-|options.session |String |The sessionId of Client in session mode. undefined means session-less Client. |undefined
-|options.enableUserAgentOnConnect |Boolean |Determines if a user agent will be sent during connection handshake. |true
-|options.headers |Object |An associative array containing the additional header key/values for the initial request. |undefined
-|options.pingEnabled |Boolean |Setup ping interval. |true
-|options.pingInterval |Number |Ping request interval in ms if ping enabled. |60000
-|options.pongTimeout |Number |Timeout of pong response in ms after sending a ping. |30000
-|=========================================================
+In the above example, `RequestOptions` defines a timeout of 500 milliseconds, but the script has three traversals with
+two internal settings for the timeout using `with()`. The request timeout used by the server will therefore be 1000
+milliseconds (overriding the 500 which itself was an override for whatever configuration was on the server).
 
-[[gremlin-javascript-transactions]]
-=== Transactions
+==== Aliases
 
-To get a full understanding of this section, it would be good to start by reading the <<transactions,Transactions>>
-section of this documentation, which discusses transactions in the general context of TinkerPop itself. This section
-builds on that content by demonstrating the transactional syntax for Javascript.
+Scripts submitted to Gremlin Server automatically have the globally configured `Graph` and `TraversalSource` instances
+made available to them.  Therefore, if Gremlin Server configures two `TraversalSource` instances called "g1" and "g2"
+a script can simply reference them directly as:
 
-[source,javascript]
+[source,java]
+----
+client.submit("g1.V()")
+client.submit("g2.V()")
 ----
-const g = traversal().withRemote(new DriverRemoteConnection('ws://localhost:8182/gremlin'));
-const tx = g.tx(); // create a Transaction
 
-// spawn a new GraphTraversalSource binding all traversals established from it to tx
-const gtx = tx.begin();
+While this is an acceptable way to submit scripts, it has the downside of forcing the client to encode the server-side
+variable name directly into the script being sent.  If the server configuration ever changed such that "g1" became
+"g100", the client-side code might have to see a significant amount of change.  Decoupling the script code from the
+server configuration can be managed by the `alias` method on `Client` as follows:
 
-// execute traversals using gtx occur within the scope of the transaction held by tx. the
-// tx is closed after calls to commit or rollback and cannot be re-used. simply spawn a
-// new Transaction from g.tx() to create a new one as needed. the g context remains
-// accessible through all this as a sessionless connection.
-Promise.all([
-  gtx.addV("person").property("name", "jorge").iterate(),
-  gtx.addV("person").property("name", "josh").iterate()
-]).then(() => {
-  return tx.commit();
-}).catch(() => {
-  return tx.rollback();
-});
+[source,java]
+----
+Client g1Client = client.alias("g1")
+Client g2Client = client.alias("g2")
+g1Client.submit("g.V()")
+g2Client.submit("g.V()")
 ----
 
-[[gremlin-javascript-lambda]]
-=== The Lambda Solution
+The above code demonstrates how the `alias` method can be used such that the script need only contain a reference
+to "g" and "g1" and "g2" are automatically rebound into "g" on the server-side.
 
-Supporting link:https://en.wikipedia.org/wiki/Anonymous_function[anonymous functions] across languages is difficult as
-most languages do not support lambda introspection and thus, code analysis. In Gremlin-Javascript, a Gremlin lambda
-should be represented as a zero-arg callable that returns a string representation of the lambda expected for use in the
-traversal. The returned lambda should be written as a Gremlin-Groovy string. When the lambda is represented in
-`Bytecode` its language is encoded such that the remote connection host can infer which translator and ultimate
-execution engine to use.
+[[gremlin-java-dsl]]
+=== Domain Specific Languages
 
-[source,javascript]
+Creating a <<dsl,Domain Specific Language>> (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]
 ----
-g.V().out().
-  map(() => "it.get().value('name').length()").
-  sum().
-  toList().then(total => console.log(total))
+@GremlinDsl
+public interface SocialTraversalDsl<S, E> extends GraphTraversal.Admin<S, E> {
+}
 ----
 
-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
-`() => "it.get().value('name')"`, prefer `() => "x -> x.get().value('name')"`.
-
-WARNING: As explained throughout the documentation, when possible <<a-note-on-lambdas,avoid>> lambdas.
-
-[[gremlin-javascript-scripts]]
-=== Submitting Scripts
+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.
 
-It is possible to submit parametrized Gremlin scripts to the server as strings, using the `Client` class:
+In this interface, define the methods that the DSL will be composed of:
 
-[source,javascript]
+[source,java]
 ----
-const gremlin = require('gremlin');
-const client = new gremlin.driver.Client('ws://localhost:8182/gremlin', { traversalSource: 'g' });
-
-const result1 = await client.submit('g.V(vid)', { vid: 1 });
-const vertex = result1.first();
+@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);
+    }
 
-const result2 = await client.submit('g.V().hasLabel(label).tail(n)', { label: 'person', n: 3 });
+    public default <E2 extends Number> GraphTraversal<S, E2> youngestFriendsAge() {
+        return out("knows").hasLabel("person").values("age").min();
+    }
 
-// ResultSet is an iterable
-for (const vertex of result2) {
-  console.log(vertex.id);
+    public default GraphTraversal<S, Long> createdAtLeast(int number) {
+        return outE("created").count().is(P.gte(number));
+    }
 }
 ----
 
-It is also possible to initialize the `Client` to use <<sessions,sessions>>:
+IMPORTANT: Follow the TinkerPop convention of using `<S,E>` in naming generics as those conventions are taken into
+account when generating the anonymous traversal class. The processor attempts to infer the appropriate type parameters
+when generating the anonymous traversal class. If it cannot do it correctly, it is possible to avoid the inference by
+using the `GremlinDsl.AnonymousMethod` annotation on the DSL method. It allows explicit specification of the types to
+use.
 
-[source,javascript]
+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]
 ----
-const client = new gremlin.driver.Client('ws://localhost:8182/gremlin', { traversalSource: 'g', 'session': 'unique-string-id' });
+org.apache.tinkerpop.gremlin.process.traversal.dsl.GremlinDslProcessor
 ----
 
-With this configuration, the state of variables within scripts are preserved between requests.
+The annotation processor will generate several classes for the DSL:
 
-==== Per Request Settings
+* `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.
+* `__` - Spawns anonymous `DefaultSocialTraversal` instances.
 
-The `client.submit()` functions accept a `requestOptions` which expects a dictionary. The `requestOptions`
-provide a way to include options that are specific to the request made with the call to `submit()`. A good use-case for
-this feature is to set a per-request override to the `evaluationTimeout` so that it only applies to the current
-request.
+Using the DSL then just involves telling the `Graph` to use it:
 
-[source,javascript]
+[source,java]
 ----
-const result = await client.submit("g.V().repeat(both()).times(100)", null, { evaluationTimeout: 5000 })
+SocialTraversalSource social = traversal(SocialTraversalSource.class).withEmbedded(graph);
+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(Graph graph, TraversalStrategies traversalStrategies) {
+        super(graph, traversalStrategies);
+    }
 
-The following options are allowed on a per-request basis in this fashion: `batchSize`, `requestId`, `userAgent` and
-`evaluationTimeout` (formerly `scriptEvaluationTimeout` which is also supported but now deprecated).
+    public SocialTraversalSourceDsl(Graph graph) {
+        super(graph);
+    }
 
-IMPORTANT: The preferred method for setting a per-request timeout for scripts is demonstrated above, but those familiar
-with bytecode may try `g.with(EVALUATION_TIMEOUT, 500)` within a script. Scripts with multiple traversals and multiple
-timeouts will be interpreted as a sum of all timeouts identified in the script for that request.
+    public SocialTraversalSourceDsl(RemoteConnection connection) {
+        super(connection);
+    }
 
+    public GraphTraversal<Vertex, Vertex> persons(String... names) {
+        GraphTraversalSource clone = this.clone();
 
-==== Processing results as they are returned from the Gremlin server
+        // 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));
 
-The Gremlin JavaScript driver maintains a WebSocket connection to the Gremlin server and receives messages according to the `batchSize` parameter on the per request settings or the `resultIterationBatchSize` value configured for the Gremlin server. When submitting scripts the default behavior is to wait for the entire result set to be returned from a query before allowing any processing on the result set.
+        return traversal;
+    }
+}
+----
 
-The following examples assume that you have 100 vertices in your graph.
+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,javascript]
+[source,java]
 ----
-const result = await client.submit("g.V()");
-console.log(result.toArray()); // 100 - all the vertices in your graph
+@GremlinDsl(traversalSource = "com.company.SocialTraversalSourceDsl")
+public interface SocialTraversalDsl<S, E> extends GraphTraversal.Admin<S, E> {
+    ...
+}
 ----
 
-When working with larger result sets it may be beneficial for memory management to process each chunk of data as it is returned from the gremlin server. The Gremlin JavaScript driver can return a readable stream instead of waiting for the entire result set to be loaded.
+It is then possible to use the `persons()` method to start traversals:
 
-[source,javascript]
+[source,java]
+----
+SocialTraversalSource social = traversal(SocialTraversalSource.class).withEmbedded(graph);
+social.persons("marko").knows("josh");
 ----
 
-const readable =  client.stream("g.V()", {}, { batchSize: 25 });
-
-readable.on('data', (data) => {
-  console.log(data.toArray()); // 25 vertices
-})
-
-readable.on('error', (error) => {
-  console.log(error); // errors returned from gremlin server
-})
+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.
 
-readable.on('end', () => {
-  console.log('query complete'); // when the end event is received then all the results have been processed
-})
-----
+[[gremlin-java-troubleshooting]]
+=== Troubleshooting
 
-If you are using NodeJS >= 10.0, you can asynchronously iterate readable streams:
+*Max frame length of 65536 has been exceeded*
 
+This error occurs when the driver attempts to process a request/response that exceeds the configured maximum size.
+The most direct way to fix this problem is to increase the `maxContentLength` setting in the driver. Ideally, the
+`maxContentLength` set for the driver should match the setting defined on the server.
 
-[source,javascript]
-----
+*TimeoutException*
 
-const readable = client.stream("g.V()", {}, { batchSize: 25 });
+A `TimeoutException` is thrown by the driver when the time limit assigned by the `maxWaitForConnection` is exceeded
+when trying to borrow a connection from the connection pool for a particular host. There are generally two scenarios
+where this occurs:
 
-try {
-  for await (const result of readable) {
-    console.log('data', result.toArray()); // 25 vertices
-  }
-} catch (err) {
-  console.log(err);
-}
+1. The server has actually reached its maximum capacity or the driver has just learned that the server is unreachable.
+2. The client is throttling requests when the pool is exhausted.
 
-----
+The latter of the two can be addressed from the driver side in the following ways:
 
+* Increase the `maxWaitForConnection` allowing the client to wait a bit longer for a connection to become available.
+* Increase the number of requests allowed per connection by increasing the `maxSimultaneousUsagePerConnection` and
+`maxInProcessPerConnection` settings.
+* Increase the number of connections available in the connection pool by increasing the `maxConnectionPoolSize`.
 
-[[gremlin-javascript-dsl]]
-=== Domain Specific Languages
+The exception and logs (assuming they are enabled) should contain information about the state of the connection pool
+along with its connections which can help shed more light on which of these scenarios caused the problem. Some examples
+of these messages and their meaning are shown below:
 
-Developing Gremlin DSLs in JavaScript largely requires extension of existing core classes with use of standalone
-functions for anonymous traversal spawning. The pattern is demonstrated in the following example:
+_The server is unavailable_
 
-[source,javascript]
+[source,text]
+----
+Timed-out (500 MILLISECONDS) waiting for connection on Host{address=localhost/127.0.0.1:45940, hostUri=ws://localhost:45940/gremlin}. Potential Cause: Connection refused: no further information
+> ConnectionPool (Host{address=localhost/127.0.0.1:45940, hostUri=ws://localhost:45940/gremlin})- no connections in pool
 ----
-class SocialTraversal extends GraphTraversal {
-  constructor(graph, traversalStrategies, bytecode) {
-    super(graph, traversalStrategies, bytecode);
-  }
-
-  aged(age) {
-    return this.has('person', 'age', age);
-  }
-}
 
-class SocialTraversalSource extends GraphTraversalSource {
-  constructor(graph, traversalStrategies, bytecode) {
-    super(graph, traversalStrategies, bytecode, SocialTraversalSource, SocialTraversal);
-  }
+_Client is likely issuing more requests than the pool size can handle_
 
-  person(name) {
-    return this.V().has('person', 'name', name);
-  }
-}
+[source,text]
+----
+Timed-out (150 MILLISECONDS) waiting for connection on Host{address=localhost/127.0.0.1:45940, hostUri=ws://localhost:45940/gremlin}. Potential Cause: Number of active requests exceeds pool size. Consider increasing the value for maxConnectionPoolSize.
+ConnectionPool (Host{address=localhost/127.0.0.1:45940, hostUri=ws://localhost:45940/gremlin})
+Connection Pool Status (size=1 max=1 min=1 toCreate=0 bin=0)
+> Connection{channel=5a859d62 isDead=false borrowed=1 pending=1 markedReplaced=false closing=false created=2022-12-19T21:08:21.569613100Z thread=gremlin-driver-conn-scheduler-1}
+-- bin --
+----
 
-function anonymous() {
-  return new SocialTraversal(null, null, new Bytecode());
-}
+_Network traffic is slow and the websocket handshake does not complete in time_
 
-function aged(age) {
-  return anonymous().aged(age);
-}
+[source,text]
+----
+Timed-out (250 MILLISECONDS) waiting for connection on Host{address=localhost/127.0.0.1:45940, hostUri=ws://localhost:45940/gremlin}. Potential Cause: WebSocket handshake not completed in stipulated time=[100]ms
+ConnectionPool (Host{address=localhost/127.0.0.1:45940, hostUri=ws://localhost:45940/gremlin})
+Connection Pool Status (size=1 max=5 min=1 toCreate=0 bin=0)
+> Connection{channel=205fc8d2 isDead=false borrowed=1 pending=1 markedReplaced=false closing=false created=2022-12-19T21:10:04.692921600Z thread=gremlin-driver-conn-scheduler-1}
+-- bin --
 ----
 
-`SocialTraversal` extends the core `GraphTraversal` class and has a three argument constructor which is immediately
-proxied to the `GraphTraversal` constructor. New DSL steps are then added to this class using available steps to
-construct the underlying traversal to execute as demonstrated in the `aged()` step.
+anchor:java-application-examples[]
+anchor:gremlin-archetypes[]
+[[gremlin-java-examples]]
+=== Application Examples
 
-The `SocialTraversal` is spawned from a `SocialTraversalSource` which is extended from `GraphTraversalSource`. Steps
-added here are meant to be start steps. In the above case, the `person()` start step find a "person" vertex to begin
-the traversal from.
+The available link:https://maven.apache.org/guides/introduction/introduction-to-archetypes.html[Maven archetypes] are
+as follows:
 
-Typically, steps that are made available on a `GraphTraversal` (i.e. SocialTraversal in this example) should also be
-made available as spawns for anonymous traversals. The recommendation is that these steps be exposed in the module
-as standalone functions. In the example above, the standalone `aged()` step creates an anonymous traversal through
-an `anonymous()` utility function. The method for creating these standalone functions can be handled in other ways if
-desired.
+* `gremlin-archetype-dsl` - An example project that demonstrates how to build Domain Specific Languages with Gremlin
+in Java.
+* `gremlin-archetype-server` - An example project that demonstrates the basic structure of a
+<<gremlin-server,Gremlin Server>> project, how to connect with the Gremlin Driver, and how to embed Gremlin Server in
+a testing framework.
+* `gremlin-archetype-tinkergraph` - A basic example of how to structure a TinkerPop project with Maven.
 
-To use the DSL, simply initialize the `g` as follows:
+Use Maven to generate these example projects with a command like:
 
-[source,javascript]
-----
-const g = traversal(SocialTraversalSource).withRemote(connection);
-g.person('marko').aged(29).values('name').toList().
-  then(names => console.log(names));
-----
+[source,shell]
+$ mvn archetype:generate -DarchetypeGroupId=org.apache.tinkerpop -DarchetypeArtifactId=gremlin-archetype-server \
+      -DarchetypeVersion=x.y.z -DgroupId=com.my -DartifactId=app -Dversion=0.1 -DinteractiveMode=false
 
-[[javascript-differences]]
-[[gremlin-javascript-differences]]
-=== Differences
+This command will generate a new Maven project in a directory called "app" with a `pom.xml` specifying a `groupId` of
+`com.my`. Please see the `README.asciidoc` in the root of each generated project for information on how to build and
+execute it.
 
-In situations where Javascript reserved words and global functions overlap with standard Gremlin steps and tokens, those
-bits of conflicting Gremlin get an underscore appended as a suffix:
+[[gremlin-javascript]]
+== Gremlin-JavaScript
 
-*Steps* - <<from-step,from_()>>, <<in-step,in_()>>, <<with-step,with_()>>
+image:gremlin-js.png[width=130,float=right] Apache TinkerPop's Gremlin-JavaScript implements Gremlin within the
+JavaScript language. It targets Node.js runtime and can be used on different operating systems on any Node.js 6 or
+above. Since the JavaScript naming conventions are very similar to that of Java, it should be very easy to switch
+between Gremlin-Java and Gremlin-JavaScript.
 
-Gremlin allows for `Map` instances to include `null` keys, but `null` keys in Javascript have some interesting behavior
-as in:
+[source,bash]
+npm install gremlin
 
-[source,text]
-----
-> var a = { null: 'something', 'b': 'else' };
-> JSON.stringify(a)
-'{"null":"something","b":"else"}'
-> JSON.parse(JSON.stringify(a))
-{ null: 'something', b: 'else' }
-> a[null]
-'something'
-> a['null']
-'something'
-----
+[[gremlin-javascript-connecting]]
+=== Connecting
 
-This behavior needs to be considered when using Gremlin to return such results. A typical situation where this might
-happen is with `group()` or `groupCount()` as in:
+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,javascript]
 ----
-g.V().groupCount().by('age')
+const g = traversal().withRemote(new DriverRemoteConnection('ws://localhost:8182/gremlin'));
 ----
 
-where "age" is not a valid key for all vertices. In these cases, it will return `null` for that key and group on that.
-It may bet better in Javascript to filter away those vertices to avoid the return of `null` in the returned `Map`:
+Gremlin-JavaScript supports plain text SASL authentication, you can set it on the connection options.
 
 [source,javascript]
 ----
-g.V().has('age').groupCount().by('age')
-g.V().hasLabel('person').groupCount().by('age')
+const authenticator = new gremlin.driver.auth.PlainTextSaslAuthenticator('myuser', 'mypassword');
+const g = traversal().withRemote(new DriverRemoteConnection('ws://localhost:8182/gremlin', { authenticator });
 ----
 
-Either of the above two options accomplishes the desired goal as both prevent `groupCount()` from having to process
-the possibility of `null`.
-
-[[gremlin-javascript-limitations]]
-=== Limitations
-
-* The `subgraph()`-step is not supported by any variant that is not running on the Java Virtual Machine as there is
-no `Graph` instance to deserialize a result into on the client-side. A workaround is to replace the step with
-`aggregate(local)` and then convert those results to something the client can use locally.
-
-anchor:gremlin-DotNet[]
-[[gremlin-dotnet]]
-== Gremlin.Net
+Given that I/O operations in Node.js are asynchronous by default, <<terminal-steps,Terminal Steps>> return a `Promise`:
 
-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 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.
+* `Traversal.toList()`: Returns a `Promise` with an `Array` as result value.
+* `Traversal.next()`: Returns a `Promise` with a `{ value, done }` tuple as result value, according to the
+link:https://github.com/tc39/proposal-async-iteration[async iterator proposal].
+* `Traversal.iterate()`: Returns a `Promise` without a value.
 
-[source,powershell]
-nuget install Gremlin.Net
+For example:
 
-[[gremlin-dotnet-connecting]]
-=== Connecting
+[source,javascript]
+----
+g.V().hasLabel('person').values('name').toList()
+  .then(names => console.log(names));
+----
 
-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.
+When using `async` functions it is possible to `await` the promises:
 
-[source,csharp]
+[source,javascript]
 ----
-include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=connecting]
+const names = await g.V().hasLabel('person').values('name').toList();
+console.log(names);
 ----
 
-Some connection options can also be set on individual requests using the `With()` step on the `TraversalSource`.
-For instance to set request timeout to 500 milliseconds:
+Some connection options can also be set on individual requests made through the using `with()` step on the
+`TraversalSource`. For instance to set request timeout to 500 milliseconds:
 
-[source,csharp]
+[source,javascript]
 ----
-var l = g.With(Tokens.ArgsEvalTimeout, 500).V().Out("knows").Count().ToList();
+const vertices = await g.with_('evaluationTimeout', 500).V().out('knows').toList()
 ----
 
 The following options are allowed on a per-request basis in this fashion: `batchSize`, `requestId`, `userAgent` and
-`evaluationTimeout` (formerly `scriptEvaluationTimeout` which is also supported but now deprecated). These options are
-available as constants on the `Gremlin.Net.Driver.Tokens` class.
+`evaluationTimeout` (formerly `scriptEvaluationTimeout` which is also supported but now deprecated).
 
-[[gremlin-dotnet-imports]]
+[[gremlin-javascript-imports]]
 === Common Imports
 
 There are a number of classes, functions and tokens that are typically used with Gremlin. The following imports
 provide most of the typical functionality required to use Gremlin:
 
-[source,csharp]
+[source,javascript]
 ----
-include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=commonImports]
+const gremlin = require('gremlin');
+const traversal = gremlin.process.AnonymousTraversalSource.traversal;
+const __ = gremlin.process.statics;
+const DriverRemoteConnection = gremlin.driver.DriverRemoteConnection;
+const column = gremlin.process.column
+const direction = gremlin.process.direction
+const p = gremlin.process.P
+const textp = gremlin.process.TextP
+const pick = gremlin.process.pick
+const pop = gremlin.process.pop
+const order = gremlin.process.order
+const scope = gremlin.process.scope
+const t = gremlin.process.t
 ----
 
-[[gremlin-dotnet-configuration]]
-=== Configuration
-
-The connection properties for the Gremlin.Net driver can be passed to the `GremlinServer` instance as keyword arguments:
-
-[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_
-|=========================================================
+By defining these imports it becomes possible to write Gremlin in the more shorthand, canonical style that is
+demonstrated in most examples found here in the documentation:
 
-==== Connection Pool
+[source,javascript]
+----
+const { P: { gt } } = gremlin.process;
+const { order: { desc } } = gremlin.process;
+g.V().hasLabel('person').has('age',gt(30)).order().by('age',desc).toList()
+----
 
-It is also possible to configure the `ConnectionPool` of the Gremlin.Net driver.
-These configuration options can be set as properties
-on the `ConnectionPoolSettings` instance that can be passed to the `GremlinClient`:
+[[gremlin-javascript-configuration]]
+=== Configuration
+The following table describes the various configuration options for the Gremlin-Javascript Driver. They
+can be passed in the constructor of a new `Client` or `DriverRemoteConnection` :
 
-[width="100%",cols="3,10,^2",options="header"]
+[width="100%",cols="3,3,10,^2",options="header"]
 |=========================================================
-|Key |Description |Default
-|PoolSize |The size of the connection pool. |4
-|MaxInProcessPerConnection |The maximum number of in-flight requests that can occur on a connection. |32
-|ReconnectionAttempts |The number of attempts to get an open connection from the pool to submit a request. |4
-|ReconnectionBaseDelay |The base delay used for the exponential backoff for the reconnection attempts. |1 s
-|EnableUserAgentOnConnect |Enables sending a user agent to the server during connection requests.
-More details can be found in provider docs
-link:https://tinkerpop.apache.org/docs/x.y.z/dev/provider/#_graph_driver_provider_requirements[here].|true
+|Key |Type |Description |Default
+|url |String |The resource uri. |None
+|options |Object |The connection options. |{}
+|options.ca |Array |Trusted certificates. |undefined
+|options.cert |String/Array/Buffer |The certificate key. |undefined
+|options.mimeType |String |The mime type to use. |'application/vnd.gremlin-v3.0+json'
+|options.pfx |String/Buffer |The private key, certificate, and CA certs. |undefined
+|options.reader |GraphSONReader/GraphBinaryReader |The reader to use. |select reader according to mimeType
+|options.writer |GraphSONWriter |The writer to use. |select writer according to mimeType
+|options.rejectUnauthorized |Boolean |Determines whether to verify or not the server certificate. |undefined
+|options.traversalSource |String |The traversal source. |'g'
+|options.authenticator |Authenticator |The authentication handler to use. |undefined
+|options.processor |String |The name of the opProcessor to use, leave it undefined or set 'session' when session mode. |undefined
+|options.session |String |The sessionId of Client in session mode. undefined means session-less Client. |undefined
+|options.enableUserAgentOnConnect |Boolean |Determines if a user agent will be sent during connection handshake. |true
+|options.headers |Object |An associative array containing the additional header key/values for the initial request. |undefined
+|options.pingEnabled |Boolean |Setup ping interval. |true
+|options.pingInterval |Number |Ping request interval in ms if ping enabled. |60000
+|options.pongTimeout |Number |Timeout of pong response in ms after sending a ping. |30000
 |=========================================================
 
-A `NoConnectionAvailableException` is thrown if all connections have reached the `MaxInProcessPerConnection` limit
-when a new request comes in.
-A `ServerUnavailableException` is thrown if no connection is available to the server to submit a request after
-`ReconnectionAttempts` retries.
+[[gremlin-javascript-transactions]]
+=== Transactions
 
-==== WebSocket Configuration
+To get a full understanding of this section, it would be good to start by reading the <<transactions,Transactions>>
+section of this documentation, which discusses transactions in the general context of TinkerPop itself. This section
+builds on that content by demonstrating the transactional syntax for Javascript.
 
-The WebSocket connections can also be configured, directly as parameters of the `GremlinClient` constructor. It takes
-an optional delegate `webSocketConfiguration` that will be invoked for each connection. This makes it possible to
-configure more advanced options like the `KeepAliveInterval` or client certificates.
+[source,javascript]
+----
+const g = traversal().withRemote(new DriverRemoteConnection('ws://localhost:8182/gremlin'));
+const tx = g.tx(); // create a Transaction
 
-Starting with .NET 6, it is also possible to use compression for WebSockets. This is enabled by default starting with
-TinkerPop 3.5.3 (again, only on .NET 6 or higher). Note that compression might make an application susceptible to
-attacks like CRIME/BREACH. Compression should therefore be turned off if the application sends sensitive data to the
-server as well as data that could potentially be controlled by an untrusted user. Compression can be disabled via the
-`disableCompression` parameter.
+// spawn a new GraphTraversalSource binding all traversals established from it to tx
+const gtx = tx.begin();
 
-[[gremlin-dotnet-logging]]
-=== Logging
+// execute traversals using gtx occur within the scope of the transaction held by tx. the
+// tx is closed after calls to commit or rollback and cannot be re-used. simply spawn a
+// new Transaction from g.tx() to create a new one as needed. the g context remains
+// accessible through all this as a sessionless connection.
+Promise.all([
+  gtx.addV("person").property("name", "jorge").iterate(),
+  gtx.addV("person").property("name", "josh").iterate()
+]).then(() => {
+  return tx.commit();
+}).catch(() => {
+  return tx.rollback();
+});
+----
 
-It is possible to enable logging for the Gremlin.Net driver by providing an `ILoggerFactory` (from the
-`Microsoft.Extensions.Logging.Abstractions` package) to the `GremlinClient` constructor:
+[[gremlin-javascript-lambda]]
+=== The Lambda Solution
 
-[source,csharp]
+Supporting link:https://en.wikipedia.org/wiki/Anonymous_function[anonymous functions] across languages is difficult as
+most languages do not support lambda introspection and thus, code analysis. In Gremlin-Javascript, a Gremlin lambda
+should be represented as a zero-arg callable that returns a string representation of the lambda expected for use in the
+traversal. The returned lambda should be written as a Gremlin-Groovy string. When the lambda is represented in
+`Bytecode` its language is encoded such that the remote connection host can infer which translator and ultimate
+execution engine to use.
+
+[source,javascript]
 ----
-include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=logging]
+g.V().out().
+  map(() => "it.get().value('name').length()").
+  sum().
+  toList().then(total => console.log(total))
 ----
 
-[[gremlin-dotnet-serialization]]
-=== Serialization
+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
+`() => "it.get().value('name')"`, prefer `() => "x -> x.get().value('name')"`.
 
-The Gremlin.Net driver uses by default GraphSON 3.0 but it is also possible to use another serialization format by passing a message serializer when creating the `GremlinClient`.
+WARNING: As explained throughout the documentation, when possible <<a-note-on-lambdas,avoid>> lambdas.
 
-GraphBinary can be configured like this:
+[[gremlin-javascript-scripts]]
+=== Submitting Scripts
 
-[source,csharp]
-----
-include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=serializationBinary]
+It is possible to submit parametrized Gremlin scripts to the server as strings, using the `Client` class:
+
+[source,javascript]
 ----
+const gremlin = require('gremlin');
+const client = new gremlin.driver.Client('ws://localhost:8182/gremlin', { traversalSource: 'g' });
 
-and GraphSON 2.0 like this:
+const result1 = await client.submit('g.V(vid)', { vid: 1 });
+const vertex = result1.first();
 
-[source,csharp]
-----
-include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=serializationGraphSon]
-----
+const result2 = await client.submit('g.V().hasLabel(label).tail(n)', { label: 'person', n: 3 });
 
-[[gremlin-dotnet-strategies]]
-=== Traversal Strategies
+// ResultSet is an iterable
+for (const vertex of result2) {
+  console.log(vertex.id);
+}
+----
 
-In order to add and remove traversal strategies from a traversal source, Gremlin.Net has an `AbstractTraversalStrategy`
-class along with a collection of subclasses that mirror the standard Gremlin-Java strategies.
+It is also possible to initialize the `Client` to use <<sessions,sessions>>:
 
-[source,csharp]
+[source,javascript]
 ----
-include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=traversalStrategies]
+const client = new gremlin.driver.Client('ws://localhost:8182/gremlin', { traversalSource: 'g', 'session': 'unique-string-id' });
 ----
 
-NOTE: Many of the TraversalStrategy classes in Gremlin.Net are proxies to the respective strategy on Apache TinkerPop’s
-JVM-based Gremlin traversal machine. As such, their `Apply(ITraversal)` method does nothing. However, the strategy is
-encoded in the Gremlin.Net bytecode and transmitted to the Gremlin traversal machine for re-construction machine-side.
+With this configuration, the state of variables within scripts are preserved between requests.
 
-[[gremlin-dotnet-transactions]]
-=== Transactions
+==== Per Request Settings
 
-To get a full understanding of this section, it would be good to start by reading the <<transactions,Transactions>>
-section of this documentation, which discusses transactions in the general context of TinkerPop itself. This section
-builds on that content by demonstrating the transactional syntax for C#.
+The `client.submit()` functions accept a `requestOptions` which expects a dictionary. The `requestOptions`
+provide a way to include options that are specific to the request made with the call to `submit()`. A good use-case for
+this feature is to set a per-request override to the `evaluationTimeout` so that it only applies to the current
+request.
 
-[source,csharp]
+[source,javascript]
 ----
-include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=transactions]
+const result = await client.submit("g.V().repeat(both()).times(100)", null, { evaluationTimeout: 5000 })
 ----
 
-[[gremlin-dotnet-lambda]]
-=== The Lambda Solution
-
-Supporting link:https://en.wikipedia.org/wiki/Anonymous_function[anonymous functions] across languages is difficult as
-most languages do not support lambda introspection and thus, code analysis. While Gremlin.Net doesn't support C# lambdas, it
-is still able to represent lambdas in other languages. When the lambda is represented in `Bytecode` its language is encoded
-such that the remote connection host can infer which translator and ultimate execution engine to use.
+The following options are allowed on a per-request basis in this fashion: `batchSize`, `requestId`, `userAgent` and
+`evaluationTimeout` (formerly `scriptEvaluationTimeout` which is also supported but now deprecated).
 
-[source,csharp]
-----
-g.V().Out().Map<int>(Lambda.Groovy("it.get().value('name').length()")).Sum<int>().ToList();      <1>
-g.V().Out().Map<int>(Lambda.Python("lambda x: len(x.get().value('name'))")).Sum<int>().ToList(); <2>
-----
+IMPORTANT: The preferred method for setting a per-request timeout for scripts is demonstrated above, but those familiar
+with bytecode may try `g.with(EVALUATION_TIMEOUT, 500)` within a script. Scripts with multiple traversals and multiple
+timeouts will be interpreted as a sum of all timeouts identified in the script for that request.
 
-<1> `Lambda.Groovy()` can be used to create a Groovy lambda. 
-<2> `Lambda.Python()` can be used to create a Python lambda.
 
-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.
+==== Processing results as they are returned from the Gremlin server
 
-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'))`.
 
-[[gremlin-dotnet-scripts]]
-=== Submitting Scripts
+The Gremlin JavaScript driver maintains a WebSocket connection to the Gremlin server and receives messages according to the `batchSize` parameter on the per request settings or the `resultIterationBatchSize` value configured for the Gremlin server. When submitting scripts the default behavior is to wait for the entire result set to be returned from a query before allowing any processing on the result set.
 
-Gremlin scripts are sent to the server from a `IGremlinClient` instance.  A `IGremlinClient` is created as follows:
+The following examples assume that you have 100 vertices in your graph.
 
-[source,csharp]
+[source,javascript]
 ----
-include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=submittingScripts]
+const result = await client.submit("g.V()");
+console.log(result.toArray()); // 100 - all the vertices in your graph
+----
+
+When working with larger result sets it may be beneficial for memory management to process each chunk of data as it is returned from the gremlin server. The Gremlin JavaScript driver can return a readable stream instead of waiting for the entire result set to be loaded.
+
+[source,javascript]
 ----
 
-If the remote system has authentication and SSL enabled, then the `GremlinServer` object can be configured as follows:
+const readable =  client.stream("g.V()", {}, { batchSize: 25 });
+
+readable.on('data', (data) => {
+  console.log(data.toArray()); // 25 vertices
+})
 
-[source,csharp]
-----
-include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=submittingScriptsWithAuthentication]
+readable.on('error', (error) => {
+  console.log(error); // errors returned from gremlin server
+})
+
+readable.on('end', () => {
+  console.log('query complete'); // when the end event is received then all the results have been processed
+})
 ----
 
-It is also possible to initialize the `Client` to use <<sessions,sessions>>:
+If you are using NodeJS >= 10.0, you can asynchronously iterate readable streams:
 
-[source,csharp]
-----
-var gremlinServer = new GremlinServer("localhost", 8182);
-var client = new GremlinClient(gremlinServer, sessionId: Guid.NewGuid().ToString()))
+
+[source,javascript]
 ----
 
-==== Per Request Settings
+const readable = client.stream("g.V()", {}, { batchSize: 25 });
 
-The `GremlinClient.Submit()` functions accept an option to build a raw `RequestMessage`. A good use-case for this
-feature is to set a per-request override to the `evaluationTimeout` so that it only applies to the current request.
+try {
+  for await (const result of readable) {
+    console.log('data', result.toArray()); // 25 vertices
+  }
+} catch (err) {
+  console.log(err);
+}
 
-[source,csharp]
-----
-include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=submittingScriptsWithTimeout]
 ----
 
-The following options are allowed on a per-request basis in this fashion: `batchSize`, `requestId`, `userAgent` and
-`evaluationTimeout` (formerly `scriptEvaluationTimeout` which is also supported but now deprecated). These options are
-available as constants on the `Gremlin.Net.Driver.Tokens` class.
-
-IMPORTANT: The preferred method for setting a per-request timeout for scripts is demonstrated above, but those familiar
-with bytecode may try `g.with(EVALUATION_TIMEOUT, 500)` within a script. Scripts with multiple traversals and multiple
-timeouts will be interpreted as a sum of all timeouts identified in the script for that request.
 
-anchor:gremlin-net-dsl[]
-[[gremlin-dotnet-dsl]]
+[[gremlin-javascript-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.
+Developing Gremlin DSLs in JavaScript largely requires extension of existing core classes with use of standalone
+functions for anonymous traversal spawning. The pattern is demonstrated in the following example:
 
-[source,csharp]
-----
-include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsDsl.cs[tags=dsl]
+[source,javascript]
 ----
+class SocialTraversal extends GraphTraversal {
+  constructor(graph, traversalStrategies, bytecode) {
+    super(graph, traversalStrategies, bytecode);
+  }
 
-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:
+  aged(age) {
+    return this.has('person', 'age', age);
+  }
+}
 
-[source,csharp]
-----
-include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsDslTests.cs[tags=dslUsing]
-----
+class SocialTraversalSource extends GraphTraversalSource {
+  constructor(graph, traversalStrategies, bytecode) {
+    super(graph, traversalStrategies, bytecode, SocialTraversalSource, SocialTraversal);
+  }
 
-and then it can be called from the application as follows:
+  person(name) {
+    return this.V().has('person', 'name', name);
+  }
+}
 
-[source,csharp]
-----
-include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsDslTests.cs[tags=dslExamples]
+function anonymous() {
+  return new SocialTraversal(null, null, new Bytecode());
+}
+
+function aged(age) {
+  return anonymous().aged(age);
+}
 ----
 
-anchor:gremlin-net-differences[]
-[[gremlin-dotnet-differences]]
-=== Differences
+`SocialTraversal` extends the core `GraphTraversal` class and has a three argument constructor which is immediately
+proxied to the `GraphTraversal` constructor. New DSL steps are then added to this class using available steps to
+construct the underlying traversal to execute as demonstrated in the `aged()` step.
 
-The biggest difference between Gremlin in .NET and the canonical version in Java is the casing of steps. Canonical
-Gremlin utilizes `camelCase` as is typical in Java for function names, but C# utilizes `PascalCase` as it is more
-typical in that language. Therefore, when viewing a typical Gremlin example written in Gremlin Console, the conversion
-to C# usually just requires capitalization of the first letter in the step name, thus the following example in Groovy:
+The `SocialTraversal` is spawned from a `SocialTraversalSource` which is extended from `GraphTraversalSource`. Steps
+added here are meant to be start steps. In the above case, the `person()` start step find a "person" vertex to begin
+the traversal from.
 
-[source,groovy]
-----
-g.V().has('person','name','marko').
-  out('knows').
-  elementMap().toList()
-----
+Typically, steps that are made available on a `GraphTraversal` (i.e. SocialTraversal in this example) should also be
+made available as spawns for anonymous traversals. The recommendation is that these steps be exposed in the module
+as standalone functions. In the example above, the standalone `aged()` step creates an anonymous traversal through
+an `anonymous()` utility function. The method for creating these standalone functions can be handled in other ways if
+desired.
 
-would become the following in C#:
+To use the DSL, simply initialize the `g` as follows:
 
-[source,csharp]
+[source,javascript]
 ----
-g.V().Has("Person","name","marko").
-  Out("knows").
-  ElementMap().ToList();
+const g = traversal(SocialTraversalSource).withRemote(connection);
+g.person('marko').aged(29).values('name').toList().
+  then(names => console.log(names));
 ----
 
-In addition to the uppercase change, also note the conversion of the single quotes to double quotes as is expected for
-declaring string values in C# and the addition of the semi-colon at the end of the line. In short, don't forget to
-apply the common syntax expectations for C# when trying to convert an example of Gremlin from a different language.
+[[javascript-differences]]
+[[gremlin-javascript-differences]]
+=== Differences
 
-Another common conversion issues lies in having to explicitly define generics, which can make canonical Gremlin appear
-much more complex in C# where type erasure is not a feature of the language. For example, the following example in
-Groovy:
+In situations where Javascript reserved words and global functions overlap with standard Gremlin steps and tokens, those
+bits of conflicting Gremlin get an underscore appended as a suffix:
 
-[source,groovy]
-----
-g.V().repeat(__.out()).times(2).values('name')
-----
+*Steps* - <<from-step,from_()>>, <<in-step,in_()>>, <<with-step,with_()>>
 
-must be written as:
+Gremlin allows for `Map` instances to include `null` keys, but `null` keys in Javascript have some interesting behavior
+as in:
 
-[source,csharp]
+[source,text]
 ----
-g.V().Repeat(__.Out()).Times(2).Values<string>("name");
+> var a = { null: 'something', 'b': 'else' };
+> JSON.stringify(a)
+'{"null":"something","b":"else"}'
+> JSON.parse(JSON.stringify(a))
+{ null: 'something', b: 'else' }
+> a[null]
+'something'
+> a['null']
+'something'
 ----
 
-Gremlin allows for `Map` instances to include `null` keys, but `null` keys in C# `Dictionary` instances are not allowed.
-It is therefore necessary to rewrite a traversal such as:
+This behavior needs to be considered when using Gremlin to return such results. A typical situation where this might
+happen is with `group()` or `groupCount()` as in:
 
 [source,javascript]
 ----
 g.V().groupCount().by('age')
 ----
 
-where "age" is not a valid key for all vertices in a way that will remove the need for a `null` to be returned.
+where "age" is not a valid key for all vertices. In these cases, it will return `null` for that key and group on that.
+It may bet better in Javascript to filter away those vertices to avoid the return of `null` in the returned `Map`:
 
 [source,javascript]
 ----
@@ -1459,494 +1586,367 @@ g.V().hasLabel('person').groupCount().by('age')
 Either of the above two options accomplishes the desired goal as both prevent `groupCount()` from having to process
 the possibility of `null`.
 
-anchor:gremlin-net-limitations[]
-[[gremlin-dotnet-limitations]]
+[[gremlin-javascript-limitations]]
 === Limitations
 
 * The `subgraph()`-step is not supported by any variant that is not running on the Java Virtual Machine as there is
 no `Graph` instance to deserialize a result into on the client-side. A workaround is to replace the step with
 `aggregate(local)` and then convert those results to something the client can use locally.
 
-anchor:gremlin-dotnet-template[]
-anchor:dotnet-application-examples[]
-anchor:gremlin-net-examples[]
-[[gremlin-dotnet-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-go]]
-== Gremlin-Go
-
-image:gremlin-go.png[width=130,float=right] Apache TinkerPop's Gremlin-Go implements Gremlin within the link:https://go.dev/[Go] language and can therefore be used on different operating systems. Go's syntax has the similar constructs as Java including
-"dot notation" for function chaining (`a.b.c`) and round bracket function arguments (`a(b,c)`). Something unlike Java is that Gremlin-Go requires a
-`gremlingo` prefix when using the namespace (`a(b())` vs `gremlingo.a(gremlingo.T__.b())`). Anyone familiar with Gremlin-Java will be able to work
-with Gremlin-Go with relative ease. Moreover, there are a few added constructs to Gremlin-Go that make traversals a bit more
-succinct.
+anchor:gremlin-DotNet[]
+[[gremlin-dotnet]]
+== Gremlin.Net
 
-To install the Gremlin-Go as a dependency for your project, run the following in the root directory of your project that contains your `go.mod` file:
+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 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,bash]
-----
-go get github.com/apache/tinkerpop/gremlin-go/v3[optionally append @<version>, such as @v3.5.3]
-----
+[source,powershell]
+nuget install Gremlin.Net
 
-[[gremlin-go-connecting]]
+[[gremlin-dotnet-connecting]]
 === 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 anonymous `Traversal_()`.
-
-[source,go]
-----
-remote, err := gremlingo.NewDriverRemoteConnection("ws://localhost:8182/gremlin")
-g := gremlingo.Traversal_().WithRemote(remote)
-----
-
-If you need to additional parameters to connection setup, you can pass in a configuration function.
-
-[source,go]
-----
-remote, err := gremlingo.NewDriverRemoteConnection("ws://localhost:8182/gremlin",
-  func(settings *DriverRemoteConnectionSettings) {
-    settings.TraversalSource = "gmodern"
-  })
-----
-
-Gremlin-go supports plain text authentication. It can be set in the connection function.
+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,go]
+[source,csharp]
 ----
-remote, err := gremlingo.NewDriverRemoteConnection("ws://localhost:8182/gremlin",
-  func(settings *DriverRemoteConnectionSettings) {
-    settings.TlsConfig = &tls.Config{InsecureSkipVerify: true}
-    settings.AuthInfo = gremlingo.BasicAuthInfo("login", "password")
-  })
+include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=connecting]
 ----
 
-If you authenticate to a remote <<connecting-gremlin-server,Gremlin Server>> or
-<<connecting-rgp,Remote Gremlin Provider>>, this server normally has SSL activated and the websockets url will start
-with 'wss://'.
-
-Some connection options can also be set on individual requests made through the using `With()` step on the
-`TraversalSource`. For instance to set request timeout to 500 milliseconds:
+Some connection options can also be set on individual requests using the `With()` step on the `TraversalSource`.
+For instance to set request timeout to 500 milliseconds:
 
-[source,go]
+[source,csharp]
 ----
-results, err := g.With("evaluationTimeout", 500).V().Out("knows").ToList()
+var l = g.With(Tokens.ArgsEvalTimeout, 500).V().Out("knows").Count().ToList();
 ----
 
 The following options are allowed on a per-request basis in this fashion: `batchSize`, `requestId`, `userAgent` and
-`evaluationTimeout`.
+`evaluationTimeout` (formerly `scriptEvaluationTimeout` which is also supported but now deprecated). These options are
+available as constants on the `Gremlin.Net.Driver.Tokens` class.
 
-anchor:go-imports[]
-[[gremlin-go-imports]]
+[[gremlin-dotnet-imports]]
 === Common Imports
 
-There are a number of classes, functions and tokens that are typically used with Gremlin. The following import
+There are a number of classes, functions and tokens that are typically used with Gremlin. The following imports
 provide most of the typical functionality required to use Gremlin:
 
-[source,go]
+[source,csharp]
 ----
-import (
-	"github.com/apache/tinkerpop/gremlin-go/driver"
-)
+include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=commonImports]
 ----
 
-These can be used analogously to how they are used in Gremlin-Java.
+[[gremlin-dotnet-configuration]]
+=== Configuration
 
-[source,go]
-----
-results, err := g.V().HasLabel("person").Has("age", gremlingo.T__.Is(gremlingo.P.Gt(30))).Order().By("age", gremlingo.Desc).ToList()
-[v[6], v[4]]
-----
+The connection properties for the Gremlin.Net driver can be passed to the `GremlinServer` instance as keyword arguments:
 
-anchor:go-configuration[]
-[[gremlin-go-configuration]]
-=== Configuration
+[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_
+|=========================================================
 
-The following table describes the various configuration options for the Gremlin-go Driver. They
-can be passed to the `NewClient` or `NewDriverRemoteConnection` functions as configuration function arguments:
+==== Connection Pool
+
+It is also possible to configure the `ConnectionPool` of the Gremlin.Net driver.
+These configuration options can be set as properties
+on the `ConnectionPoolSettings` instance that can be passed to the `GremlinClient`:
 
 [width="100%",cols="3,10,^2",options="header"]
 |=========================================================
 |Key |Description |Default
-|TraversalSource |Traversal source. |"g"
-|TransporterType |Transporter type. |Gorilla
-|LogVerbosity |Log verbosity.|gremlingo.INFO
-|Logger |Instance of logger. |log
-|Language |Language used for logging messages. |language.English
-|AuthInfo |Authentification info, can be build with BasicAuthInfo() or HeaderAuthInfo(). |empty
-|TlsConfig |TLS configuration. |empty
-|KeepAliveInterval |Keep connection alive interval. |5 seconds
-|WriteDeadline |Write deadline. |3 seconds
-|ConnectionTimeout | Timeout for establishing connection. |45 seconds
-|NewConnectionThreshold | Minimum amount of concurrent active traversals on a connection to trigger creation of a new connection. |4
-|MaximumConcurrentConnections | Maximum number of concurrent connections. |number of runtime processors
-|EnableCompression |Flag to enable compression. |false
-|ReadBufferSize |Specify I/O buffer sizes in bytes. If a buffer size is zero, then a useful default size is used |0
-|WriteBufferSize |Specify I/O buffer sizes in bytes. If a buffer size is zero, then a useful default size is used |0
-|Session |Session ID. |""
+|PoolSize |The size of the connection pool. |4
+|MaxInProcessPerConnection |The maximum number of in-flight requests that can occur on a connection. |32
+|ReconnectionAttempts |The number of attempts to get an open connection from the pool to submit a request. |4
+|ReconnectionBaseDelay |The base delay used for the exponential backoff for the reconnection attempts. |1 s
 |EnableUserAgentOnConnect |Enables sending a user agent to the server during connection requests.
 More details can be found in provider docs
 link:https://tinkerpop.apache.org/docs/x.y.z/dev/provider/#_graph_driver_provider_requirements[here].|true
 |=========================================================
 
-[[gremlin-go-strategies]]
-=== Traversal Strategies
+A `NoConnectionAvailableException` is thrown if all connections have reached the `MaxInProcessPerConnection` limit
+when a new request comes in.
+A `ServerUnavailableException` is thrown if no connection is available to the server to submit a request after
+`ReconnectionAttempts` retries.
 
-In order to add and remove <<traversalstrategy,traversal strategies>> from a traversal source, Gremlin-Go has a
-`TraversalStrategy` interface along with a collection of functions that mirror the standard Gremlin-Java strategies.
+==== WebSocket Configuration
 
-[source,go]
-----
-promise := g.WithStrategies(gremlingo.ReadOnlyStrategy()).AddV("person").Property("name", "foo").Iterate()
-----
+The WebSocket connections can also be configured, directly as parameters of the `GremlinClient` constructor. It takes
+an optional delegate `webSocketConfiguration` that will be invoked for each connection. This makes it possible to
+configure more advanced options like the `KeepAliveInterval` or client certificates.
 
-NOTE: Many of the `TraversalStrategy` classes in Gremlin-Go are proxies to the respective strategy on
-Apache TinkerPop's JVM-based Gremlin traversal machine. As such, their `apply(Traversal)` method does nothing. However,
-the strategy is encoded in the Gremlin-Go bytecode and transmitted to the Gremlin traversal machine for
-re-construction machine-side.
+Starting with .NET 6, it is also possible to use compression for WebSockets. This is enabled by default starting with
+TinkerPop 3.5.3 (again, only on .NET 6 or higher). Note that compression might make an application susceptible to
+attacks like CRIME/BREACH. Compression should therefore be turned off if the application sends sensitive data to the
+server as well as data that could potentially be controlled by an untrusted user. Compression can be disabled via the
+`disableCompression` parameter.
 
-[[gremlin-go-transactions]]
-=== Transactions
+[[gremlin-dotnet-logging]]
+=== Logging
 
-To get a full understanding of this section, it would be good to start by reading the <<transactions,Transactions>>
-section of this documentation, which discusses transactions in the general context of TinkerPop itself. This section
-builds on that content by demonstrating the transactional syntax for Go.
+It is possible to enable logging for the Gremlin.Net driver by providing an `ILoggerFactory` (from the
+`Microsoft.Extensions.Logging.Abstractions` package) to the `GremlinClient` constructor:
 
-[source,go]
+[source,csharp]
 ----
-remote, err := NewDriverRemoteConnection("ws://localhost:8182/gremlin")
-g := gremlingo.Traversal_().WithRemote(remote)
-
-// Create a Transaction.
-tx := g.Tx()
-
-// Spawn a new GraphTraversalSource, binding all traversals established from it to tx.
-gtx, _ := tx.Begin()
-
-// Execute a traversal within the transaction.
-promise := g.AddV("person").Property("name", "Lyndon").Iterate()
-err := <-promise
-
-if err != nil {
-  // Rollback the transaction if an error occurs.
-  tx.rollback()
-} else {
-  // Commit the transaction. The transaction can no longer be used and cannot be re-used.
-  // A new transaction can be spawned through g.Tx().
-  tx.Commit()
-}
+include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=logging]
 ----
 
-[[gremlin-go-lambda]]
-=== The Lambda Solution
-
-Supporting link:https://en.wikipedia.org/wiki/Anonymous_function[anonymous functions] across languages is difficult as
-most languages do not support lambda introspection and thus, code analysis. In Gremlin-Go, a Gremlin lambda should
-be represented as a zero-arg callable that returns a string representation of the lambda expected for use in the
-traversal. The lambda should be written as a `Gremlin-Groovy` string. When the lambda is represented in `Bytecode` its
-language is encoded such that the remote connection host can infer which translator and ultimate execution engine to
-use.
-
-[source,go]
-----
-r, err := g.V().Out().Map(&gremlingo.Lambda{Script: "it.get().value('name').length()", Language: ""}).Sum().ToList()
-----
+[[gremlin-dotnet-serialization]]
+=== Serialization
 
-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
-`Script: "it.get().value('name')", Language: "gremlin-groovy"`, prefer `Script: "x -> x.get().value('name')", Language: "gremlin-groovy"`.
+The Gremlin.Net driver uses by default GraphSON 3.0 but it is also possible to use another serialization format by passing a message serializer when creating the `GremlinClient`.
 
-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.
+GraphBinary can be configured like this:
 
-[source,go]
+[source,csharp]
 ----
-r, err := g.V((&gremlingo.Bindings{}).Of("x", 1)).Out("created").Map(&gremlingo.Lambda{Script: "it.get().value('name').length()", Language: ""}).Sum().ToList()
-// 3
-r, err := g.V((&gremlingo.Bindings{}).Of("x", 4)).Out("created").Map(&gremlingo.Lambda{Script: "it.get().value('name').length()", Language: ""}).Sum().ToList()
-// 9
+include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=serializationBinary]
 ----
 
-WARNING: As explained throughout the documentation, when possible <<a-note-on-lambdas,avoid>> lambdas.
-
-[[gremlin-go-scripts]]
-=== Submitting Scripts
-
-The `Client` class implementation/interface is based on the Java Driver, with some restrictions. Most notably,
-Gremlin-go does not yet implement the `Cluster` class. Instead, `Client` is instantiated directly.
-Usage is as follows:
+and GraphSON 2.0 like this:
 
-[source,go]
+[source,csharp]
 ----
-import "github.com/apache/tinkerpop/gremlin-go/v3/driver" <1>
-client, err := gremlingo.NewClient("ws://localhost:8182/gremlin") <2>
+include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=serializationGraphSon]
 ----
 
-<1> Import the Gremlin-Go 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.
+[[gremlin-dotnet-strategies]]
+=== Traversal Strategies
 
-Once a `Client` instance is ready, it is possible to issue some Gremlin:
+In order to add and remove traversal strategies from a traversal source, Gremlin.Net has an `AbstractTraversalStrategy`
+class along with a collection of subclasses that mirror the standard Gremlin-Java strategies.
 
-[source,go]
+[source,csharp]
 ----
-resultSet, err := client.Submit("g.V().count()") <1>
-result, err := resultSet.All() <2>
-fmt.Println(result[0].GetString()) <3>
+include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=traversalStrategies]
 ----
 
-<1> Submit a script that simply returns a Count of vertexes.
-<2> Get results from resultSet. Block until the the script is evaluated and results are sent back by the server.
-<3> Use the result.
+NOTE: Many of the TraversalStrategy classes in Gremlin.Net are proxies to the respective strategy on Apache TinkerPop’s
+JVM-based Gremlin traversal machine. As such, their `Apply(ITraversal)` method does nothing. However, the strategy is
+encoded in the Gremlin.Net bytecode and transmitted to the Gremlin traversal machine for re-construction machine-side.
 
-==== Per Request Settings
+[[gremlin-dotnet-transactions]]
+=== Transactions
 
-The `client.Submit()` functions accept a `bindings` which expects a map. The `bindings` provide a way to include options
-that are specific to the request made with the call to `Submit()`. A good use-case for this feature is to set a per-request
-override to the `evaluationTimeout` so that it only applies to the current request.
+To get a full understanding of this section, it would be good to start by reading the <<transactions,Transactions>>
+section of this documentation, which discusses transactions in the general context of TinkerPop itself. This section
+builds on that content by demonstrating the transactional syntax for C#.
 
-[source,go]
+[source,csharp]
 ----
-resultSet, err := client.Submit("g.V().repeat(both()).times(100)", map[string]interface{}{"evaluationTimeout": 5000})
+include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=transactions]
 ----
 
-The following options are allowed on a per-request basis in this fashion: `batchSize`, `requestId`, `userAgent` and
-`evaluationTimeout`.
+[[gremlin-dotnet-lambda]]
+=== The Lambda Solution
 
-IMPORTANT: The preferred method for setting a per-request timeout for scripts is demonstrated above, but those familiar
-with bytecode may try `g.with("evaluationTimeout", 500)` within a script. Scripts with multiple traversals and multiple
-timeouts will be interpreted as a sum of all timeouts identified in the script for that request.
+Supporting link:https://en.wikipedia.org/wiki/Anonymous_function[anonymous functions] across languages is difficult as
+most languages do not support lambda introspection and thus, code analysis. While Gremlin.Net doesn't support C# lambdas, it
+is still able to represent lambdas in other languages. When the lambda is represented in `Bytecode` its language is encoded
+such that the remote connection host can infer which translator and ultimate execution engine to use.
 
-[source,go]
+[source,csharp]
 ----
-resultSet, err := client.Submit("g.with('evaluationTimeout', 500).addV().iterate();"+
-  "g.addV().iterate();"+
-  "g.with('evaluationTimeout', 500).addV();", map[string]interface{}{"evaluationTimeout": 500})
-results, err := resultSet.All()
+g.V().Out().Map<int>(Lambda.Groovy("it.get().value('name').length()")).Sum<int>().ToList();      <1>
+g.V().Out().Map<int>(Lambda.Python("lambda x: len(x.get().value('name'))")).Sum<int>().ToList(); <2>
 ----
 
-In the above example, defines a timeout of 500 milliseconds, but the script has three traversals with
-two internal settings for the timeout using `with()`. The request timeout used by the server will therefore be 1000
-milliseconds (overriding the 500 which itself was an override for whatever configuration was on the server).
-
-[[gremlin-go-dsl]]
-=== Domain Specific Languages
+<1> `Lambda.Groovy()` can be used to create a Groovy lambda. 
+<2> `Lambda.Python()` can be used to create a Python lambda.
 
-Writing a Gremlin <<dsl,Domain Specific Language>> (DSL) in Go requires embedding of several structs and interfaces:
+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.
 
-* `GraphTraversal` - which exposes the various steps used in traversal writing
-* `GraphTraversalSource` - which spawns `GraphTraversal` instances
-* `AnonymousTraversal` - which spawns anonymous traversals from steps
+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'))`.
 
-The Social DSL based on the link:https://tinkerpop.apache.org/docs/x.y.z/images/tinkerpop-modern.png["modern" toy graph]
-might look like this:
+[[gremlin-dotnet-scripts]]
+=== Submitting Scripts
 
-[source,go]
-----
-// Optional syntactic sugar.
-var __ = gremlingo.T__
-var P = gremlingo.P
-var gt = gremlingo.P.Gt
-// Optional alias for import convenience.
-type GraphTraversal = gremlingo.GraphTraversal
-type GraphTraversalSource = gremlingo.GraphTraversalSource
-type AnonymousTraversal = gremlingo.AnonymousTraversal
+Gremlin scripts are sent to the server from a `IGremlinClient` instance.  A `IGremlinClient` is created as follows:
 
-// Embed Graph traversal inside custom traversal struct to add custom traversal functions.
-// In go, capitalizing the first letter exports (makes public) the struct/method to outside of package, for this example
-// we have defined everything package private. In actual usage, please see fit to your application.
-type socialTraversal struct {
-	*GraphTraversal
-}
+[source,csharp]
+----
+include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=submittingScripts]
+----
 
-func (s *socialTraversal) knows(personName string) *socialTraversal {
-	return &socialTraversal{s.Out("knows").HasLabel("person").Has("name", personName)}
-}
+If the remote system has authentication and SSL enabled, then the `GremlinServer` object can be configured as follows:
 
-func (s *socialTraversal) youngestFriendsAge() *socialTraversal {
-	return &socialTraversal{s.Out("knows").HasLabel("person").Values("age").Min()}
-}
+[source,csharp]
+----
+include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=submittingScriptsWithAuthentication]
+----
 
-func (s *socialTraversal) createdAtLeast(number int) *socialTraversal {
-	return &socialTraversal{s.OutE("created").Count().Is(gt(number))}
-}
+It is also possible to initialize the `Client` to use <<sessions,sessions>>:
 
-// Add custom social traversal source to spaw custom traversals.
-type socialTraversalSource struct {
-	*GraphTraversalSource
-}
+[source,csharp]
+----
+var gremlinServer = new GremlinServer("localhost", 8182);
+var client = new GremlinClient(gremlinServer, sessionId: Guid.NewGuid().ToString()))
+----
 
-// Define the source step function by adding steps to the bytecode.
-func (sts *socialTraversalSource) persons(personNames ...interface{}) *socialTraversal {
-	t := sts.GetGraphTraversal()
-	t.Bytecode.AddStep("V")
-	t.Bytecode.AddStep("hasLabel", "person")
-	if personNames != nil {
-		t.Bytecode.AddStep("has", "name", P.Within(personNames...))
-	}
-	return &socialTraversal{t}
-}
+==== Per Request Settings
 
+The `GremlinClient.Submit()` functions accept an option to build a raw `RequestMessage`. A good use-case for this
+feature is to set a per-request override to the `evaluationTimeout` so that it only applies to the current request.
 
-// Create the social anonymous traversal interface to embed and extend the anonymous traversal functions.
-type iSocialAnonymousTraversal interface {
-	AnonymousTraversal
-	knows(personName string) *GraphTraversal
-	youngestFriendsAge() *GraphTraversal
-	createdAtLeast(number int) *GraphTraversal
-}
+[source,csharp]
+----
+include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=submittingScriptsWithTimeout]
+----
 
-// Add the struct to implement the iSocialAnonymousTraversal interface.
-type socialAnonymousTraversal struct {
-	AnonymousTraversal
-	socialTraversal func() *socialTraversal
-}
+The following options are allowed on a per-request basis in this fashion: `batchSize`, `requestId`, `userAgent` and
+`evaluationTimeout` (formerly `scriptEvaluationTimeout` which is also supported but now deprecated). These options are
+available as constants on the `Gremlin.Net.Driver.Tokens` class.
 
-// Add the variable s__ to call anonymous traversal step functions in place of __.
-var s__ iSocialAnonymousTraversal = &socialAnonymousTraversal{
-	__,
-	func() *socialTraversal {
-		return &socialTraversal{gremlingo.NewGraphTraversal(nil, gremlingo.NewBytecode(nil), nil)}
-	},
-}
+IMPORTANT: The preferred method for setting a per-request timeout for scripts is demonstrated above, but those familiar
+with bytecode may try `g.with(EVALUATION_TIMEOUT, 500)` within a script. Scripts with multiple traversals and multiple
+timeouts will be interpreted as a sum of all timeouts identified in the script for that request.
 
-// Extended anonymous traversal functions need to return GraphTraversal for serialization purposes
-func (sat *socialAnonymousTraversal) knows(personName string) *GraphTraversal {
-	return sat.socialTraversal().knows(personName).GraphTraversal
-}
+anchor:gremlin-net-dsl[]
+[[gremlin-dotnet-dsl]]
+=== Domain Specific Languages
 
-func (sat *socialAnonymousTraversal) youngestFriendsAge() *GraphTraversal {
-	return sat.socialTraversal().youngestFriendsAge().GraphTraversal
-}
+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.
 
-func (sat *socialAnonymousTraversal) createdAtLeast(number int) *GraphTraversal {
-	return sat.socialTraversal().createdAtLeast(number).GraphTraversal
-}
+[source,csharp]
+----
+include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsDsl.cs[tags=dsl]
 ----
 
-Using the DSL requires a social traversal source to be created from the default traversal source:
+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,go]
+[source,csharp]
+----
+include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsDslTests.cs[tags=dslUsing]
 ----
-// Creating the driver remote connection as regular.
-driverRemoteConnection, _ := gremlingo.NewDriverRemoteConnection("ws://localhost:8182/gremlin",
-	func(settings *gremlingo.DriverRemoteConnectionSettings) {
-		settings.TraversalSource = "gmodern"
-	})
-defer driverRemoteConnection.Close()
 
-// Create social traversal source from graph traversal source.
-social := &socialTraversalSource{gremlingo.Traversal_().WithRemote(driverRemoteConnection)}
+and then it can be called from the application as follows:
 
-// We can now use the social traversal source as well as traversal steps
-resBool, _ := social.persons("marko", "stephen").knows("josh").HasNext()
-fmt.Println(resBool)
+[source,csharp]
+----
+include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsDslTests.cs[tags=dslExamples]
+----
 
-// Using the createdAtLeast step.
-resCreated, _ := social.persons().createdAtLeast(1).Next()
-fmt.Println(resCreated.GetString())
+anchor:gremlin-net-differences[]
+[[gremlin-dotnet-differences]]
+=== Differences
 
-// Using the social anonymous traversal.
-resAnon, _ := social.persons().Filter(s__.createdAtLeast(1)).Count().Next()
-fmt.Println(resAnon.GetString())
+The biggest difference between Gremlin in .NET and the canonical version in Java is the casing of steps. Canonical
+Gremlin utilizes `camelCase` as is typical in Java for function names, but C# utilizes `PascalCase` as it is more
+typical in that language. Therefore, when viewing a typical Gremlin example written in Gremlin Console, the conversion
+to C# usually just requires capitalization of the first letter in the step name, thus the following example in Groovy:
 
-// Note that error handling has been omitted with _ from the above examples.
+[source,groovy]
+----
+g.V().has('person','name','marko').
+  out('knows').
+  elementMap().toList()
 ----
 
-[[gremlin-go-differences]]
-=== Differences
+would become the following in C#:
 
-In situations where Go reserved words and global functions overlap with standard Gremlin steps and tokens, those
-bits of conflicting Gremlin get an underscore appended as a suffix. In addition, all function names start with a
-capital letter in order to be public:
+[source,csharp]
+----
+g.V().Has("Person","name","marko").
+  Out("knows").
+  ElementMap().ToList();
+----
 
-*Steps* - <<and-step,And()>>, <<as-step,As()>>, <<filter-step,Filter()>>, <<from-step,From()>>, <<id-step,Id()>>,
-<<is-step,Is()>>, <<in-step,In()>>, <<max-step,Max()>>, <<min-step,Min()>>, <<not-step,Not()>>, <<or-step,Or()>>,
-<<range-step,Range()>>, <<sum-step,Sum()>>, <<with-step,With()>>
+In addition to the uppercase change, also note the conversion of the single quotes to double quotes as is expected for
+declaring string values in C# and the addition of the semi-colon at the end of the line. In short, don't forget to
+apply the common syntax expectations for C# when trying to convert an example of Gremlin from a different language.
 
-*Tokens* - <<a-note-on-scopes,Scope.Global>>, <<a-note-on-scopes,Scope.Local>>
+Another common conversion issues lies in having to explicitly define generics, which can make canonical Gremlin appear
+much more complex in C# where type erasure is not a feature of the language. For example, the following example in
+Groovy:
 
-[[gremlin-go-aliases]]
-=== Aliases
-To make the code more readable and close to the Gremlin query language), you can use aliases. These aliases can be named with capital letters to be consistent with non-aliased steps but will result in exported variables which could be problematic if not being used in a top-level program (i.e. not a redistributable package).
-[source,go]
+[source,groovy]
+----
+g.V().repeat(__.out()).times(2).values('name')
 ----
-	var __ = gremlingo.T__
-	var gt = gremlingo.P.Gt
-	var order = gremlingo.Order
 
-	results, err := g.V().HasLabel("person").Has("age", __.Is(gt(30))).Order().By("age", order.Desc).ToList()
+must be written as:
+
+[source,csharp]
+----
+g.V().Repeat(__.Out()).Times(2).Values<string>("name");
 ----
 
-==== List of useful aliases
-[source,go]
+Gremlin allows for `Map` instances to include `null` keys, but `null` keys in C# `Dictionary` instances are not allowed.
+It is therefore necessary to rewrite a traversal such as:
+
+[source,javascript]
+----
+g.V().groupCount().by('age')
 ----
-	// common
-	var __ = gremlingo.T__
-	var TextP = gremlingo.TextP
 
-	// predicates
-	var between = gremlingo.P.Between
-	var eq = gremlingo.P.Eq
-	var gt = gremlingo.P.Gt
-	var gte = gremlingo.P.Gte
-	var inside = gremlingo.P.Inside
-	var lt = gremlingo.P.Lt
-	var lte = gremlingo.P.Lte
-	var neq = gremlingo.P.Neq
-	var not = gremlingo.P.Not
-	var outside = gremlingo.P.Outside
-	var test = gremlingo.P.Test
-	var within = gremlingo.P.Within
-	var without = gremlingo.P.Without
-	var and = gremlingo.P.And
-	var or = gremlingo.P.Or
+where "age" is not a valid key for all vertices in a way that will remove the need for a `null` to be returned.
 
-	// sorting
-	var order = gremlingo.Order
+[source,javascript]
+----
+g.V().has('age').groupCount().by('age')
+g.V().hasLabel('person').groupCount().by('age')
 ----
 
-[[gremlin-go-limitations]]
+Either of the above two options accomplishes the desired goal as both prevent `groupCount()` from having to process
+the possibility of `null`.
+
+anchor:gremlin-net-limitations[]
+[[gremlin-dotnet-limitations]]
 === Limitations
 
-* There is no default `set` type in Go. Any set type code from server will be deserialized into slices with the list
-type implementation. To input a set into Gremlin-Go, a custom struct which implements the `gremlingo.Set` interface
-will be serialized as a set. `gremlingo.NewSimpleSet` is a basic implementation of a set that is provided by Gremlin-Go
-that can be used to fulfill the `gremlingo.Set` interface if desired.
+* The `subgraph()`-step is not supported by any variant that is not running on the Java Virtual Machine as there is
+no `Graph` instance to deserialize a result into on the client-side. A workaround is to replace the step with
+`aggregate(local)` and then convert those results to something the client can use locally.
 
-[[gremlin-go-examples]]
+anchor:gremlin-dotnet-template[]
+anchor:dotnet-application-examples[]
+anchor:gremlin-net-examples[]
+[[gremlin-dotnet-examples]]
 === Application Examples
 
-The TinkerPop source code contains a simple Go script that shows a basic example of how gremlin-go works. It
-can be found in GitHub link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-go/example/example.go[here]
-and is designed to work best with a running <<gremlin-server,Gremlin Server>> configured with the default
-`conf/gremlin-server.yaml` file as included with the standard release packaging.
+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]
-----
-go run example.go
-----
+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-python]]
 == Gremlin-Python


[tinkerpop] 02/03: Merge branch '3.5-dev' into 3.6-dev

Posted by sp...@apache.org.
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 097d3f7103ba458f7827abcdb7ec55ecac6a90ab
Merge: d0a526fd4d b8e6b2827d
Author: Stephen Mallette <st...@amazon.com>
AuthorDate: Tue Jan 10 13:35:45 2023 -0500

    Merge branch '3.5-dev' into 3.6-dev

 docs/src/reference/gremlin-variants.asciidoc | 2784 +++++++++++++-------------
 1 file changed, 1392 insertions(+), 1392 deletions(-)

diff --cc docs/src/reference/gremlin-variants.asciidoc
index 605ef12b1d,30590dcd87..fcf8f126b1
--- a/docs/src/reference/gremlin-variants.asciidoc
+++ b/docs/src/reference/gremlin-variants.asciidoc
@@@ -556,96 -626,231 +626,229 @@@ are provided as follows
  
  [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);
-     }
+ GraphTraversalSource g = traversal().withRemote(DriverRemoteConnection.using("localhost",8182,"g"));
+ ----
  
-     public default <E2 extends Number> GraphTraversal<S, E2> youngestFriendsAge() {
-         return out("knows").hasLabel("person").values("age").min();
-     }
+ It is also possible to create it from a configuration. The most basic way to do so involves the following line of code:
  
-     public default GraphTraversal<S, Long> createdAtLeast(int number) {
-         return outE("created").count().is(P.gte(number));
-     }
- }
+ [source,java]
+ ----
+ GraphTraversalSource g = traversal().withRemote('conf/remote-graph.properties');
  ----
  
- IMPORTANT: Follow the TinkerPop convention of using `<S,E>` in naming generics as those conventions are taken into
- account when generating the anonymous traversal class. The processor attempts to infer the appropriate type parameters
- when generating the anonymous traversal class. If it cannot do it correctly, it is possible to avoid the inference by
- using the `GremlinDsl.AnonymousMethod` annotation on the DSL method. It allows explicit specification of the types to
- use.
+ The `remote-graph.properties` file simply provides connection information to the `GraphTraversalSource` which is used
+ to configure a `RemoteConnection`. That file looks like this:
+ 
+ [source,text]
+ ----
+ gremlin.remote.remoteConnectionClass=org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteConnection
+ gremlin.remote.driver.clusterFile=conf/remote-objects.yaml
+ gremlin.remote.driver.sourceName=g
+ ----
+ 
+ The `RemoteConnection` is an interface that provides the transport mechanism for "g" and makes it possible to for
+ that mechanism to be altered (typically by graph providers who have their own protocols). TinkerPop provides one such
+ implementation called the `DriverRemoteConnection` which enables transport over Gremlin Server protocols using the
+ TinkerPop driver. The driver is configured by the specified `gremlin.remote.driver.clusterFile` and the local "g" is
+ bound to the `GraphTraversalSource` on the remote end with `gremlin.remote.driver.sourceName` which in this case is
+ also "g".
+ 
+ There are other ways to configure the traversal using `withRemote()` as it has other overloads. It can take an
+ Apache Commons `Configuration` object which would have keys similar to those shown in the properties file and it
+ can also take a `RemoteConnection` instance directly. The latter is interesting in that it means it is possible to
+ programmatically construct all aspects of the `RemoteConnection`. For TinkerPop usage, that might mean directly
+ constructing the `DriverRemoteConnection` and the driver instance that supplies the transport mechanism. For example,
+ the command shown above could be re-written using programmatic construction as follows:
+ 
+ [source,java]
+ ----
+ Cluster cluster = Cluster.open();
+ GraphTraversalSource g = traversal().withRemote(DriverRemoteConnection.using(cluster, "g"));
+ ----
+ 
+ Please consider the following example:
+ 
+ [gremlin-groovy]
+ ----
+ g = traversal().withRemote('conf/remote-graph.properties')
+ g.V().elementMap()
+ g.close()
+ ----
+ 
+ [source,java]
+ ----
+ GraphTraversalSource g = traversal().withRemote("conf/remote-graph.properties");
+ List<Map> list = g.V().elementMap();
+ g.close();
+ ----
+ 
+ Note the call to `close()` above. The call to `withRemote()` internally instantiates a connection via the driver that
+ can only be released by "closing" the `GraphTraversalSource`. It is important to take that step to release network
+ resources associated with `g`.
+ 
+ If working with multiple remote `TraversalSource` instances it is more efficient to construct `Cluster` and `Client`
+ objects and then re-use them.
+ 
+ [gremlin-groovy]
+ ----
+ cluster = Cluster.open('conf/remote-objects.yaml')
+ client = cluster.connect()
+ g = traversal().withRemote(DriverRemoteConnection.using(client, "g"))
+ g.V().elementMap()
+ g.close()
+ client.close()
+ cluster.close()
+ ----
+ 
+ If the `Client` instance is supplied externally, as is shown above, then it is not closed implicitly by the close of
+ "g".  Closing "g" will have no effect on "client" or "cluster". When supplying them externally, the `Client` and
+ `Cluster` objects must also be closed explicitly. It's worth noting that the close of a `Cluster` will close all
+ `Client` instances spawned by the `Cluster`.
+ 
+ Some connection options can also be set on individual requests made through the Java driver using `with()` step
+ on the `TraversalSource`. For instance to set request timeout to 500 milliseconds:
+ 
+ [source,java]
+ ----
+ GraphTraversalSource g = traversal().withRemote(conf);
+ List<Vertex> vertices = g.with(Tokens.ARGS_EVAL_TIMEOUT, 500L).V().out("knows").toList()
+ ----
+ 
+ The following options are allowed on a per-request basis in this fashion: `batchSize`, `requestId`, `userAgent` and
+ `evaluationTimeout` (formerly `scriptEvaluationTimeout` which is also supported but now deprecated). Use of `Tokens`
+ to reference these options is preferred.
+ 
+ anchor:java-imports[]
+ [[gremlin-java-imports]]
+ === Common Imports
+ 
+ There are a number of classes, functions and tokens that are typically used with Gremlin. The following imports
+ provide most of the common functionality required to use Gremlin:
+ 
+ [source,java]
+ ----
+ import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+ import org.apache.tinkerpop.gremlin.process.traversal.IO;
+ import static org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource.traversal;
+ import static org.apache.tinkerpop.gremlin.process.traversal.Operator.*;
+ import static org.apache.tinkerpop.gremlin.process.traversal.Order.*;
+ import static org.apache.tinkerpop.gremlin.process.traversal.P.*;
+ import static org.apache.tinkerpop.gremlin.process.traversal.Pop.*;
+ import static org.apache.tinkerpop.gremlin.process.traversal.SackFunctions.*;
+ import static org.apache.tinkerpop.gremlin.process.traversal.Scope.*;
+ import static org.apache.tinkerpop.gremlin.process.traversal.TextP.*;
+ import static org.apache.tinkerpop.gremlin.structure.Column.*;
+ import static org.apache.tinkerpop.gremlin.structure.Direction.*;
+ import static org.apache.tinkerpop.gremlin.structure.T.*;
+ import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.*;
+ ----
+ 
+ [[gremlin-java-configuration]]
+ === Configuration
+ 
+ The following table describes the various configuration options for the Gremlin Driver:
+ 
+ [width="100%",cols="3,10,^2",options="header"]
+ |=========================================================
+ |Key |Description |Default
+ |connectionPool.channelizer |The fully qualified classname of the client `Channelizer` that defines how to connect to the server. |`Channelizer.WebSocketChannelizer`
+ |connectionPool.enableSsl |Determines if SSL should be enabled or not. If enabled on the server then it must be enabled on the client. |false
+ |connectionPool.keepAliveInterval |Length of time in milliseconds to wait on an idle connection before sending a keep-alive request. Set to zero to disable this feature. |180000
+ |connectionPool.keyStore |The private key in JKS or PKCS#12 format. |_none_
+ |connectionPool.keyStorePassword |The password of the `keyStore` if it is password-protected. |_none_
+ |connectionPool.keyStoreType |`JKS` (Java 8 default) or `PKCS12` (Java 9+ default)|_none_
+ |connectionPool.maxContentLength |The maximum length in bytes that a message can be sent to the server. This number can be no greater than the setting of the same name in the server configuration. |65536
+ |connectionPool.maxInProcessPerConnection |The maximum number of in-flight requests that can occur on a connection. |4
+ |connectionPool.maxSimultaneousUsagePerConnection |The maximum number of times that a connection can be borrowed from the pool simultaneously. |16
+ |connectionPool.maxSize |The maximum size of a connection pool for a host. |8
+ |connectionPool.maxWaitForConnection |The amount of time in milliseconds to wait for a new connection before timing out. |3000
+ |connectionPool.maxWaitForClose |The amount of time in milliseconds to wait for pending messages to be returned from the server before closing the connection. |3000
+ |connectionPool.minInProcessPerConnection |The minimum number of in-flight requests that can occur on a connection. |1
+ |connectionPool.minSimultaneousUsagePerConnection |The maximum number of times that a connection can be borrowed from the pool simultaneously. |8
+ |connectionPool.minSize |The minimum size of a connection pool for a host. |2
+ |connectionPool.reconnectInterval |The amount of time in milliseconds to wait before trying to reconnect to a dead host. |1000
+ |connectionPool.resultIterationBatchSize |The override value for the size of the result batches to be returned from the server. |64
+ |connectionPool.sslCipherSuites |The list of JSSE ciphers to support for SSL connections. If specified, only the ciphers that are listed and supported will be enabled. If not specified, the JVM default is used.  |_none_
+ |connectionPool.sslEnabledProtocols |The list of SSL protocols to support for SSL connections. If specified, only the protocols that are listed and supported will be enabled. If not specified, the JVM default is used.  |_none_
+ |connectionPool.sslSkipCertValidation |Configures the `TrustManager` to trust all certs without any validation. Should not be used in production.|false
+ |connectionPool.trustStore |File location for a SSL Certificate Chain to use when SSL is enabled. If this value is not provided and SSL is enabled, the default `TrustManager` will be used. |_none_
+ |connectionPool.trustStorePassword |The password of the `trustStore` if it is password-protected |_none_
+ |connectionPool.validationRequest |A script that is used to test server connectivity. A good script to use is one that evaluates quickly and returns no data. The default simply returns an empty string, but if a graph is required by a particular provider, a good traversal might be `g.inject()`. |_''_
+ |connectionPool.connectionSetupTimeoutMillis | Duration of time in milliseconds provided for connection setup to complete which includes WebSocket protocol handshake and SSL handshake. |15000
+ |hosts |The list of hosts that the driver will connect to. |localhost
+ |jaasEntry |Sets the `AuthProperties.Property.JAAS_ENTRY` properties for authentication to Gremlin Server. |_none_
+ |nioPoolSize |Size of the pool for handling request/response operations. |available processors
+ |password |The password to submit on requests that require authentication. |_none_
+ |path |The URL path to the Gremlin Server. |_/gremlin_
+ |port |The port of the Gremlin Server to connect to. The same port will be applied for all hosts. |8192
+ |protocol |Sets the `AuthProperties.Property.PROTOCOL` properties for authentication to Gremlin Server. |_none_
+ |serializer.className |The fully qualified class name of the `MessageSerializer` that will be used to communicate with the server. Note that the serializer configured on the client should be supported by the server configuration. |_none_
+ |serializer.config |A `Map` of configuration settings for the serializer. |_none_
+ |username |The username to submit on requests that require authentication. |_none_
+ |workerPoolSize |Size of the pool for handling background work. |available processors * 2
+ |enableUserAgentOnConnect |Enables sending a user agent to the server during connection requests. More details can be found in provider docs link:https://tinkerpop.apache.org/docs/x.y.z/dev/provider/#_graph_driver_provider_requirements[here].|true
+ |=========================================================
  
- 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:
+ Please see the link:https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/driver/Cluster.Builder.html[Cluster.Builder javadoc] to get more information on these settings.
  
- [source,java]
- ----
- org.apache.tinkerpop.gremlin.process.traversal.dsl.GremlinDslProcessor
- ----
+ [[gremlin-java-transactions]]
+ === Transactions
  
- The annotation processor will generate several classes for the DSL:
+ Transactions with Java are best described in <<transactions,The Traversal - Transactions>> section of this
+ documentation as Java covers both embedded and remote use cases.
  
- * `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.
- * `__` - Spawns anonymous `DefaultSocialTraversal` instances.
+ [[gremlin-java-serialization]]
+ === Serialization
  
- Using the DSL then just involves telling the `Graph` to use it:
+ Remote systems like Gremlin Server and Remote Gremlin Providers respond to requests made in a particular serialization
+ format and respond by serializing results to some format to be interpreted by the client. For JVM-based languages,
 -there are three options for serialization: Gryo, GraphSON and GraphBinary. It is important that the client and server
++there are two options for serialization: GraphSON and GraphBinary. It is important that the client and server
+ have the same serializers configured in the same way or else one or the other will experience serialization exceptions
+ and fail to always communicate. Discrepancy in serializer registration between client and server can happen fairly
+ easily as different graph systems may automatically include serializers on the server-side, thus leaving the client
+ to be configured manually. As an example:
  
  [source,java]
  ----
- SocialTraversalSource social = traversal(SocialTraversalSource.class).withEmbedded(graph);
- 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]
+ IoRegistry registry = ...; // an IoRegistry instance exposed by a specific graph provider
+ TypeSerializerRegistry typeSerializerRegistry = TypeSerializerRegistry.build().addRegistry(registry).create();
+ MessageSerializer serializer = new GraphBinaryMessageSerializerV1(typeSerializerRegistry);
+ Cluster cluster = Cluster.build().
+                           serializer(serializer).
+                           create();
+ Client client = cluster.connect();
+ GraphTraversalSource g = traversal().withRemote(DriverRemoteConnection.using(client, "g"));
  ----
- public class SocialTraversalSourceDsl extends GraphTraversalSource {
- 
-     public SocialTraversalSourceDsl(Graph graph, TraversalStrategies traversalStrategies) {
-         super(graph, traversalStrategies);
-     }
- 
-     public SocialTraversalSourceDsl(Graph graph) {
-         super(graph);
-     }
- 
-     public SocialTraversalSourceDsl(RemoteConnection connection) {
-         super(connection);
-     }
  
-     public GraphTraversal<Vertex, Vertex> persons(String... names) {
-         GraphTraversalSource clone = this.clone();
+ The `IoRegistry` tells the serializer what classes from the graph provider to auto-register during serialization.
+ Gremlin Server roughly uses this same approach when it configures its serializers, so using this same model will
 -ensure compatibility when making requests. Obviously, it is possible to switch to GraphSON or Gryo by using
 -the appropriate `MessageSerializer` (e.g. `GraphSONMessageSerializerV3d0` or `GryoMessageSerializerV3d0` respectively)
++ensure compatibility when making requests. Obviously, it is possible to switch to GraphSON or GraphBinary by using
++the appropriate `MessageSerializer` (e.g. `GraphSONMessageSerializerV3d0` or `GraphBinaryMessageSerializerV1d0` respectively)
+ in the same way and building that into the `Cluster` object.
  
-         // 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));
 -NOTE: Gryo is no longer the preferred binary serialization format for Gremlin Server - please prefer GraphBinary.
 -
+ [[gremlin-java-lambda]]
+ === The Lambda Solution
  
-         traversal = traversal.hasLabel("person");
-         if (names.length > 0) traversal = traversal.has("name", P.within(names));
+ Supporting link:https://en.wikipedia.org/wiki/Anonymous_function[anonymous functions] across languages is difficult as
+ most languages do not support lambda introspection and thus, code analysis. In Gremlin-Java and with
+ <<connecting-embedded,embedded>> usage, lambdas can be leveraged directly:
  
-         return traversal;
-     }
- }
+ [source,java]
+ ----
+ g.V().out("knows").map(t -> t.get().value("name") + " is the friend name") <1>
+ g.V().out("knows").sideEffect(System.out::println) <2>
+ g.V().as("a").out("knows").as("b").select("b").by((Function<Vertex, Integer>) v -> v.<String>value("name").length()) <3>
  ----
  
- 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`:
+ <1> A Java `Function` is used to map a `Traverser<S>` to an object `E`.
+ <2> Gremlin steps that take consumer arguments can be passed Java method references.
+ <3> Gremlin-Java may sometimes require explicit lambda typing when types can not be automatically inferred.
+ 
+ When sending traversals remotely to <<connecting-gremlin-server,Gremlin Server>> or
+ <<connecting-rgp,Remote Gremlin Providers>>, the static methods of `Lambda` should be used and should denote a
+ particular JSR-223 `ScriptEngine` that is available on the remote end (typically, this is Groovy). `Lambda` creates a
+ string-based lambda that is  then converted into a lambda/closure/anonymous-function/etc. by the respective lambda
+ language's JSR-223 `ScriptEngine` implementation.
  
  [source,java]
  ----
@@@ -659,471 -867,356 +865,366 @@@ execute. To express bindings in Java, u
  
  [source,java]
  ----
- SocialTraversalSource social = traversal(SocialTraversalSource.class).withEmbedded(graph);
- social.persons("marko").knows("josh");
+ b = Bindings.instance()
+ g.V(b.of('id',1)).out('created').values('name').map{t -> "name: " + t.get() }
+ g.V(b.of('id',4)).out('created').values('name').map{t -> "name: " + t.get() }
+ g.V(b.of('id',4)).out('created').values('name').getBytecode()
+ g.V(b.of('id',4)).out('created').values('name').getBytecode().getBindings()
+ cluster.close()
  ----
  
- 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-java-troubleshooting]]
- === Troubleshooting
- 
- *Max frame length of 65536 has been exceeded*
- 
- This error occurs when the driver attempts to process a request/response that exceeds the configured maximum size.
- The most direct way to fix this problem is to increase the `maxContentLength` setting in the driver. Ideally, the
- `maxContentLength` set for the driver should match the setting defined on the server.
- 
- *TimeoutException*
- 
- A `TimeoutException` is thrown by the driver when the time limit assigned by the `maxWaitForConnection` is exceeded
- when trying to borrow a connection from the connection pool for a particular host. There are generally two scenarios
- where this occurs:
- 
- 1. The server has actually reached its maximum capacity or the driver has just learned that the server is unreachable.
- 2. The client is throttling requests when the pool is exhausted.
+ Both traversals are abstractly defined as `g.V(id).out('created').values('name').map{t -> "name: " + t.get() }` and
+ thus, the first submission can be cached for faster evaluation on the next submission.
  
- The latter of the two can be addressed from the driver side in the following ways:
+ WARNING: It is generally advised to avoid lambda usage. Please consider <<a-note-on-lambdas,A Note On Lambdas>> for
+ more information.
  
- * Increase the `maxWaitForConnection` allowing the client to wait a bit longer for a connection to become available.
- * Increase the number of requests allowed per connection by increasing the `maxSimultaneousUsagePerConnection` and
- `maxInProcessPerConnection` settings.
- * Increase the number of connections available in the connection pool by increasing the `maxConnectionPoolSize`.
+ [[gremlin-java-scripts]]
+ === Submitting Scripts
  
- The exception and logs (assuming they are enabled) should contain information about the state of the connection pool
- along with its connections which can help shed more light on which of these scenarios caused the problem. Some examples
- of these messages and their meaning are shown below:
+ image:gremlin-java.png[width=175,float=left] TinkerPop comes equipped with a reference client for Java-based
+ applications.  It is referred to as `gremlin-driver`, which enables applications to send requests to Gremlin Server
+ and get back results.
  
- _The server is unavailable_
+ Gremlin scripts are sent to the server from a `Client` instance.  A `Client` is created as follows:
  
- [source,text]
+ [source,java]
  ----
- Timed-out (500 MILLISECONDS) waiting for connection on Host{address=localhost/127.0.0.1:45940, hostUri=ws://localhost:45940/gremlin}. Potential Cause: Connection refused: no further information
- > ConnectionPool (Host{address=localhost/127.0.0.1:45940, hostUri=ws://localhost:45940/gremlin})- no connections in pool
+ Cluster cluster = Cluster.open();  <1>
+ Client client = cluster.connect(); <2>
  ----
  
- _Client is likely issuing more requests than the pool size can handle_
- 
- [source,text]
- ----
- Timed-out (150 MILLISECONDS) waiting for connection on Host{address=localhost/127.0.0.1:45940, hostUri=ws://localhost:45940/gremlin}. Potential Cause: Number of active requests exceeds pool size. Consider increasing the value for maxConnectionPoolSize.
- ConnectionPool (Host{address=localhost/127.0.0.1:45940, hostUri=ws://localhost:45940/gremlin})
- Connection Pool Status (size=1 max=1 min=1 toCreate=0 bin=0)
- > Connection{channel=5a859d62 isDead=false borrowed=1 pending=1 markedReplaced=false closing=false created=2022-12-19T21:08:21.569613100Z thread=gremlin-driver-conn-scheduler-1}
- -- bin --
- ----
+ <1> Opens a reference to `localhost` - note that there are many configuration options available in defining a `Cluster` object.
+ <2> Creates a `Client` given the configuration options of the `Cluster`.
  
- _Network traffic is slow and the websocket handshake does not complete in time_
+ Once a `Client` instance is ready, it is possible to issue some Gremlin Groovy scripts:
  
- [source,text]
- ----
- Timed-out (250 MILLISECONDS) waiting for connection on Host{address=localhost/127.0.0.1:45940, hostUri=ws://localhost:45940/gremlin}. Potential Cause: WebSocket handshake not completed in stipulated time=[100]ms
- ConnectionPool (Host{address=localhost/127.0.0.1:45940, hostUri=ws://localhost:45940/gremlin})
- Connection Pool Status (size=1 max=5 min=1 toCreate=0 bin=0)
- > Connection{channel=205fc8d2 isDead=false borrowed=1 pending=1 markedReplaced=false closing=false created=2022-12-19T21:10:04.692921600Z thread=gremlin-driver-conn-scheduler-1}
- -- bin --
+ [source,java]
  ----
+ ResultSet results = client.submit("[1,2,3,4]");  <1>
+ results.stream().map(i -> i.get(Integer.class) * 2);       <2>
  
- anchor:java-application-examples[]
- anchor:gremlin-archetypes[]
- [[gremlin-java-examples]]
- === Application Examples
- 
- The available link:https://maven.apache.org/guides/introduction/introduction-to-archetypes.html[Maven archetypes] are
- as follows:
- 
- * `gremlin-archetype-dsl` - An example project that demonstrates how to build Domain Specific Languages with Gremlin
- in Java.
- * `gremlin-archetype-server` - An example project that demonstrates the basic structure of a
- <<gremlin-server,Gremlin Server>> project, how to connect with the Gremlin Driver, and how to embed Gremlin Server in
- a testing framework.
- * `gremlin-archetype-tinkergraph` - A basic example of how to structure a TinkerPop project with Maven.
- 
- Use Maven to generate these example projects with a command like:
- 
- [source,shell]
- $ mvn archetype:generate -DarchetypeGroupId=org.apache.tinkerpop -DarchetypeArtifactId=gremlin-archetype-server \
-       -DarchetypeVersion=x.y.z -DgroupId=com.my -DartifactId=app -Dversion=0.1 -DinteractiveMode=false
- 
- This command will generate a new Maven project in a directory called "app" with a `pom.xml` specifying a `groupId` of
- `com.my`. Please see the `README.asciidoc` in the root of each generated project for information on how to build and
- execute it.
+ CompletableFuture<List<Result>> results = client.submit("[1,2,3,4]").all();  <3>
  
- [[gremlin-javascript]]
- == Gremlin-JavaScript
+ CompletableFuture<ResultSet> future = client.submitAsync("[1,2,3,4]"); <4>
  
- image:gremlin-js.png[width=130,float=right] Apache TinkerPop's Gremlin-JavaScript implements Gremlin within the
- JavaScript language. It targets Node.js runtime and can be used on different operating systems on any Node.js 6 or
- above. Since the JavaScript naming conventions are very similar to that of Java, it should be very easy to switch
- between Gremlin-Java and Gremlin-JavaScript.
+ Map<String,Object> params = new HashMap<>();
+ params.put("x",4);
+ client.submit("[1,2,3,x]", params); <5>
+ ----
  
- [source,bash]
- npm install gremlin
+ <1> Submits 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.
+ In this case, they are streamed from the server as they arrive.
+ <3> Submit a script, get a `ResultSet`, then return a `CompletableFuture` that will be called when all results have been returned.
+ <4> Submit a script asynchronously without waiting for the request to be written to the server.
+ <5> Parameterized request are considered the most efficient way to send Gremlin to the server as they can be cached,
+ which will boost performance and reduce resources required on the server.
  
- [[gremlin-javascript-connecting]]
- === Connecting
+ ==== Per Request Settings
  
- 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.
+ There are a number of overloads to `Client.submit()` that accept a `RequestOptions` object. The `RequestOptions`
+ provide a way to include options that are specific to the request made with the call to `submit()`. A good use-case for
+ this feature is to set a per-request override to the `evaluationTimeout` so that it only applies to the current
+ request.
  
- [source,javascript]
+ [source,java]
  ----
- const g = traversal().withRemote(new DriverRemoteConnection('ws://localhost:8182/gremlin'));
+ Cluster cluster = Cluster.open();
+ Client client = cluster.connect();
+ RequestOptions options = RequestOptions.build().timeout(500).create();
+ List<Result> result = client.submit("g.V().repeat(both()).times(100)", options).all().get();
  ----
  
- Gremlin-JavaScript supports plain text SASL authentication, you can set it on the connection options.
+ The preferred method for setting a per-request timeout for scripts is demonstrated above, but those familiar with
+ bytecode may try `g.with(EVALUATION_TIMEOUT, 500)` within a script. Gremlin Server will respect timeouts set this way
+ in scripts as well. With scripts of course, it is possible to send multiple traversals at once in the same script.
+ In such events, the timeout for the request is interpreted as a sum of all timeouts identified in the script.
  
- [source,javascript]
+ [source,java]
  ----
- const authenticator = new gremlin.driver.auth.PlainTextSaslAuthenticator('myuser', 'mypassword');
- const g = traversal().withRemote(new DriverRemoteConnection('ws://localhost:8182/gremlin', { authenticator });
+ RequestOptions options = RequestOptions.build().timeout(500).create();
+ List<Result> result = client.submit("g.with(EVALUATION_TIMEOUT, 500).addV().iterate();" +
+                                     "g.addV().iterate();" + 
+                                     "g.with(EVALUATION_TIMEOUT, 500).addV();", options).all().get();
  ----
  
- Given that I/O operations in Node.js are asynchronous by default, <<terminal-steps,Terminal Steps>> return a `Promise`:
- 
- * `Traversal.toList()`: Returns a `Promise` with an `Array` as result value.
- * `Traversal.next()`: Returns a `Promise` with a `{ value, done }` tuple as result value, according to the
- link:https://github.com/tc39/proposal-async-iteration[async iterator proposal].
- * `Traversal.iterate()`: Returns a `Promise` without a value.
- 
- For example:
+ In the above example, `RequestOptions` defines a timeout of 500 milliseconds, but the script has three traversals with
+ two internal settings for the timeout using `with()`. The request timeout used by the server will therefore be 1000
+ milliseconds (overriding the 500 which itself was an override for whatever configuration was on the server).
  
- [source,javascript]
- ----
- g.V().hasLabel('person').values('name').toList()
-   .then(names => console.log(names));
- ----
+ ==== Aliases
  
- When using `async` functions it is possible to `await` the promises:
+ Scripts submitted to Gremlin Server automatically have the globally configured `Graph` and `TraversalSource` instances
+ made available to them.  Therefore, if Gremlin Server configures two `TraversalSource` instances called "g1" and "g2"
+ a script can simply reference them directly as:
  
- [source,javascript]
+ [source,java]
  ----
- const names = await g.V().hasLabel('person').values('name').toList();
- console.log(names);
+ client.submit("g1.V()")
+ client.submit("g2.V()")
  ----
  
- Some connection options can also be set on individual requests made through the using `with()` step on the
- `TraversalSource`. For instance to set request timeout to 500 milliseconds:
+ While this is an acceptable way to submit scripts, it has the downside of forcing the client to encode the server-side
+ variable name directly into the script being sent.  If the server configuration ever changed such that "g1" became
+ "g100", the client-side code might have to see a significant amount of change.  Decoupling the script code from the
+ server configuration can be managed by the `alias` method on `Client` as follows:
  
- [source,javascript]
+ [source,java]
  ----
- const vertices = await g.with_('evaluationTimeout', 500).V().out('knows').toList()
+ Client g1Client = client.alias("g1")
+ Client g2Client = client.alias("g2")
+ g1Client.submit("g.V()")
+ g2Client.submit("g.V()")
  ----
  
- The following options are allowed on a per-request basis in this fashion: `batchSize`, `requestId`, `userAgent` and
- `evaluationTimeout` (formerly `scriptEvaluationTimeout` which is also supported but now deprecated).
+ The above code demonstrates how the `alias` method can be used such that the script need only contain a reference
+ to "g" and "g1" and "g2" are automatically rebound into "g" on the server-side.
  
- [[gremlin-javascript-imports]]
- === Common Imports
+ [[gremlin-java-dsl]]
+ === Domain Specific Languages
  
- There are a number of classes, functions and tokens that are typically used with Gremlin. The following imports
- provide most of the typical functionality required to use Gremlin:
 -Creating a <<dsl,Domain Specific Language>> (DSL) in Java requires the `@GremlinDsl` Java annotation in `gremlin-core`.
 -This annotation should be applied to a "DSL interface" that extends `GraphTraversal.Admin`:
++Creating a <<dsl,Domain Specific Language>> (DSL) in Java requires the `@GremlinDsl` Java annotation in the
++`gremlin-annotations` module. This annotation should be applied to a "DSL interface" that extends
++`GraphTraversal.Admin`:
 +
- [source,javascript]
++[source,xml]
 +----
- const gremlin = require('gremlin');
- const traversal = gremlin.process.AnonymousTraversalSource.traversal;
- const __ = gremlin.process.statics;
- const DriverRemoteConnection = gremlin.driver.DriverRemoteConnection;
- const column = gremlin.process.column
- const direction = gremlin.process.direction
- Direction: {
-   BOTH: traversalModule.direction.both,
-   IN: traversalModule.direction.in,
-   OUT: traversalModule.direction.out,
-   from_: traversalModule.direction.in,
-   to: traversalModule.direction.out,
- }
- const p = gremlin.process.P
- const textp = gremlin.process.TextP
- const pick = gremlin.process.pick
- const pop = gremlin.process.pop
- const order = gremlin.process.order
- const scope = gremlin.process.scope
- const t = gremlin.process.t
++<dependency>
++    <groupId>org.apache.tinkerpop</groupId>
++    <artifactId>gremlin-annotations</artifactId>
++    <version>x.y.z</version>
++</dependency>
 +----
  
- By defining these imports it becomes possible to write Gremlin in the more shorthand, canonical style that is
- demonstrated in most examples found here in the documentation:
- 
- [source,javascript]
+ [source,java]
  ----
- const { P: { gt } } = gremlin.process;
- const { order: { desc } } = gremlin.process;
- g.V().hasLabel('person').has('age',gt(30)).order().by('age',desc).toList()
+ @GremlinDsl
+ public interface SocialTraversalDsl<S, E> extends GraphTraversal.Admin<S, E> {
+ }
  ----
  
- [[gremlin-javascript-configuration]]
- === Configuration
- The following table describes the various configuration options for the Gremlin-Javascript Driver. They
- can be passed in the constructor of a new `Client` or `DriverRemoteConnection` :
- 
- [width="100%",cols="3,3,10,^2",options="header"]
- |=========================================================
- |Key |Type |Description |Default
- |url |String |The resource uri. |None
- |options |Object |The connection options. |{}
- |options.ca |Array |Trusted certificates. |undefined
- |options.cert |String/Array/Buffer |The certificate key. |undefined
- |options.mimeType |String |The mime type to use. |'application/vnd.gremlin-v3.0+json'
- |options.pfx |String/Buffer |The private key, certificate, and CA certs. |undefined
- |options.reader |GraphSONReader/GraphBinaryReader |The reader to use. |select reader according to mimeType
- |options.writer |GraphSONWriter |The writer to use. |select writer according to mimeType
- |options.rejectUnauthorized |Boolean |Determines whether to verify or not the server certificate. |undefined
- |options.traversalSource |String |The traversal source. |'g'
- |options.authenticator |Authenticator |The authentication handler to use. |undefined
- |options.processor |String |The name of the opProcessor to use, leave it undefined or set 'session' when session mode. |undefined
- |options.session |String |The sessionId of Client in session mode. undefined means session-less Client. |undefined
- |options.enableUserAgentOnConnect |Boolean |Determines if a user agent will be sent during connection handshake. |true
- |options.headers |Object |An associative array containing the additional header key/values for the initial request. |undefined
- |options.pingEnabled |Boolean |Setup ping interval. |true
- |options.pingInterval |Number |Ping request interval in ms if ping enabled. |60000
- |options.pongTimeout |Number |Timeout of pong response in ms after sending a ping. |30000
- |=========================================================
- 
- [[gremlin-javascript-transactions]]
- === Transactions
+ 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.
  
- To get a full understanding of this section, it would be good to start by reading the <<transactions,Transactions>>
- section of this documentation, which discusses transactions in the general context of TinkerPop itself. This section
- builds on that content by demonstrating the transactional syntax for Javascript.
+ In this interface, define the methods that the DSL will be composed of:
  
- [source,javascript]
+ [source,java]
  ----
- const g = traversal().withRemote(new DriverRemoteConnection('ws://localhost:8182/gremlin'));
- const tx = g.tx(); // create a Transaction
+ @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);
+     }
  
- // spawn a new GraphTraversalSource binding all traversals established from it to tx
- const gtx = tx.begin();
+     public default <E2 extends Number> GraphTraversal<S, E2> youngestFriendsAge() {
+         return out("knows").hasLabel("person").values("age").min();
+     }
  
- // execute traversals using gtx occur within the scope of the transaction held by tx. the
- // tx is closed after calls to commit or rollback and cannot be re-used. simply spawn a
- // new Transaction from g.tx() to create a new one as needed. the g context remains
- // accessible through all this as a sessionless connection.
- Promise.all([
-   gtx.addV("person").property("name", "jorge").iterate(),
-   gtx.addV("person").property("name", "josh").iterate()
- ]).then(() => {
-   return tx.commit();
- }).catch(() => {
-   return tx.rollback();
- });
+     public default GraphTraversal<S, Long> createdAtLeast(int number) {
+         return outE("created").count().is(P.gte(number));
+     }
+ }
  ----
  
- [[gremlin-javascript-lambda]]
- === The Lambda Solution
+ IMPORTANT: Follow the TinkerPop convention of using `<S,E>` in naming generics as those conventions are taken into
+ account when generating the anonymous traversal class. The processor attempts to infer the appropriate type parameters
+ when generating the anonymous traversal class. If it cannot do it correctly, it is possible to avoid the inference by
+ using the `GremlinDsl.AnonymousMethod` annotation on the DSL method. It allows explicit specification of the types to
+ use.
  
- Supporting link:https://en.wikipedia.org/wiki/Anonymous_function[anonymous functions] across languages is difficult as
- most languages do not support lambda introspection and thus, code analysis. In Gremlin-Javascript, a Gremlin lambda
- should be represented as a zero-arg callable that returns a string representation of the lambda expected for use in the
- traversal. The returned lambda should be written as a Gremlin-Groovy string. When the lambda is represented in
- `Bytecode` its language is encoded such that the remote connection host can infer which translator and ultimate
- execution engine to use.
+ 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,javascript]
+ [source,java]
  ----
- g.V().out().
-   map(() => "it.get().value('name').length()").
-   sum().
-   toList().then(total => console.log(total))
+ org.apache.tinkerpop.gremlin.process.traversal.dsl.GremlinDslProcessor
  ----
  
- 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
- `() => "it.get().value('name')"`, prefer `() => "x -> x.get().value('name')"`.
- 
- WARNING: As explained throughout the documentation, when possible <<a-note-on-lambdas,avoid>> lambdas.
+ The annotation processor will generate several classes for the DSL:
  
- [[gremlin-javascript-scripts]]
- === Submitting Scripts
+ * `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.
+ * `__` - Spawns anonymous `DefaultSocialTraversal` instances.
  
- It is possible to submit parametrized Gremlin scripts to the server as strings, using the `Client` class:
+ Using the DSL then just involves telling the `Graph` to use it:
  
- [source,javascript]
+ [source,java]
  ----
- const gremlin = require('gremlin');
- const client = new gremlin.driver.Client('ws://localhost:8182/gremlin', { traversalSource: 'g' });
- 
- const result1 = await client.submit('g.V(vid)', { vid: 1 });
- const vertex = result1.first();
- 
- const result2 = await client.submit('g.V().hasLabel(label).tail(n)', { label: 'person', n: 3 });
- 
- // ResultSet is an iterable
- for (const vertex of result2) {
-   console.log(vertex.id);
- }
+ SocialTraversalSource social = traversal(SocialTraversalSource.class).withEmbedded(graph);
+ social.V().has("name","marko").knows("josh");
  ----
  
- It is also possible to initialize the `Client` to use <<sessions,sessions>>:
+ 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,javascript]
- ----
- const client = new gremlin.driver.Client('ws://localhost:8182/gremlin', { traversalSource: 'g', 'session': 'unique-string-id' });
+ [source,java]
  ----
+ public class SocialTraversalSourceDsl extends GraphTraversalSource {
  
- With this configuration, the state of variables within scripts are preserved between requests.
- 
- ==== Per Request Settings
+     public SocialTraversalSourceDsl(Graph graph, TraversalStrategies traversalStrategies) {
+         super(graph, traversalStrategies);
+     }
  
- The `client.submit()` functions accept a `requestOptions` which expects a dictionary. The `requestOptions`
- provide a way to include options that are specific to the request made with the call to `submit()`. A good use-case for
- this feature is to set a per-request override to the `evaluationTimeout` so that it only applies to the current
- request.
+     public SocialTraversalSourceDsl(Graph graph) {
+         super(graph);
+     }
  
- [source,javascript]
- ----
- const result = await client.submit("g.V().repeat(both()).times(100)", null, { evaluationTimeout: 5000 })
- ----
+     public SocialTraversalSourceDsl(RemoteConnection connection) {
+         super(connection);
+     }
  
- The following options are allowed on a per-request basis in this fashion: `batchSize`, `requestId`, `userAgent` and
- `evaluationTimeout` (formerly `scriptEvaluationTimeout` which is also supported but now deprecated).
+     public GraphTraversal<Vertex, Vertex> persons(String... names) {
+         GraphTraversalSource clone = this.clone();
  
- IMPORTANT: The preferred method for setting a per-request timeout for scripts is demonstrated above, but those familiar
- with bytecode may try `g.with(EVALUATION_TIMEOUT, 500)` within a script. Scripts with multiple traversals and multiple
- timeouts will be interpreted as a sum of all timeouts identified in the script for that request.
+         // 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));
  
- ==== Processing results as they are returned from the Gremlin server
+         traversal = traversal.hasLabel("person");
+         if (names.length > 0) traversal = traversal.has("name", P.within(names));
  
- The Gremlin JavaScript driver maintains a WebSocket connection to the Gremlin server and receives messages according to the `batchSize` parameter on the per request settings or the `resultIterationBatchSize` value configured for the Gremlin server. When submitting scripts the default behavior is to wait for the entire result set to be returned from a query before allowing any processing on the result set.
+         return traversal;
+     }
+ }
+ ----
  
- The following examples assume that you have 100 vertices in your graph.
+ 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,javascript]
+ [source,java]
  ----
- const result = await client.submit("g.V()");
- console.log(result.toArray()); // 100 - all the vertices in your graph
+ @GremlinDsl(traversalSource = "com.company.SocialTraversalSourceDsl")
+ public interface SocialTraversalDsl<S, E> extends GraphTraversal.Admin<S, E> {
+     ...
+ }
  ----
  
- When working with larger result sets it may be beneficial for memory management to process each chunk of data as it is returned from the gremlin server. The Gremlin JavaScript driver can return a readable stream instead of waiting for the entire result set to be loaded.
+ It is then possible to use the `persons()` method to start traversals:
  
- [source,javascript]
+ [source,java]
+ ----
+ SocialTraversalSource social = traversal(SocialTraversalSource.class).withEmbedded(graph);
+ social.persons("marko").knows("josh");
  ----
  
- const readable =  client.stream("g.V()", {}, { batchSize: 25 });
- 
- readable.on('data', (data) => {
-   console.log(data.toArray()); // 25 vertices
- })
+ 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.
  
- readable.on('error', (error) => {
-   console.log(error); // errors returned from gremlin server
- })
+ [[gremlin-java-troubleshooting]]
+ === Troubleshooting
  
- readable.on('end', () => {
-   console.log('query complete'); // when the end event is received then all the results have been processed
- })
- ----
+ *Max frame length of 65536 has been exceeded*
  
- If you are using NodeJS >= 10.0, you can asynchronously iterate readable streams:
+ This error occurs when the driver attempts to process a request/response that exceeds the configured maximum size.
+ The most direct way to fix this problem is to increase the `maxContentLength` setting in the driver. Ideally, the
+ `maxContentLength` set for the driver should match the setting defined on the server.
  
+ *TimeoutException*
  
- [source,javascript]
- ----
+ A `TimeoutException` is thrown by the driver when the time limit assigned by the `maxWaitForConnection` is exceeded
+ when trying to borrow a connection from the connection pool for a particular host. There are generally two scenarios
+ where this occurs:
  
- const readable = client.stream("g.V()", {}, { batchSize: 25 });
+ 1. The server has actually reached its maximum capacity or the driver has just learned that the server is unreachable.
+ 2. The client is throttling requests when the pool is exhausted.
  
- try {
-   for await (const result of readable) {
-     console.log('data', result.toArray()); // 25 vertices
-   }
- } catch (err) {
-   console.log(err);
- }
+ The latter of the two can be addressed from the driver side in the following ways:
  
- ----
+ * Increase the `maxWaitForConnection` allowing the client to wait a bit longer for a connection to become available.
+ * Increase the number of requests allowed per connection by increasing the `maxSimultaneousUsagePerConnection` and
+ `maxInProcessPerConnection` settings.
+ * Increase the number of connections available in the connection pool by increasing the `maxConnectionPoolSize`.
  
- [[gremlin-javascript-dsl]]
- === Domain Specific Languages
+ The exception and logs (assuming they are enabled) should contain information about the state of the connection pool
+ along with its connections which can help shed more light on which of these scenarios caused the problem. Some examples
+ of these messages and their meaning are shown below:
  
- Developing Gremlin DSLs in JavaScript largely requires extension of existing core classes with use of standalone
- functions for anonymous traversal spawning. The pattern is demonstrated in the following example:
+ _The server is unavailable_
  
- [source,javascript]
+ [source,text]
+ ----
+ Timed-out (500 MILLISECONDS) waiting for connection on Host{address=localhost/127.0.0.1:45940, hostUri=ws://localhost:45940/gremlin}. Potential Cause: Connection refused: no further information
+ > ConnectionPool (Host{address=localhost/127.0.0.1:45940, hostUri=ws://localhost:45940/gremlin})- no connections in pool
  ----
- class SocialTraversal extends GraphTraversal {
-   constructor(graph, traversalStrategies, bytecode) {
-     super(graph, traversalStrategies, bytecode);
-   }
- 
-   aged(age) {
-     return this.has('person', 'age', age);
-   }
- }
  
- class SocialTraversalSource extends GraphTraversalSource {
-   constructor(graph, traversalStrategies, bytecode) {
-     super(graph, traversalStrategies, bytecode, SocialTraversalSource, SocialTraversal);
-   }
+ _Client is likely issuing more requests than the pool size can handle_
  
-   person(name) {
-     return this.V().has('person', 'name', name);
-   }
- }
+ [source,text]
+ ----
+ Timed-out (150 MILLISECONDS) waiting for connection on Host{address=localhost/127.0.0.1:45940, hostUri=ws://localhost:45940/gremlin}. Potential Cause: Number of active requests exceeds pool size. Consider increasing the value for maxConnectionPoolSize.
+ ConnectionPool (Host{address=localhost/127.0.0.1:45940, hostUri=ws://localhost:45940/gremlin})
+ Connection Pool Status (size=1 max=1 min=1 toCreate=0 bin=0)
+ > Connection{channel=5a859d62 isDead=false borrowed=1 pending=1 markedReplaced=false closing=false created=2022-12-19T21:08:21.569613100Z thread=gremlin-driver-conn-scheduler-1}
+ -- bin --
+ ----
  
- function anonymous() {
-   return new SocialTraversal(null, null, new Bytecode());
- }
+ _Network traffic is slow and the websocket handshake does not complete in time_
  
- function aged(age) {
-   return anonymous().aged(age);
- }
+ [source,text]
+ ----
+ Timed-out (250 MILLISECONDS) waiting for connection on Host{address=localhost/127.0.0.1:45940, hostUri=ws://localhost:45940/gremlin}. Potential Cause: WebSocket handshake not completed in stipulated time=[100]ms
+ ConnectionPool (Host{address=localhost/127.0.0.1:45940, hostUri=ws://localhost:45940/gremlin})
+ Connection Pool Status (size=1 max=5 min=1 toCreate=0 bin=0)
+ > Connection{channel=205fc8d2 isDead=false borrowed=1 pending=1 markedReplaced=false closing=false created=2022-12-19T21:10:04.692921600Z thread=gremlin-driver-conn-scheduler-1}
+ -- bin --
  ----
  
- `SocialTraversal` extends the core `GraphTraversal` class and has a three argument constructor which is immediately
- proxied to the `GraphTraversal` constructor. New DSL steps are then added to this class using available steps to
- construct the underlying traversal to execute as demonstrated in the `aged()` step.
+ anchor:java-application-examples[]
+ anchor:gremlin-archetypes[]
+ [[gremlin-java-examples]]
+ === Application Examples
  
- The `SocialTraversal` is spawned from a `SocialTraversalSource` which is extended from `GraphTraversalSource`. Steps
- added here are meant to be start steps. In the above case, the `person()` start step find a "person" vertex to begin
- the traversal from.
+ The available link:https://maven.apache.org/guides/introduction/introduction-to-archetypes.html[Maven archetypes] are
+ as follows:
  
- Typically, steps that are made available on a `GraphTraversal` (i.e. SocialTraversal in this example) should also be
- made available as spawns for anonymous traversals. The recommendation is that these steps be exposed in the module
- as standalone functions. In the example above, the standalone `aged()` step creates an anonymous traversal through
- an `anonymous()` utility function. The method for creating these standalone functions can be handled in other ways if
- desired.
+ * `gremlin-archetype-dsl` - An example project that demonstrates how to build Domain Specific Languages with Gremlin
+ in Java.
+ * `gremlin-archetype-server` - An example project that demonstrates the basic structure of a
+ <<gremlin-server,Gremlin Server>> project, how to connect with the Gremlin Driver, and how to embed Gremlin Server in
+ a testing framework.
+ * `gremlin-archetype-tinkergraph` - A basic example of how to structure a TinkerPop project with Maven.
  
- To use the DSL, simply initialize the `g` as follows:
+ Use Maven to generate these example projects with a command like:
  
- [source,javascript]
- ----
- const g = traversal(SocialTraversalSource).withRemote(connection);
- g.person('marko').aged(29).values('name').toList().
-   then(names => console.log(names));
- ----
+ [source,shell]
+ $ mvn archetype:generate -DarchetypeGroupId=org.apache.tinkerpop -DarchetypeArtifactId=gremlin-archetype-server \
+       -DarchetypeVersion=x.y.z -DgroupId=com.my -DartifactId=app -Dversion=0.1 -DinteractiveMode=false
  
- [[javascript-differences]]
- [[gremlin-javascript-differences]]
- === Differences
+ This command will generate a new Maven project in a directory called "app" with a `pom.xml` specifying a `groupId` of
+ `com.my`. Please see the `README.asciidoc` in the root of each generated project for information on how to build and
+ execute it.
  
- In situations where Javascript reserved words and global functions overlap with standard Gremlin steps and tokens, those
- bits of conflicting Gremlin get an underscore appended as a suffix:
+ [[gremlin-javascript]]
+ == Gremlin-JavaScript
  
- *Steps* - <<from-step,from_()>>, <<in-step,in_()>>, <<with-step,with_()>>
- *Tokens* - `Direction.from_`
+ image:gremlin-js.png[width=130,float=right] Apache TinkerPop's Gremlin-JavaScript implements Gremlin within the
+ JavaScript language. It targets Node.js runtime and can be used on different operating systems on any Node.js 6 or
+ above. Since the JavaScript naming conventions are very similar to that of Java, it should be very easy to switch
+ between Gremlin-Java and Gremlin-JavaScript.
  
- Gremlin allows for `Map` instances to include `null` keys, but `null` keys in Javascript have some interesting behavior
- as in:
+ [source,bash]
+ npm install gremlin
  
- [source,text]
- ----
- > var a = { null: 'something', 'b': 'else' };
- > JSON.stringify(a)
- '{"null":"something","b":"else"}'
- > JSON.parse(JSON.stringify(a))
- { null: 'something', b: 'else' }
- > a[null]
- 'something'
- > a['null']
- 'something'
- ----
+ [[gremlin-javascript-connecting]]
+ === Connecting
  
- This behavior needs to be considered when using Gremlin to return such results. A typical situation where this might
- happen is with `group()` or `groupCount()` as in:
+ 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,javascript]
  ----
@@@ -1193,267 -1271,303 +1279,308 @@@ The following options are allowed on a 
  There are a number of classes, functions and tokens that are typically used with Gremlin. The following imports
  provide most of the typical functionality required to use Gremlin:
  
- [source,csharp]
+ [source,javascript]
  ----
- include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=commonImports]
+ const gremlin = require('gremlin');
+ const traversal = gremlin.process.AnonymousTraversalSource.traversal;
+ const __ = gremlin.process.statics;
+ const DriverRemoteConnection = gremlin.driver.DriverRemoteConnection;
+ const column = gremlin.process.column
+ const direction = gremlin.process.direction
++Direction: {
++  BOTH: traversalModule.direction.both,
++  IN: traversalModule.direction.in,
++  OUT: traversalModule.direction.out,
++  from_: traversalModule.direction.in,
++  to: traversalModule.direction.out,
++}
+ const p = gremlin.process.P
+ const textp = gremlin.process.TextP
+ const pick = gremlin.process.pick
+ const pop = gremlin.process.pop
+ const order = gremlin.process.order
+ const scope = gremlin.process.scope
+ const t = gremlin.process.t
  ----
  
- [[gremlin-dotnet-configuration]]
- === Configuration
- 
- The connection properties for the Gremlin.Net driver can be passed to the `GremlinServer` instance as keyword arguments:
- 
- [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_
- |=========================================================
+ By defining these imports it becomes possible to write Gremlin in the more shorthand, canonical style that is
+ demonstrated in most examples found here in the documentation:
  
- ==== Connection Pool
+ [source,javascript]
+ ----
+ const { P: { gt } } = gremlin.process;
+ const { order: { desc } } = gremlin.process;
+ g.V().hasLabel('person').has('age',gt(30)).order().by('age',desc).toList()
+ ----
  
- It is also possible to configure the `ConnectionPool` of the Gremlin.Net driver.
- These configuration options can be set as properties
- on the `ConnectionPoolSettings` instance that can be passed to the `GremlinClient`:
+ [[gremlin-javascript-configuration]]
+ === Configuration
+ The following table describes the various configuration options for the Gremlin-Javascript Driver. They
+ can be passed in the constructor of a new `Client` or `DriverRemoteConnection` :
  
- [width="100%",cols="3,10,^2",options="header"]
+ [width="100%",cols="3,3,10,^2",options="header"]
  |=========================================================
- |Key |Description |Default
- |PoolSize |The size of the connection pool. |4
- |MaxInProcessPerConnection |The maximum number of in-flight requests that can occur on a connection. |32
- |ReconnectionAttempts |The number of attempts to get an open connection from the pool to submit a request. |4
- |ReconnectionBaseDelay |The base delay used for the exponential backoff for the reconnection attempts. |1 s
- |EnableUserAgentOnConnect |Enables sending a user agent to the server during connection requests.
- More details can be found in provider docs
- link:https://tinkerpop.apache.org/docs/x.y.z/dev/provider/#_graph_driver_provider_requirements[here].|true
+ |Key |Type |Description |Default
+ |url |String |The resource uri. |None
+ |options |Object |The connection options. |{}
+ |options.ca |Array |Trusted certificates. |undefined
+ |options.cert |String/Array/Buffer |The certificate key. |undefined
+ |options.mimeType |String |The mime type to use. |'application/vnd.gremlin-v3.0+json'
+ |options.pfx |String/Buffer |The private key, certificate, and CA certs. |undefined
+ |options.reader |GraphSONReader/GraphBinaryReader |The reader to use. |select reader according to mimeType
+ |options.writer |GraphSONWriter |The writer to use. |select writer according to mimeType
+ |options.rejectUnauthorized |Boolean |Determines whether to verify or not the server certificate. |undefined
+ |options.traversalSource |String |The traversal source. |'g'
+ |options.authenticator |Authenticator |The authentication handler to use. |undefined
+ |options.processor |String |The name of the opProcessor to use, leave it undefined or set 'session' when session mode. |undefined
+ |options.session |String |The sessionId of Client in session mode. undefined means session-less Client. |undefined
+ |options.enableUserAgentOnConnect |Boolean |Determines if a user agent will be sent during connection handshake. |true
+ |options.headers |Object |An associative array containing the additional header key/values for the initial request. |undefined
+ |options.pingEnabled |Boolean |Setup ping interval. |true
+ |options.pingInterval |Number |Ping request interval in ms if ping enabled. |60000
+ |options.pongTimeout |Number |Timeout of pong response in ms after sending a ping. |30000
  |=========================================================
  
- A `NoConnectionAvailableException` is thrown if all connections have reached the `MaxInProcessPerConnection` limit
- when a new request comes in.
- A `ServerUnavailableException` is thrown if no connection is available to the server to submit a request after
- `ReconnectionAttempts` retries.
- 
- ==== WebSocket Configuration
- 
- The WebSocket connections can also be configured, directly as parameters of the `GremlinClient` constructor. It takes
- an optional delegate `webSocketConfiguration` that will be invoked for each connection. This makes it possible to
- configure more advanced options like the `KeepAliveInterval` or client certificates.
+ [[gremlin-javascript-transactions]]
+ === Transactions
  
- Starting with .NET 6, it is also possible to use compression for WebSockets. This is enabled by default starting with
- TinkerPop 3.5.3 (again, only on .NET 6 or higher). Note that compression might make an application susceptible to
- attacks like CRIME/BREACH. Compression should therefore be turned off if the application sends sensitive data to the
- server as well as data that could potentially be controlled by an untrusted user. Compression can be disabled via the
- `disableCompression` parameter.
+ To get a full understanding of this section, it would be good to start by reading the <<transactions,Transactions>>
+ section of this documentation, which discusses transactions in the general context of TinkerPop itself. This section
+ builds on that content by demonstrating the transactional syntax for Javascript.
  
- [[gremlin-dotnet-logging]]
- === Logging
+ [source,javascript]
+ ----
+ const g = traversal().withRemote(new DriverRemoteConnection('ws://localhost:8182/gremlin'));
+ const tx = g.tx(); // create a Transaction
  
- It is possible to enable logging for the Gremlin.Net driver by providing an `ILoggerFactory` (from the
- `Microsoft.Extensions.Logging.Abstractions` package) to the `GremlinClient` constructor:
+ // spawn a new GraphTraversalSource binding all traversals established from it to tx
+ const gtx = tx.begin();
  
- [source,csharp]
- ----
- include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=logging]
+ // execute traversals using gtx occur within the scope of the transaction held by tx. the
+ // tx is closed after calls to commit or rollback and cannot be re-used. simply spawn a
+ // new Transaction from g.tx() to create a new one as needed. the g context remains
+ // accessible through all this as a sessionless connection.
+ Promise.all([
+   gtx.addV("person").property("name", "jorge").iterate(),
+   gtx.addV("person").property("name", "josh").iterate()
+ ]).then(() => {
+   return tx.commit();
+ }).catch(() => {
+   return tx.rollback();
+ });
  ----
  
- [[gremlin-dotnet-serialization]]
- === Serialization
- 
- The Gremlin.Net driver uses by default GraphBinary but it is also possible to use another serialization format by passing a message serializer when creating the `GremlinClient`.
+ [[gremlin-javascript-lambda]]
+ === The Lambda Solution
  
- GraphSON 3.0 can be configured like this:
+ Supporting link:https://en.wikipedia.org/wiki/Anonymous_function[anonymous functions] across languages is difficult as
+ most languages do not support lambda introspection and thus, code analysis. In Gremlin-Javascript, a Gremlin lambda
+ should be represented as a zero-arg callable that returns a string representation of the lambda expected for use in the
+ traversal. The returned lambda should be written as a Gremlin-Groovy string. When the lambda is represented in
+ `Bytecode` its language is encoded such that the remote connection host can infer which translator and ultimate
+ execution engine to use.
  
- [source,csharp]
+ [source,javascript]
  ----
- include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=serializationGraphSon3]
+ g.V().out().
+   map(() => "it.get().value('name').length()").
+   sum().
+   toList().then(total => console.log(total))
  ----
  
- and GraphSON 2.0 like this:
+ 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
+ `() => "it.get().value('name')"`, prefer `() => "x -> x.get().value('name')"`.
  
- [source,csharp]
- ----
- include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=serializationGraphSon]
- ----
+ WARNING: As explained throughout the documentation, when possible <<a-note-on-lambdas,avoid>> lambdas.
  
- [[gremlin-dotnet-strategies]]
- === Traversal Strategies
+ [[gremlin-javascript-scripts]]
+ === Submitting Scripts
  
- In order to add and remove traversal strategies from a traversal source, Gremlin.Net has an `AbstractTraversalStrategy`
- class along with a collection of subclasses that mirror the standard Gremlin-Java strategies.
+ It is possible to submit parametrized Gremlin scripts to the server as strings, using the `Client` class:
  
- [source,csharp]
- ----
- include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=traversalStrategies]
+ [source,javascript]
  ----
+ const gremlin = require('gremlin');
+ const client = new gremlin.driver.Client('ws://localhost:8182/gremlin', { traversalSource: 'g' });
  
- NOTE: Many of the TraversalStrategy classes in Gremlin.Net are proxies to the respective strategy on Apache TinkerPop’s
- JVM-based Gremlin traversal machine. As such, their `Apply(ITraversal)` method does nothing. However, the strategy is
- encoded in the Gremlin.Net bytecode and transmitted to the Gremlin traversal machine for re-construction machine-side.
+ const result1 = await client.submit('g.V(vid)', { vid: 1 });
+ const vertex = result1.first();
  
- [[gremlin-dotnet-transactions]]
- === Transactions
+ const result2 = await client.submit('g.V().hasLabel(label).tail(n)', { label: 'person', n: 3 });
  
- To get a full understanding of this section, it would be good to start by reading the <<transactions,Transactions>>
- section of this documentation, which discusses transactions in the general context of TinkerPop itself. This section
- builds on that content by demonstrating the transactional syntax for C#.
+ // ResultSet is an iterable
+ for (const vertex of result2) {
+   console.log(vertex.id);
+ }
+ ----
  
- [source,csharp]
+ It is also possible to initialize the `Client` to use <<sessions,sessions>>:
+ 
+ [source,javascript]
  ----
- include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=transactions]
+ const client = new gremlin.driver.Client('ws://localhost:8182/gremlin', { traversalSource: 'g', 'session': 'unique-string-id' });
  ----
  
- [[gremlin-dotnet-lambda]]
- === The Lambda Solution
+ With this configuration, the state of variables within scripts are preserved between requests.
  
- Supporting link:https://en.wikipedia.org/wiki/Anonymous_function[anonymous functions] across languages is difficult as
- most languages do not support lambda introspection and thus, code analysis. While Gremlin.Net doesn't support C# lambdas, it
- is still able to represent lambdas in other languages. When the lambda is represented in `Bytecode` its language is encoded
- such that the remote connection host can infer which translator and ultimate execution engine to use.
+ ==== Per Request Settings
  
- [source,csharp]
+ The `client.submit()` functions accept a `requestOptions` which expects a dictionary. The `requestOptions`
+ provide a way to include options that are specific to the request made with the call to `submit()`. A good use-case for
+ this feature is to set a per-request override to the `evaluationTimeout` so that it only applies to the current
+ request.
+ 
+ [source,javascript]
  ----
- g.V().Out().Map<int>(Lambda.Groovy("it.get().value('name').length()")).Sum<int>().ToList();      <1>
- g.V().Out().Map<int>(Lambda.Python("lambda x: len(x.get().value('name'))")).Sum<int>().ToList(); <2>
+ const result = await client.submit("g.V().repeat(both()).times(100)", null, { evaluationTimeout: 5000 })
  ----
  
- <1> `Lambda.Groovy()` can be used to create a Groovy lambda.
- <2> `Lambda.Python()` can be used to create a Python lambda.
+ The following options are allowed on a per-request basis in this fashion: `batchSize`, `requestId`, `userAgent` and
+ `evaluationTimeout` (formerly `scriptEvaluationTimeout` which is also supported but now deprecated).
  
- 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.
+ IMPORTANT: The preferred method for setting a per-request timeout for scripts is demonstrated above, but those familiar
+ with bytecode may try `g.with(EVALUATION_TIMEOUT, 500)` within a script. Scripts with multiple traversals and multiple
+ timeouts will be interpreted as a sum of all timeouts identified in the script for that request.
  
- 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'))`.
 -
+ ==== Processing results as they are returned from the Gremlin server
  
- [[gremlin-dotnet-scripts]]
- === Submitting Scripts
 -
+ The Gremlin JavaScript driver maintains a WebSocket connection to the Gremlin server and receives messages according to the `batchSize` parameter on the per request settings or the `resultIterationBatchSize` value configured for the Gremlin server. When submitting scripts the default behavior is to wait for the entire result set to be returned from a query before allowing any processing on the result set.
  
- Gremlin scripts are sent to the server from a `IGremlinClient` instance.  A `IGremlinClient` is created as follows:
+ The following examples assume that you have 100 vertices in your graph.
  
- [source,csharp]
+ [source,javascript]
  ----
- include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=submittingScripts]
+ const result = await client.submit("g.V()");
+ console.log(result.toArray()); // 100 - all the vertices in your graph
  ----
  
- If the remote system has authentication and SSL enabled, then the `GremlinServer` object can be configured as follows:
+ When working with larger result sets it may be beneficial for memory management to process each chunk of data as it is returned from the gremlin server. The Gremlin JavaScript driver can return a readable stream instead of waiting for the entire result set to be loaded.
  
- [source,csharp]
- ----
- include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=submittingScriptsWithAuthentication]
+ [source,javascript]
  ----
  
- It is also possible to initialize the `Client` to use <<sessions,sessions>>:
+ const readable =  client.stream("g.V()", {}, { batchSize: 25 });
  
- [source,csharp]
- ----
- var gremlinServer = new GremlinServer("localhost", 8182);
- var client = new GremlinClient(gremlinServer, sessionId: Guid.NewGuid().ToString()))
+ readable.on('data', (data) => {
+   console.log(data.toArray()); // 25 vertices
+ })
+ 
+ readable.on('error', (error) => {
+   console.log(error); // errors returned from gremlin server
+ })
+ 
+ readable.on('end', () => {
+   console.log('query complete'); // when the end event is received then all the results have been processed
+ })
  ----
  
- ==== Per Request Settings
+ If you are using NodeJS >= 10.0, you can asynchronously iterate readable streams:
  
- The `GremlinClient.Submit()` functions accept an option to build a raw `RequestMessage`. A good use-case for this
- feature is to set a per-request override to the `evaluationTimeout` so that it only applies to the current request.
  
- [source,csharp]
- ----
- include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=submittingScriptsWithTimeout]
+ [source,javascript]
  ----
  
- The following options are allowed on a per-request basis in this fashion: `batchSize`, `requestId`, `userAgent` and
- `evaluationTimeout` (formerly `scriptEvaluationTimeout` which is also supported but now deprecated). These options are
- available as constants on the `Gremlin.Net.Driver.Tokens` class.
+ const readable = client.stream("g.V()", {}, { batchSize: 25 });
  
- IMPORTANT: The preferred method for setting a per-request timeout for scripts is demonstrated above, but those familiar
- with bytecode may try `g.with(EVALUATION_TIMEOUT, 500)` within a script. Scripts with multiple traversals and multiple
- timeouts will be interpreted as a sum of all timeouts identified in the script for that request.
+ try {
+   for await (const result of readable) {
+     console.log('data', result.toArray()); // 25 vertices
+   }
+ } catch (err) {
+   console.log(err);
+ }
  
- anchor:gremlin-net-dsl[]
- [[gremlin-dotnet-dsl]]
+ ----
+ 
 -
+ [[gremlin-javascript-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.
+ Developing Gremlin DSLs in JavaScript largely requires extension of existing core classes with use of standalone
+ functions for anonymous traversal spawning. The pattern is demonstrated in the following example:
  
- [source,csharp]
- ----
- include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsDsl.cs[tags=dsl]
+ [source,javascript]
  ----
+ class SocialTraversal extends GraphTraversal {
+   constructor(graph, traversalStrategies, bytecode) {
+     super(graph, traversalStrategies, bytecode);
+   }
  
- 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:
+   aged(age) {
+     return this.has('person', 'age', age);
+   }
+ }
  
- [source,csharp]
- ----
- include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsDslTests.cs[tags=dslUsing]
- ----
+ class SocialTraversalSource extends GraphTraversalSource {
+   constructor(graph, traversalStrategies, bytecode) {
+     super(graph, traversalStrategies, bytecode, SocialTraversalSource, SocialTraversal);
+   }
  
- and then it can be called from the application as follows:
+   person(name) {
+     return this.V().has('person', 'name', name);
+   }
+ }
  
- [source,csharp]
- ----
- include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsDslTests.cs[tags=dslExamples]
+ function anonymous() {
+   return new SocialTraversal(null, null, new Bytecode());
+ }
+ 
+ function aged(age) {
+   return anonymous().aged(age);
+ }
  ----
  
- anchor:gremlin-net-differences[]
- [[gremlin-dotnet-differences]]
- === Differences
+ `SocialTraversal` extends the core `GraphTraversal` class and has a three argument constructor which is immediately
+ proxied to the `GraphTraversal` constructor. New DSL steps are then added to this class using available steps to
+ construct the underlying traversal to execute as demonstrated in the `aged()` step.
  
- The biggest difference between Gremlin in .NET and the canonical version in Java is the casing of steps. Canonical
- Gremlin utilizes `camelCase` as is typical in Java for function names, but C# utilizes `PascalCase` as it is more
- typical in that language. Therefore, when viewing a typical Gremlin example written in Gremlin Console, the conversion
- to C# usually just requires capitalization of the first letter in the step name, thus the following example in Groovy:
+ The `SocialTraversal` is spawned from a `SocialTraversalSource` which is extended from `GraphTraversalSource`. Steps
+ added here are meant to be start steps. In the above case, the `person()` start step find a "person" vertex to begin
+ the traversal from.
  
- [source,groovy]
- ----
- g.V().has('person','name','marko').
-   out('knows').
-   elementMap().toList()
- ----
+ Typically, steps that are made available on a `GraphTraversal` (i.e. SocialTraversal in this example) should also be
+ made available as spawns for anonymous traversals. The recommendation is that these steps be exposed in the module
+ as standalone functions. In the example above, the standalone `aged()` step creates an anonymous traversal through
+ an `anonymous()` utility function. The method for creating these standalone functions can be handled in other ways if
+ desired.
  
- would become the following in C#:
+ To use the DSL, simply initialize the `g` as follows:
  
- [source,csharp]
+ [source,javascript]
  ----
- g.V().Has("Person","name","marko").
-   Out("knows").
-   ElementMap().ToList();
+ const g = traversal(SocialTraversalSource).withRemote(connection);
+ g.person('marko').aged(29).values('name').toList().
+   then(names => console.log(names));
  ----
  
- In addition to the uppercase change, also note the conversion of the single quotes to double quotes as is expected for
- declaring string values in C# and the addition of the semi-colon at the end of the line. In short, don't forget to
- apply the common syntax expectations for C# when trying to convert an example of Gremlin from a different language.
+ [[javascript-differences]]
+ [[gremlin-javascript-differences]]
+ === Differences
  
- Another common conversion issues lies in having to explicitly define generics, which can make canonical Gremlin appear
- much more complex in C# where type erasure is not a feature of the language. For example, the following example in
- Groovy:
+ In situations where Javascript reserved words and global functions overlap with standard Gremlin steps and tokens, those
+ bits of conflicting Gremlin get an underscore appended as a suffix:
  
- [source,groovy]
- ----
- g.V().repeat(__.out()).times(2).values('name')
- ----
+ *Steps* - <<from-step,from_()>>, <<in-step,in_()>>, <<with-step,with_()>>
++*Tokens* - `Direction.from_`
  
- must be written as:
+ Gremlin allows for `Map` instances to include `null` keys, but `null` keys in Javascript have some interesting behavior
+ as in:
  
- [source,csharp]
+ [source,text]
  ----
- g.V().Repeat(__.Out()).Times(2).Values<string>("name");
+ > var a = { null: 'something', 'b': 'else' };
+ > JSON.stringify(a)
+ '{"null":"something","b":"else"}'
+ > JSON.parse(JSON.stringify(a))
+ { null: 'something', b: 'else' }
+ > a[null]
+ 'something'
+ > a['null']
+ 'something'
  ----
  
- Gremlin allows for `Map` instances to include `null` keys, but `null` keys in C# `Dictionary` instances are not allowed.
- It is therefore necessary to rewrite a traversal such as:
+ This behavior needs to be considered when using Gremlin to return such results. A typical situation where this might
+ happen is with `group()` or `groupCount()` as in:
  
  [source,javascript]
  ----
@@@ -1470,9 -1585,8 +1598,7 @@@ g.V().hasLabel('person').groupCount().b
  
  Either of the above two options accomplishes the desired goal as both prevent `groupCount()` from having to process
  the possibility of `null`.
--
- anchor:gremlin-net-limitations[]
- [[gremlin-dotnet-limitations]]
+ [[gremlin-javascript-limitations]]
  === Limitations
  
  * The `subgraph()`-step is not supported by any variant that is not running on the Java Virtual Machine as there is
@@@ -1620,345 -1676,277 +1688,277 @@@ More details can be found in provider d
  link:https://tinkerpop.apache.org/docs/x.y.z/dev/provider/#_graph_driver_provider_requirements[here].|true
  |=========================================================
  
- [[gremlin-go-strategies]]
- === Traversal Strategies
+ A `NoConnectionAvailableException` is thrown if all connections have reached the `MaxInProcessPerConnection` limit
+ when a new request comes in.
+ A `ServerUnavailableException` is thrown if no connection is available to the server to submit a request after
+ `ReconnectionAttempts` retries.
  
- In order to add and remove <<traversalstrategy,traversal strategies>> from a traversal source, Gremlin-Go has a
- `TraversalStrategy` interface along with a collection of functions that mirror the standard Gremlin-Java strategies.
+ ==== WebSocket Configuration
  
- [source,go]
- ----
- promise := g.WithStrategies(gremlingo.ReadOnlyStrategy()).AddV("person").Property("name", "foo").Iterate()
- ----
+ The WebSocket connections can also be configured, directly as parameters of the `GremlinClient` constructor. It takes
+ an optional delegate `webSocketConfiguration` that will be invoked for each connection. This makes it possible to
+ configure more advanced options like the `KeepAliveInterval` or client certificates.
  
- NOTE: Many of the `TraversalStrategy` classes in Gremlin-Go are proxies to the respective strategy on
- Apache TinkerPop's JVM-based Gremlin traversal machine. As such, their `apply(Traversal)` method does nothing. However,
- the strategy is encoded in the Gremlin-Go bytecode and transmitted to the Gremlin traversal machine for
- re-construction machine-side.
+ Starting with .NET 6, it is also possible to use compression for WebSockets. This is enabled by default starting with
+ TinkerPop 3.5.3 (again, only on .NET 6 or higher). Note that compression might make an application susceptible to
+ attacks like CRIME/BREACH. Compression should therefore be turned off if the application sends sensitive data to the
+ server as well as data that could potentially be controlled by an untrusted user. Compression can be disabled via the
+ `disableCompression` parameter.
  
- [[gremlin-go-transactions]]
- === Transactions
+ [[gremlin-dotnet-logging]]
+ === Logging
  
- To get a full understanding of this section, it would be good to start by reading the <<transactions,Transactions>>
- section of this documentation, which discusses transactions in the general context of TinkerPop itself. This section
- builds on that content by demonstrating the transactional syntax for Go.
+ It is possible to enable logging for the Gremlin.Net driver by providing an `ILoggerFactory` (from the
+ `Microsoft.Extensions.Logging.Abstractions` package) to the `GremlinClient` constructor:
  
- [source,go]
+ [source,csharp]
  ----
- remote, err := NewDriverRemoteConnection("ws://localhost:8182/gremlin")
- g := gremlingo.Traversal_().WithRemote(remote)
- 
- // Create a Transaction.
- tx := g.Tx()
- 
- // Spawn a new GraphTraversalSource, binding all traversals established from it to tx.
- gtx, _ := tx.Begin()
- 
- // Execute a traversal within the transaction.
- promise := g.AddV("person").Property("name", "Lyndon").Iterate()
- err := <-promise
- 
- if err != nil {
-   // Rollback the transaction if an error occurs.
-   tx.rollback()
- } else {
-   // Commit the transaction. The transaction can no longer be used and cannot be re-used.
-   // A new transaction can be spawned through g.Tx().
-   tx.Commit()
- }
+ include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=logging]
  ----
  
- [[gremlin-go-lambda]]
- === The Lambda Solution
- 
- Supporting link:https://en.wikipedia.org/wiki/Anonymous_function[anonymous functions] across languages is difficult as
- most languages do not support lambda introspection and thus, code analysis. In Gremlin-Go, a Gremlin lambda should
- be represented as a zero-arg callable that returns a string representation of the lambda expected for use in the
- traversal. The lambda should be written as a `Gremlin-Groovy` string. When the lambda is represented in `Bytecode` its
- language is encoded such that the remote connection host can infer which translator and ultimate execution engine to
- use.
- 
- [source,go]
- ----
- r, err := g.V().Out().Map(&gremlingo.Lambda{Script: "it.get().value('name').length()", Language: ""}).Sum().ToList()
- ----
+ [[gremlin-dotnet-serialization]]
+ === Serialization
  
- 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
- `Script: "it.get().value('name')", Language: "gremlin-groovy"`, prefer `Script: "x -> x.get().value('name')", Language: "gremlin-groovy"`.
 -The Gremlin.Net driver uses by default GraphSON 3.0 but it is also possible to use another serialization format by passing a message serializer when creating the `GremlinClient`.
++The Gremlin.Net driver uses by default GraphBinary but it is also possible to use another serialization format by passing a message serializer when creating the `GremlinClient`.
  
- 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.
 -GraphBinary can be configured like this:
++GraphSON 3.0 can be configured like this:
  
- [source,go]
+ [source,csharp]
  ----
- r, err := g.V((&gremlingo.Bindings{}).Of("x", 1)).Out("created").Map(&gremlingo.Lambda{Script: "it.get().value('name').length()", Language: ""}).Sum().ToList()
- // 3
- r, err := g.V((&gremlingo.Bindings{}).Of("x", 4)).Out("created").Map(&gremlingo.Lambda{Script: "it.get().value('name').length()", Language: ""}).Sum().ToList()
- // 9
 -include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=serializationBinary]
++include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=serializationGraphSon3]
  ----
  
- WARNING: As explained throughout the documentation, when possible <<a-note-on-lambdas,avoid>> lambdas.
- 
- [[gremlin-go-scripts]]
- === Submitting Scripts
- 
- The `Client` class implementation/interface is based on the Java Driver, with some restrictions. Most notably,
- Gremlin-go does not yet implement the `Cluster` class. Instead, `Client` is instantiated directly.
- Usage is as follows:
+ and GraphSON 2.0 like this:
  
- [source,go]
+ [source,csharp]
  ----
- import "github.com/apache/tinkerpop/gremlin-go/v3/driver" <1>
- client, err := gremlingo.NewClient("ws://localhost:8182/gremlin") <2>
+ include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=serializationGraphSon]
  ----
  
- <1> Import the Gremlin-Go 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.
+ [[gremlin-dotnet-strategies]]
+ === Traversal Strategies
  
- Once a `Client` instance is ready, it is possible to issue some Gremlin:
+ In order to add and remove traversal strategies from a traversal source, Gremlin.Net has an `AbstractTraversalStrategy`
+ class along with a collection of subclasses that mirror the standard Gremlin-Java strategies.
  
- [source,go]
+ [source,csharp]
  ----
- resultSet, err := client.Submit("g.V().count()") <1>
- result, err := resultSet.All() <2>
- fmt.Println(result[0].GetString()) <3>
+ include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=traversalStrategies]
  ----
  
- <1> Submit a script that simply returns a Count of vertexes.
- <2> Get results from resultSet. Block until the the script is evaluated and results are sent back by the server.
- <3> Use the result.
+ NOTE: Many of the TraversalStrategy classes in Gremlin.Net are proxies to the respective strategy on Apache TinkerPop’s
+ JVM-based Gremlin traversal machine. As such, their `Apply(ITraversal)` method does nothing. However, the strategy is
+ encoded in the Gremlin.Net bytecode and transmitted to the Gremlin traversal machine for re-construction machine-side.
  
- ==== Per Request Settings
+ [[gremlin-dotnet-transactions]]
+ === Transactions
  
- The `client.Submit()` functions accept a `bindings` which expects a map. The `bindings` provide a way to include options
- that are specific to the request made with the call to `Submit()`. A good use-case for this feature is to set a per-request
- override to the `evaluationTimeout` so that it only applies to the current request.
+ To get a full understanding of this section, it would be good to start by reading the <<transactions,Transactions>>
+ section of this documentation, which discusses transactions in the general context of TinkerPop itself. This section
+ builds on that content by demonstrating the transactional syntax for C#.
  
- [source,go]
+ [source,csharp]
  ----
- resultSet, err := client.Submit("g.V().repeat(both()).times(100)", map[string]interface{}{"evaluationTimeout": 5000})
+ include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=transactions]
  ----
  
- The following options are allowed on a per-request basis in this fashion: `batchSize`, `requestId`, `userAgent` and
- `evaluationTimeout`.
+ [[gremlin-dotnet-lambda]]
+ === The Lambda Solution
  
- IMPORTANT: The preferred method for setting a per-request timeout for scripts is demonstrated above, but those familiar
- with bytecode may try `g.with("evaluationTimeout", 500)` within a script. Scripts with multiple traversals and multiple
- timeouts will be interpreted as a sum of all timeouts identified in the script for that request.
+ Supporting link:https://en.wikipedia.org/wiki/Anonymous_function[anonymous functions] across languages is difficult as
+ most languages do not support lambda introspection and thus, code analysis. While Gremlin.Net doesn't support C# lambdas, it
+ is still able to represent lambdas in other languages. When the lambda is represented in `Bytecode` its language is encoded
+ such that the remote connection host can infer which translator and ultimate execution engine to use.
  
- [source,go]
+ [source,csharp]
  ----
- resultSet, err := client.Submit("g.with('evaluationTimeout', 500).addV().iterate();"+
-   "g.addV().iterate();"+
-   "g.with('evaluationTimeout', 500).addV();", map[string]interface{}{"evaluationTimeout": 500})
- results, err := resultSet.All()
+ g.V().Out().Map<int>(Lambda.Groovy("it.get().value('name').length()")).Sum<int>().ToList();      <1>
+ g.V().Out().Map<int>(Lambda.Python("lambda x: len(x.get().value('name'))")).Sum<int>().ToList(); <2>
  ----
  
- In the above example, defines a timeout of 500 milliseconds, but the script has three traversals with
- two internal settings for the timeout using `with()`. The request timeout used by the server will therefore be 1000
- milliseconds (overriding the 500 which itself was an override for whatever configuration was on the server).
- 
- [[gremlin-go-dsl]]
- === Domain Specific Languages
 -<1> `Lambda.Groovy()` can be used to create a Groovy lambda. 
++<1> `Lambda.Groovy()` can be used to create a Groovy lambda.
+ <2> `Lambda.Python()` can be used to create a Python lambda.
  
- Writing a Gremlin <<dsl,Domain Specific Language>> (DSL) in Go requires embedding of several structs and interfaces:
+ 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.
  
- * `GraphTraversal` - which exposes the various steps used in traversal writing
- * `GraphTraversalSource` - which spawns `GraphTraversal` instances
- * `AnonymousTraversal` - which spawns anonymous traversals from steps
+ 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'))`.
  
- The Social DSL based on the link:https://tinkerpop.apache.org/docs/x.y.z/images/tinkerpop-modern.png["modern" toy graph]
- might look like this:
+ [[gremlin-dotnet-scripts]]
+ === Submitting Scripts
  
- [source,go]
- ----
- // Optional syntactic sugar.
- var __ = gremlingo.T__
- var P = gremlingo.P
- var gt = gremlingo.P.Gt
- // Optional alias for import convenience.
- type GraphTraversal = gremlingo.GraphTraversal
- type GraphTraversalSource = gremlingo.GraphTraversalSource
- type AnonymousTraversal = gremlingo.AnonymousTraversal
+ Gremlin scripts are sent to the server from a `IGremlinClient` instance.  A `IGremlinClient` is created as follows:
  
- // Embed Graph traversal inside custom traversal struct to add custom traversal functions.
- // In go, capitalizing the first letter exports (makes public) the struct/method to outside of package, for this example
- // we have defined everything package private. In actual usage, please see fit to your application.
- type socialTraversal struct {
- 	*GraphTraversal
- }
+ [source,csharp]
+ ----
+ include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=submittingScripts]
+ ----
  
- func (s *socialTraversal) knows(personName string) *socialTraversal {
- 	return &socialTraversal{s.Out("knows").HasLabel("person").Has("name", personName)}
- }
+ If the remote system has authentication and SSL enabled, then the `GremlinServer` object can be configured as follows:
  
- func (s *socialTraversal) youngestFriendsAge() *socialTraversal {
- 	return &socialTraversal{s.Out("knows").HasLabel("person").Values("age").Min()}
- }
+ [source,csharp]
+ ----
+ include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=submittingScriptsWithAuthentication]
+ ----
  
- func (s *socialTraversal) createdAtLeast(number int) *socialTraversal {
- 	return &socialTraversal{s.OutE("created").Count().Is(gt(number))}
- }
+ It is also possible to initialize the `Client` to use <<sessions,sessions>>:
  
- // Add custom social traversal source to spaw custom traversals.
- type socialTraversalSource struct {
- 	*GraphTraversalSource
- }
+ [source,csharp]
+ ----
+ var gremlinServer = new GremlinServer("localhost", 8182);
+ var client = new GremlinClient(gremlinServer, sessionId: Guid.NewGuid().ToString()))
+ ----
  
- // Define the source step function by adding steps to the bytecode.
- func (sts *socialTraversalSource) persons(personNames ...interface{}) *socialTraversal {
- 	t := sts.GetGraphTraversal()
- 	t.Bytecode.AddStep("V")
- 	t.Bytecode.AddStep("hasLabel", "person")
- 	if personNames != nil {
- 		t.Bytecode.AddStep("has", "name", P.Within(personNames...))
- 	}
- 	return &socialTraversal{t}
- }
+ ==== Per Request Settings
  
+ The `GremlinClient.Submit()` functions accept an option to build a raw `RequestMessage`. A good use-case for this
+ feature is to set a per-request override to the `evaluationTimeout` so that it only applies to the current request.
  
- // Create the social anonymous traversal interface to embed and extend the anonymous traversal functions.
- type iSocialAnonymousTraversal interface {
- 	AnonymousTraversal
- 	knows(personName string) *GraphTraversal
- 	youngestFriendsAge() *GraphTraversal
- 	createdAtLeast(number int) *GraphTraversal
- }
+ [source,csharp]
+ ----
+ include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs[tags=submittingScriptsWithTimeout]
+ ----
  
- // Add the struct to implement the iSocialAnonymousTraversal interface.
- type socialAnonymousTraversal struct {
- 	AnonymousTraversal
- 	socialTraversal func() *socialTraversal
- }
+ The following options are allowed on a per-request basis in this fashion: `batchSize`, `requestId`, `userAgent` and
+ `evaluationTimeout` (formerly `scriptEvaluationTimeout` which is also supported but now deprecated). These options are
+ available as constants on the `Gremlin.Net.Driver.Tokens` class.
  
- // Add the variable s__ to call anonymous traversal step functions in place of __.
- var s__ iSocialAnonymousTraversal = &socialAnonymousTraversal{
- 	__,
- 	func() *socialTraversal {
- 		return &socialTraversal{gremlingo.NewGraphTraversal(nil, gremlingo.NewBytecode(nil), nil)}
- 	},
- }
+ IMPORTANT: The preferred method for setting a per-request timeout for scripts is demonstrated above, but those familiar
+ with bytecode may try `g.with(EVALUATION_TIMEOUT, 500)` within a script. Scripts with multiple traversals and multiple
+ timeouts will be interpreted as a sum of all timeouts identified in the script for that request.
  
- // Extended anonymous traversal functions need to return GraphTraversal for serialization purposes
- func (sat *socialAnonymousTraversal) knows(personName string) *GraphTraversal {
- 	return sat.socialTraversal().knows(personName).GraphTraversal
- }
+ anchor:gremlin-net-dsl[]
+ [[gremlin-dotnet-dsl]]
+ === Domain Specific Languages
  
- func (sat *socialAnonymousTraversal) youngestFriendsAge() *GraphTraversal {
- 	return sat.socialTraversal().youngestFriendsAge().GraphTraversal
- }
+ 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.
  
- func (sat *socialAnonymousTraversal) createdAtLeast(number int) *GraphTraversal {
- 	return sat.socialTraversal().createdAtLeast(number).GraphTraversal
- }
+ [source,csharp]
+ ----
+ include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsDsl.cs[tags=dsl]
  ----
  
- Using the DSL requires a social traversal source to be created from the default traversal source:
+ 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,go]
+ [source,csharp]
+ ----
+ include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsDslTests.cs[tags=dslUsing]
  ----
- // Creating the driver remote connection as regular.
- driverRemoteConnection, _ := gremlingo.NewDriverRemoteConnection("ws://localhost:8182/gremlin",
- 	func(settings *gremlingo.DriverRemoteConnectionSettings) {
- 		settings.TraversalSource = "gmodern"
- 	})
- defer driverRemoteConnection.Close()
  
- // Create social traversal source from graph traversal source.
- social := &socialTraversalSource{gremlingo.Traversal_().WithRemote(driverRemoteConnection)}
+ and then it can be called from the application as follows:
  
- // We can now use the social traversal source as well as traversal steps
- resBool, _ := social.persons("marko", "stephen").knows("josh").HasNext()
- fmt.Println(resBool)
+ [source,csharp]
+ ----
+ include::../../../gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsDslTests.cs[tags=dslExamples]
+ ----
  
- // Using the createdAtLeast step.
- resCreated, _ := social.persons().createdAtLeast(1).Next()
- fmt.Println(resCreated.GetString())
+ anchor:gremlin-net-differences[]
+ [[gremlin-dotnet-differences]]
+ === Differences
  
- // Using the social anonymous traversal.
- resAnon, _ := social.persons().Filter(s__.createdAtLeast(1)).Count().Next()
- fmt.Println(resAnon.GetString())
+ The biggest difference between Gremlin in .NET and the canonical version in Java is the casing of steps. Canonical
+ Gremlin utilizes `camelCase` as is typical in Java for function names, but C# utilizes `PascalCase` as it is more
+ typical in that language. Therefore, when viewing a typical Gremlin example written in Gremlin Console, the conversion
+ to C# usually just requires capitalization of the first letter in the step name, thus the following example in Groovy:
  
- // Note that error handling has been omitted with _ from the above examples.
+ [source,groovy]
+ ----
+ g.V().has('person','name','marko').
+   out('knows').
+   elementMap().toList()
  ----
  
- [[gremlin-go-differences]]
- === Differences
+ would become the following in C#:
  
- In situations where Go reserved words and global functions overlap with standard Gremlin steps and tokens, those
- bits of conflicting Gremlin get an underscore appended as a suffix. In addition, all function names start with a
- capital letter in order to be public:
+ [source,csharp]
+ ----
+ g.V().Has("Person","name","marko").
+   Out("knows").
+   ElementMap().ToList();
+ ----
  
- *Steps* - <<and-step,And()>>, <<as-step,As()>>, <<filter-step,Filter()>>, <<from-step,From()>>, <<id-step,Id()>>,
- <<is-step,Is()>>, <<in-step,In()>>, <<max-step,Max()>>, <<min-step,Min()>>, <<not-step,Not()>>, <<or-step,Or()>>,
- <<range-step,Range()>>, <<sum-step,Sum()>>, <<with-step,With()>>
+ In addition to the uppercase change, also note the conversion of the single quotes to double quotes as is expected for
+ declaring string values in C# and the addition of the semi-colon at the end of the line. In short, don't forget to
+ apply the common syntax expectations for C# when trying to convert an example of Gremlin from a different language.
  
- *Tokens* - <<a-note-on-scopes,Scope.Global>>, <<a-note-on-scopes,Scope.Local>>
+ Another common conversion issues lies in having to explicitly define generics, which can make canonical Gremlin appear
+ much more complex in C# where type erasure is not a feature of the language. For example, the following example in
+ Groovy:
  
- [[gremlin-go-aliases]]
- === Aliases
- To make the code more readable and close to the Gremlin query language), you can use aliases. These aliases can be named with capital letters to be consistent with non-aliased steps but will result in exported variables which could be problematic if not being used in a top-level program (i.e. not a redistributable package).
- [source,go]
+ [source,groovy]
+ ----
+ g.V().repeat(__.out()).times(2).values('name')
  ----
- 	var __ = gremlingo.T__
- 	var gt = gremlingo.P.Gt
- 	var order = gremlingo.Order
  
- 	results, err := g.V().HasLabel("person").Has("age", __.Is(gt(30))).Order().By("age", order.Desc).ToList()
+ must be written as:
+ 
+ [source,csharp]
+ ----
+ g.V().Repeat(__.Out()).Times(2).Values<string>("name");
  ----
  
- ==== List of useful aliases
- [source,go]
+ Gremlin allows for `Map` instances to include `null` keys, but `null` keys in C# `Dictionary` instances are not allowed.
+ It is therefore necessary to rewrite a traversal such as:
+ 
+ [source,javascript]
+ ----
+ g.V().groupCount().by('age')
  ----
- 	// common
- 	var __ = gremlingo.T__
- 	var TextP = gremlingo.TextP
  
- 	// predicates
- 	var between = gremlingo.P.Between
- 	var eq = gremlingo.P.Eq
- 	var gt = gremlingo.P.Gt
- 	var gte = gremlingo.P.Gte
- 	var inside = gremlingo.P.Inside
- 	var lt = gremlingo.P.Lt
- 	var lte = gremlingo.P.Lte
- 	var neq = gremlingo.P.Neq
- 	var not = gremlingo.P.Not
- 	var outside = gremlingo.P.Outside
- 	var test = gremlingo.P.Test
- 	var within = gremlingo.P.Within
- 	var without = gremlingo.P.Without
- 	var and = gremlingo.P.And
- 	var or = gremlingo.P.Or
+ where "age" is not a valid key for all vertices in a way that will remove the need for a `null` to be returned.
  
- 	// sorting
- 	var order = gremlingo.Order
+ [source,javascript]
+ ----
+ g.V().has('age').groupCount().by('age')
+ g.V().hasLabel('person').groupCount().by('age')
  ----
  
- [[gremlin-go-limitations]]
+ Either of the above two options accomplishes the desired goal as both prevent `groupCount()` from having to process
+ the possibility of `null`.
+ 
+ anchor:gremlin-net-limitations[]
+ [[gremlin-dotnet-limitations]]
  === Limitations
  
- * There is no default `set` type in Go. Any set type code from server will be deserialized into slices with the list
- type implementation. To input a set into Gremlin-Go, a custom struct which implements the `gremlingo.Set` interface
- will be serialized as a set. `gremlingo.NewSimpleSet` is a basic implementation of a set that is provided by Gremlin-Go
- that can be used to fulfill the `gremlingo.Set` interface if desired.
+ * The `subgraph()`-step is not supported by any variant that is not running on the Java Virtual Machine as there is
+ no `Graph` instance to deserialize a result into on the client-side. A workaround is to replace the step with
+ `aggregate(local)` and then convert those results to something the client can use locally.
  
- [[gremlin-go-examples]]
+ anchor:gremlin-dotnet-template[]
+ anchor:dotnet-application-examples[]
+ anchor:gremlin-net-examples[]
+ [[gremlin-dotnet-examples]]
  === Application Examples
  
- The TinkerPop source code contains a simple Go script that shows a basic example of how gremlin-go works. It
- can be found in GitHub link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-go/example/example.go[here]
- and is designed to work best with a running <<gremlin-server,Gremlin Server>> configured with the default
- `conf/gremlin-server.yaml` file as included with the standard release packaging.
+ 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]
- ----
- go run example.go
- ----
+ 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-python]]
  == Gremlin-Python


[tinkerpop] 03/03: Merge branch '3.6-dev'

Posted by sp...@apache.org.
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 a80bba5781772899ed8c209e997457eb0a7328f8
Merge: f9fbd98742 097d3f7103
Author: Stephen Mallette <st...@amazon.com>
AuthorDate: Tue Jan 10 13:35:54 2023 -0500

    Merge branch '3.6-dev'

 docs/src/reference/gremlin-variants.asciidoc | 2784 +++++++++++++-------------
 1 file changed, 1392 insertions(+), 1392 deletions(-)