diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index 671a28664c4..0e50ed6929e 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -27,6 +27,8 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima * Added getter for `parameterItems` and `valueTraversal` on `DifferenceStep`. * Added properties to `Element` objects found in a `Path` for GraphSON v2 and v3 and GraphBinary. * Fixed edge properties for GraphBinary which were not deserializing properly. +* Improved GLV examples reliability and documentation with step-by-step instructions. +* Added root-level GLV examples in `glv-examples/` directory that use published driver versions for easy out-of-the-box usage, separate from module-level examples that use local development code. * Bump netty to 4.1.125.Final [[release-3-7-4]] diff --git a/docs/src/dev/developer/development-environment.asciidoc b/docs/src/dev/developer/development-environment.asciidoc index 248dcdb6fe0..c5dab5f4694 100644 --- a/docs/src/dev/developer/development-environment.asciidoc +++ b/docs/src/dev/developer/development-environment.asciidoc @@ -497,6 +497,11 @@ and GLVs will run automatically with integration tests against the TinkerTransac ** Generate web site locally: `bin/generate-home.sh` ** Publish web site: `bin/publish-home.sh ` +[[glv-examples]] +== GLV Examples + +TinkerPop maintains GLV examples in two distinct locations. User-facing examples in the `glv-examples/` directory utilize published driver versions and are referenced in the main documentation. Module-level examples within each GLV directory (e.g., `gremlin-python/src/main/python/examples/`) use local development code to ensure compatibility and prevent regressions. + [[building-on-windows]] == Building On Windows diff --git a/docs/src/dev/developer/release.asciidoc b/docs/src/dev/developer/release.asciidoc index 5110fe36e9e..6788a7b5c50 100644 --- a/docs/src/dev/developer/release.asciidoc +++ b/docs/src/dev/developer/release.asciidoc @@ -329,6 +329,13 @@ the help of a PMC member for those steps. . Consider the changes made to Gremlin and determine if the community needs to organize a PR to [DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/gremlin) to keep TypeScript up to date. . Ensure that the GLV examples compile and run with the latest image and dependencies: `bin/run-examples.sh`. .. Make changes as necessary to update the examples. +. Update root-level GLV examples to use the new release version: +.. Update version numbers in `glv-examples/gremlin-java/pom.xml` to reference the new release version +.. Update version numbers in `glv-examples/gremlin-javascript/package.json` to reference the new release version +.. Update version numbers in `glv-examples/gremlin-python/requirements.txt` to reference the new release version +.. Update version numbers in `glv-examples/gremlin-dotnet/*/\*.csproj` to reference the new release version +.. Update version numbers in `glv-examples/gremlin-go/go.mod` to reference the new release version +.. Test that all root-level examples work correctly with the new published versions . Generate a list of dead branches that will be automatically deleted and post them as a DISCUSS thread for review, then once consensus is reached removed those branches. . Set up the IO tests for the current `SNAPSHOT` as discussed in the <> diff --git a/docs/src/reference/gremlin-variants.asciidoc b/docs/src/reference/gremlin-variants.asciidoc index b0a4cbf580b..a58ff8e03a2 100644 --- a/docs/src/reference/gremlin-variants.asciidoc +++ b/docs/src/reference/gremlin-variants.asciidoc @@ -521,31 +521,48 @@ that can be used to fulfill the `gremlingo.Set` interface if desired. === Application Examples The TinkerPop source code contains some sample applications that demonstrate the basics of Gremlin-Go. They -can be found in GitHub link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-go/examples/[here] +can be found in GitHub link:https://github.com/apache/tinkerpop/tree/x.y.z/glv-examples/gremlin-go/[here] and are designed to connect to a running <> configured with the `conf/gremlin-server.yaml` and `conf/gremlin-server-modern.yaml` files as included with the standard release packaging. -To run the examples, first download an image of Gremlin Server from Docker Hub: +This guide assumes Gremlin Server will be executed using Docker. Alternatively, Gremlin Server can run locally (see the <> documentation for this option). + +To start Gremlin Server using Docker, first download an image of Gremlin Server from Docker Hub: + [source,shell] ---- docker pull tinkerpop/gremlin-server ---- -The remote connection and basic Gremlin examples can be run on a clean server, which uses the default configuration file -`conf/gremlin-server.yaml`. To start a clean server, launch a new container with `docker run`: +Clean server: + [source,shell] ---- docker run -d -p 8182:8182 tinkerpop/gremlin-server ---- -The traversal examples should be run on a server configured to start with the Modern toy graph, using `conf/gremlin-server-modern.yaml`. -To start a server with the Modern graph preloaded, launch a new container with `docker run`: +Modern toy graph server: + [source,shell] ---- docker run -d -p 8182:8182 tinkerpop/gremlin-server conf/gremlin-server-modern.yaml ---- -Each example can now be run with the following commands: +The remote connection and basic Gremlin examples can be run on a clean server, while traversal examples should be +run on a server with the Modern graph preloaded. + +==== Prerequisites +- Compatible Go installed (see <> for supported versions) + +Navigate to the examples directory: + +[source,shell] +---- +cd glv-examples/gremlin-go +---- + +Run the examples: + [source,shell] ---- go run connections.go @@ -1263,19 +1280,62 @@ execute it. === Application Examples The TinkerPop source code contains some sample applications that demonstrate the basics of Gremlin-Java. They -can be found in GitHub link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-driver/src/main/java/examples/[here]. +can be found in GitHub link:https://github.com/apache/tinkerpop/tree/x.y.z/glv-examples/gremlin-java/[here] +and are designed to connect to a running <> configured with the +`conf/gremlin-server.yaml` and `conf/gremlin-server-modern.yaml` files as included with the standard release packaging. + +This guide assumes Gremlin Server will be executed using Docker. Alternatively, Gremlin Server can run locally (see the <> documentation for this option). -The remote connection examples in particular are designed to connect to a running <> -configured with the `conf/gremlin-server.yaml` file as included with the standard release packaging. +To start Gremlin Server using Docker, first download an image of Gremlin Server from Docker Hub: -To do so, download an image of Gremlin Server from Docker Hub, then launch a new container with `docker run`: [source,shell] ---- docker pull tinkerpop/gremlin-server +---- + +Clean server: + +[source,shell] +---- docker run -d -p 8182:8182 tinkerpop/gremlin-server ---- -All examples can then be run using your IDE of choice. +Modern toy graph server: + +[source,shell] +---- +docker run -d -p 8182:8182 tinkerpop/gremlin-server conf/gremlin-server-modern.yaml +---- + +The remote connection and basic Gremlin examples can be run on a clean server, while traversal examples should be +run on a server with the Modern graph preloaded. + +==== Prerequisites +- Compatible JDK installed (see <> for supported versions) +- Maven installed + +Navigate to the examples directory: + +[source,shell] +---- +cd glv-examples/gremlin-java +---- + +Build the examples with Maven: + +[source,shell] +---- +mvn clean install +---- + +Run the examples: + +[source,shell] +---- +java -cp target/run-examples-shaded.jar examples.Connections +java -cp target/run-examples-shaded.jar examples.BasicGremlin +java -cp target/run-examples-shaded.jar examples.ModernTraversals +---- [[gremlin-javascript]] == Gremlin-JavaScript @@ -1687,37 +1747,56 @@ no `Graph` instance to deserialize a result into on the client-side. A workaroun === Application Examples The TinkerPop source code contains some sample applications that demonstrate the basics of Gremlin-JavaScript. They -can be found in GitHub link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-javascript/examples/[here] +can be found in GitHub link:https://github.com/apache/tinkerpop/tree/x.y.z/glv-examples/gremlin-javascript/[here] and are designed to connect to a running <> configured with the `conf/gremlin-server.yaml` and `conf/gremlin-server-modern.yaml` files as included with the standard release packaging. -To run the examples, first download an image of Gremlin Server from Docker Hub: +This guide assumes Gremlin Server will be executed using Docker. Alternatively, Gremlin Server can run locally (see the <> documentation for this option). + +To start Gremlin Server using Docker, first download an image of Gremlin Server from Docker Hub: + [source,shell] ---- docker pull tinkerpop/gremlin-server ---- -The remote connection and basic Gremlin examples can be run on a clean server, which uses the default configuration file -`conf/gremlin-server.yaml`. To start a clean server, launch a new container with `docker run`: +Clean server: + [source,shell] ---- docker run -d -p 8182:8182 tinkerpop/gremlin-server ---- -The traversal examples should be run on a server configured to start with the Modern toy graph, using `conf/gremlin-server-modern.yaml`. -To start a server with the Modern graph preloaded, launch a new container with `docker run`: +Modern toy graph server: + [source,shell] ---- docker run -d -p 8182:8182 tinkerpop/gremlin-server conf/gremlin-server-modern.yaml ---- -Make sure to install all necessary packages: +The remote connection and basic Gremlin examples can be run on a clean server, while traversal examples should be +run on a server with the Modern graph preloaded. + +==== Prerequisites +- Compatible Node.js installed (see <> for supported versions) +- npm installed + +Navigate to the examples directory: + +[source,shell] +---- +cd glv-examples/gremlin-javascript +---- + +Install the dependencies: + [source,shell] ---- npm install ---- -Each example can now be run with the following commands: +Run the examples: + [source,shell] ---- node connections.js @@ -2088,34 +2167,60 @@ dotnet new gremlin -o MyFirstGremlinProject === Application Examples The TinkerPop source code contains some sample applications that demonstrate the basics of Gremlin-Dotnet. They -can be found in GitHub link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-dotnet/Examples/[here] +can be found in GitHub link:https://github.com/apache/tinkerpop/tree/x.y.z/glv-examples/gremlin-dotnet/[here] and are designed to connect to a running <> configured with the `conf/gremlin-server.yaml` and `conf/gremlin-server-modern.yaml` files as included with the standard release packaging. -To run the examples, first download an image of Gremlin Server from Docker Hub: +This guide assumes Gremlin Server will be executed using Docker. Alternatively, Gremlin Server can run locally (see the <> documentation for this option). + +To start Gremlin Server using Docker, first download an image of Gremlin Server from Docker Hub: + [source,shell] ---- docker pull tinkerpop/gremlin-server ---- -The remote connection and basic Gremlin examples can be run on a clean server, which uses the default configuration file -`conf/gremlin-server.yaml`. To start a clean server, launch a new container with `docker run`: +Clean server: + [source,shell] ---- docker run -d -p 8182:8182 tinkerpop/gremlin-server ---- -The traversal examples should be run on a server configured to start with the Modern toy graph, using `conf/gremlin-server-modern.yaml`. -To start a server with the Modern graph preloaded, launch a new container with `docker run`: +Modern toy graph server: + [source,shell] ---- docker run -d -p 8182:8182 tinkerpop/gremlin-server conf/gremlin-server-modern.yaml ---- -Each example can now be run with the following command in their respective project directories: +The remote connection and basic Gremlin examples can be run on a clean server, while traversal examples should be +run on a server with the Modern graph preloaded. + +==== Prerequisites +- Compatible .NET SDK installed (see <> for supported versions) + +Navigate to the examples directory: + [source,shell] ---- -dotnet run +cd glv-examples/gremlin-dotnet +---- + +Build all projects: + +[source,shell] +---- +dotnet build Examples.sln +---- + +Run specific examples: + +[source,shell] +---- +dotnet run --project BasicGremlin +dotnet run --project Connections +dotnet run --project ModernTraversals ---- [[gremlin-python]] @@ -2658,31 +2763,58 @@ async def run_in_thread(): === Application Examples The TinkerPop source code contains some sample applications that demonstrate the basics of Gremlin-Python. They -can be found in GitHub link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-python/src/main/python/examples/[here] +can be found in GitHub link:https://github.com/apache/tinkerpop/tree/x.y.z/glv-examples/gremlin-python/[here] and are designed to connect to a running <> configured with the `conf/gremlin-server.yaml` and `conf/gremlin-server-modern.yaml` files as included with the standard release packaging. -To run the examples, first download an image of Gremlin Server from Docker Hub: +This guide assumes Gremlin Server will be executed using Docker. Alternatively, Gremlin Server can run locally (see the <> documentation for this option). + +To start Gremlin Server using Docker, first download an image of Gremlin Server from Docker Hub: + [source,shell] ---- docker pull tinkerpop/gremlin-server ---- -The remote connection and basic Gremlin examples can be run on a clean server, which uses the default configuration file -`conf/gremlin-server.yaml`. To start a clean server, launch a new container with `docker run`: +Clean server: + [source,shell] ---- docker run -d -p 8182:8182 tinkerpop/gremlin-server ---- -The traversal examples should be run on a server configured to start with the Modern toy graph, using `conf/gremlin-server-modern.yaml`. -To start a server with the Modern graph preloaded, launch a new container with `docker run`: +Modern toy graph server: + [source,shell] ---- docker run -d -p 8182:8182 tinkerpop/gremlin-server conf/gremlin-server-modern.yaml ---- -Each example can now be run with the following commands: +The remote connection and basic Gremlin examples can be run on a clean server, while traversal examples should be +run on a server with the Modern graph preloaded. + +==== Prerequisites +- Compatible Python installed (see <> for supported versions) +- pip installed + +NOTE: On some systems, you may need to use `python3` and `pip3` instead of `python` and `pip`. + +Navigate to the examples directory: + +[source,shell] +---- +cd glv-examples/gremlin-python +---- + +Install the requirements: + +[source,shell] +---- +pip install -r requirements.txt +---- + +Run the examples: + [source,shell] ---- python connections.py diff --git a/glv-examples/README.md b/glv-examples/README.md new file mode 100644 index 00000000000..b68ce5033b5 --- /dev/null +++ b/glv-examples/README.md @@ -0,0 +1,28 @@ + + +# TinkerPop GLV Examples + +This directory contains ready-to-run examples for all Gremlin Language Variants (GLVs) using the latest published driver versions. These examples work out-of-the-box without requiring you to build TinkerPop from source. For detailed instructions on how to run these examples, please refer to the official documentation for each language: + +## GLV Examples Documentation + +- **Go**: https://tinkerpop.apache.org/docs/current/reference/#gremlin-go-examples +- **Java**: https://tinkerpop.apache.org/docs/current/reference/#gremlin-java-examples +- **JavaScript**: https://tinkerpop.apache.org/docs/current/reference/#gremlin-javascript-examples +- **.NET**: https://tinkerpop.apache.org/docs/current/reference/#gremlin-dotnet-examples +- **Python**: https://tinkerpop.apache.org/docs/current/reference/#gremlin-python-examples diff --git a/glv-examples/gremlin-dotnet/BasicGremlin/BasicGremlin.cs b/glv-examples/gremlin-dotnet/BasicGremlin/BasicGremlin.cs new file mode 100644 index 00000000000..91820bfe095 --- /dev/null +++ b/glv-examples/gremlin-dotnet/BasicGremlin/BasicGremlin.cs @@ -0,0 +1,54 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/ + +using Gremlin.Net.Driver; +using Gremlin.Net.Driver.Remote; +using static Gremlin.Net.Process.Traversal.AnonymousTraversalSource; + +public class BasicGremlinExample +{ + static async Task Main() + { + var server = new GremlinServer("localhost", 8182); + using var remoteConnection = new DriverRemoteConnection(new GremlinClient(server), "g"); + var g = Traversal().WithRemote(remoteConnection); + + // Basic Gremlin: adding and retrieving data + var v1 = g.AddV("person").Property("name", "marko").Next(); + var v2 = g.AddV("person").Property("name", "stephen").Next(); + var v3 = g.AddV("person").Property("name", "vadas").Next(); + + // Be sure to use a terminating step like Next() or Iterate() so that the traversal "executes" + // Iterate() does not return any data and is used to just generate side-effects (i.e. write data to the database) + g.V(v1).AddE("knows").To(v2).Property("weight", 0.75).Iterate(); + g.V(v1).AddE("knows").To(v3).Property("weight", 0.75).Iterate(); + + // Retrieve the data from the "marko" vertex + var marko = await g.V().Has("person", "name", "marko").Values("name").Promise(t => t.Next()); + Console.WriteLine("name: " + marko); + + // Find the "marko" vertex and then traverse to the people he "knows" and return their data + var peopleMarkoKnows = await g.V().Has("person", "name", "marko").Out("knows").Values("name").Promise(t => t.ToList()); + foreach (var person in peopleMarkoKnows) + { + Console.WriteLine("marko knows " + person); + } + } +} + diff --git a/glv-examples/gremlin-dotnet/BasicGremlin/BasicGremlin.csproj b/glv-examples/gremlin-dotnet/BasicGremlin/BasicGremlin.csproj new file mode 100644 index 00000000000..45bb6afd73c --- /dev/null +++ b/glv-examples/gremlin-dotnet/BasicGremlin/BasicGremlin.csproj @@ -0,0 +1,30 @@ + + + + + + Exe + net8.0 + enable + enable + + + + + + diff --git a/glv-examples/gremlin-dotnet/Connections/Connections.cs b/glv-examples/gremlin-dotnet/Connections/Connections.cs new file mode 100644 index 00000000000..940cc05990b --- /dev/null +++ b/glv-examples/gremlin-dotnet/Connections/Connections.cs @@ -0,0 +1,74 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/ + +using Gremlin.Net.Driver; +using Gremlin.Net.Driver.Remote; +using Gremlin.Net.Structure.IO.GraphSON; +using static Gremlin.Net.Process.Traversal.AnonymousTraversalSource; + +public class ConnectionExample +{ + static void Main() + { + WithRemote(); + WithConf(); + WithSerializer(); + } + + // Connecting to the server + static void WithRemote() + { + var server = new GremlinServer("localhost", 8182); + using var remoteConnection = new DriverRemoteConnection(new GremlinClient(server), "g"); + var g = Traversal().WithRemote(remoteConnection); + + // Drop existing vertices + g.V().Drop().Iterate(); + + // Simple query to verify connection + var v = g.AddV().Iterate(); + var count = g.V().Count().Next(); + Console.WriteLine("Vertex count: " + count); + } + + // Connecting to the server with customized configurations + static void WithConf() + { + using var remoteConnection = new DriverRemoteConnection(new GremlinClient( + new GremlinServer(hostname: "localhost", port: 8182, enableSsl: false, username: "", password: "")), "g"); + var g = Traversal().WithRemote(remoteConnection); + + var v = g.AddV().Iterate(); + var count = g.V().Count().Next(); + Console.WriteLine("Vertex count: " + count); + } + + // Specifying a serializer + static void WithSerializer() + { + var server = new GremlinServer("localhost", 8182); + var client = new GremlinClient(server, new GraphSON3MessageSerializer()); + using var remoteConnection = new DriverRemoteConnection(client, "g"); + var g = Traversal().WithRemote(remoteConnection); + + var v = g.AddV().Iterate(); + var count = g.V().Count().Next(); + Console.WriteLine("Vertex count: " + count); + } +} diff --git a/glv-examples/gremlin-dotnet/Connections/Connections.csproj b/glv-examples/gremlin-dotnet/Connections/Connections.csproj new file mode 100644 index 00000000000..45bb6afd73c --- /dev/null +++ b/glv-examples/gremlin-dotnet/Connections/Connections.csproj @@ -0,0 +1,30 @@ + + + + + + Exe + net8.0 + enable + enable + + + + + + diff --git a/glv-examples/gremlin-dotnet/Examples.sln b/glv-examples/gremlin-dotnet/Examples.sln new file mode 100644 index 00000000000..963bb259f6e --- /dev/null +++ b/glv-examples/gremlin-dotnet/Examples.sln @@ -0,0 +1,37 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 25.0.1706.4 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Connections", "Connections\Connections.csproj", "{9E201BDD-911A-4671-A12E-B7400E9FA5DB}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BasicGremlin", "BasicGremlin\BasicGremlin.csproj", "{535D7393-6115-4BEF-A344-E7DE3A891098}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModernTraversals", "ModernTraversals\ModernTraversals.csproj", "{F3D3A764-F72A-4F63-9C23-D998BA61CAD4}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9E201BDD-911A-4671-A12E-B7400E9FA5DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9E201BDD-911A-4671-A12E-B7400E9FA5DB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9E201BDD-911A-4671-A12E-B7400E9FA5DB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9E201BDD-911A-4671-A12E-B7400E9FA5DB}.Release|Any CPU.Build.0 = Release|Any CPU + {535D7393-6115-4BEF-A344-E7DE3A891098}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {535D7393-6115-4BEF-A344-E7DE3A891098}.Debug|Any CPU.Build.0 = Debug|Any CPU + {535D7393-6115-4BEF-A344-E7DE3A891098}.Release|Any CPU.ActiveCfg = Release|Any CPU + {535D7393-6115-4BEF-A344-E7DE3A891098}.Release|Any CPU.Build.0 = Release|Any CPU + {F3D3A764-F72A-4F63-9C23-D998BA61CAD4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F3D3A764-F72A-4F63-9C23-D998BA61CAD4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F3D3A764-F72A-4F63-9C23-D998BA61CAD4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F3D3A764-F72A-4F63-9C23-D998BA61CAD4}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {042DF872-50CB-4F95-9CDB-117540F4DF29} + EndGlobalSection +EndGlobal diff --git a/glv-examples/gremlin-dotnet/ModernTraversals/ModernTraversals.cs b/glv-examples/gremlin-dotnet/ModernTraversals/ModernTraversals.cs new file mode 100644 index 00000000000..fab70735301 --- /dev/null +++ b/glv-examples/gremlin-dotnet/ModernTraversals/ModernTraversals.cs @@ -0,0 +1,71 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/ + +using Gremlin.Net.Driver; +using Gremlin.Net.Driver.Remote; +using Gremlin.Net.Process.Traversal; +using static Gremlin.Net.Process.Traversal.AnonymousTraversalSource; +using static Gremlin.Net.Process.Traversal.__; +using static Gremlin.Net.Process.Traversal.P; + +public class ModernTraversalExample +{ + static void Main() + { + var server = new GremlinServer("localhost", 8182); + using var remoteConnection = new DriverRemoteConnection(new GremlinClient(server), "g"); + var g = Traversal().WithRemote(remoteConnection); + + /* + This example requires the Modern toy graph to be preloaded upon launching the Gremlin server. + For details, see https://tinkerpop.apache.org/docs/current/reference/#gremlin-server-docker-image and use + conf/gremlin-server-modern.yaml. + */ + var e1 = g.V(1).BothE().ToList(); // (1) + var e2 = g.V(1).BothE().Where(OtherV().HasId(2)).ToList(); // (2) + var v1 = g.V(1).Next(); + var v2 = g.V(2).Next(); + var e3 = g.V(v1).BothE().Where(OtherV().Is(v2)).ToList(); // (3) + var e4 = g.V(v1).OutE().Where(InV().Is(v2)).ToList(); // (4) + var e5 = g.V(1).OutE().Where(InV().Has(T.Id, Within(2, 3))).ToList(); // (5) + var e6 = g.V(1).Out().Where(__.In().HasId(6)).ToList(); // (6) + + Console.WriteLine(string.Join(", ", e1)); + Console.WriteLine(string.Join(", ", e2)); + Console.WriteLine(string.Join(", ", e3)); + Console.WriteLine(string.Join(", ", e4)); + Console.WriteLine(string.Join(", ", e5)); + Console.WriteLine(string.Join(", ", e6)); + + /* + 1. There are three edges from the vertex with the identifier of "1". + 2. Filter those three edges using the Where()-step using the identifier of the vertex returned by OtherV() to + ensure it matches on the vertex of concern, which is the one with an identifier of "2". + 3. Note that the same traversal will work if there are actual Vertex instances rather than just vertex + identifiers. + 4. The vertex with identifier "1" has all outgoing edges, so it would also be acceptable to use the directional + steps of OutE() and InV() since the schema allows it. + 5. There is also no problem with filtering the terminating side of the traversal on multiple vertices, in this + case, vertices with identifiers "2" and "3". + 6. There’s no reason why the same pattern of exclusion used for edges with Where() can’t work for a vertex + + between two vertices. + */ + } +} \ No newline at end of file diff --git a/glv-examples/gremlin-dotnet/ModernTraversals/ModernTraversals.csproj b/glv-examples/gremlin-dotnet/ModernTraversals/ModernTraversals.csproj new file mode 100644 index 00000000000..0cb709499be --- /dev/null +++ b/glv-examples/gremlin-dotnet/ModernTraversals/ModernTraversals.csproj @@ -0,0 +1,30 @@ + + + + + + Exe + net8.0 + enable + enable + + + + + + diff --git a/glv-examples/gremlin-go/basic_gremlin.go b/glv-examples/gremlin-go/basic_gremlin.go new file mode 100644 index 00000000000..0ab2b1117fd --- /dev/null +++ b/glv-examples/gremlin-go/basic_gremlin.go @@ -0,0 +1,69 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/ + +package main + +import ( + "fmt" + + "github.com/apache/tinkerpop/gremlin-go/v3/driver" +) + +func main() { + driverRemoteConnection, err := gremlingo.NewDriverRemoteConnection("ws://localhost:8182/gremlin") + if err != nil { + fmt.Println(err) + return + } + defer driverRemoteConnection.Close() + g := gremlingo.Traversal_().WithRemote(driverRemoteConnection) + + // Basic Gremlin: adding and retrieving data + v1, err := g.AddV("person").Property("name", "marko").Next() + v2, err := g.AddV("person").Property("name", "stephen").Next() + v3, err := g.AddV("person").Property("name", "vadas").Next() + v1Vertex, err := v1.GetVertex() + v2Vertex, err := v2.GetVertex() + v3Vertex, err := v3.GetVertex() + + // Be sure to use a terminating step like Next() or Iterate() so that the traversal "executes" + // Iterate() does not return any data and is used to just generate side-effects (i.e. write data to the database) + promise := g.V(v1Vertex).AddE("knows").To(v2Vertex).Property("weight", 0.75).Iterate() + err = <-promise + if err != nil { + fmt.Println(err) + return + } + promise = g.V(v1Vertex).AddE("knows").To(v3Vertex).Property("weight", 0.75).Iterate() + err = <-promise + if err != nil { + fmt.Println(err) + return + } + + // Retrieve the data from the "marko" vertex + marko, err := g.V().Has("person", "name", "marko").Values("name").Next() + fmt.Println("name:", marko.GetString()) + + // Find the "marko" vertex and then traverse to the people he "knows" and return their data + peopleMarkoKnows, err := g.V().Has("person", "name", "marko").Out("knows").Values("name").ToList() + for _, person := range peopleMarkoKnows { + fmt.Println("marko knows", person.GetString()) + } +} \ No newline at end of file diff --git a/glv-examples/gremlin-go/connections.go b/glv-examples/gremlin-go/connections.go new file mode 100644 index 00000000000..3e1f1de174d --- /dev/null +++ b/glv-examples/gremlin-go/connections.go @@ -0,0 +1,81 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/ + +package main + +import ( + "fmt" + + "github.com/apache/tinkerpop/gremlin-go/v3/driver" +) + +func main() { + withRemote() + withConfigs() +} + +func withRemote() { + // Creating the connection to the server + driverRemoteConnection, err := gremlingo.NewDriverRemoteConnection("ws://localhost:8182/gremlin") + + // Error handling + if err != nil { + fmt.Println(err) + return + } + + // Cleanup + defer driverRemoteConnection.Close() + + // Creating the graph traversal + g := gremlingo.Traversal_().WithRemote(driverRemoteConnection) + + // Drop existing vertices + prom := g.V().Drop().Iterate() + <-prom + + // Simple query to verify connection + g.AddV().Iterate() + count, _ := g.V().Count().Next() + fmt.Println("Vertex count:", *count) +} + +func withConfigs() { + // Connecting to the server with customized configurations + driverRemoteConnection, err := gremlingo.NewDriverRemoteConnection("ws://localhost:8182/gremlin", + func(settings *gremlingo.DriverRemoteConnectionSettings) { + settings.TraversalSource = "g" + settings.NewConnectionThreshold = 4 + settings.EnableCompression = false + settings.ReadBufferSize = 0 + settings.WriteBufferSize = 0 + }) + + if err != nil { + fmt.Println(err) + return + } + + defer driverRemoteConnection.Close() + g := gremlingo.Traversal_().WithRemote(driverRemoteConnection) + + g.AddV().Iterate() + count, _ := g.V().Count().Next() + fmt.Println("Vertex count:", *count) +} \ No newline at end of file diff --git a/glv-examples/gremlin-go/go.mod b/glv-examples/gremlin-go/go.mod new file mode 100644 index 00000000000..4dfa2fe4276 --- /dev/null +++ b/glv-examples/gremlin-go/go.mod @@ -0,0 +1,29 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +module example + +go 1.24.0 + +require github.com/apache/tinkerpop/gremlin-go/v3 v3.7.4 + +require ( + github.com/google/uuid v1.6.0 // indirect + github.com/gorilla/websocket v1.5.3 // indirect + github.com/nicksnyder/go-i18n/v2 v2.6.0 // indirect + golang.org/x/text v0.29.0 // indirect +) diff --git a/glv-examples/gremlin-go/go.sum b/glv-examples/gremlin-go/go.sum new file mode 100644 index 00000000000..406055a78bf --- /dev/null +++ b/glv-examples/gremlin-go/go.sum @@ -0,0 +1,28 @@ +github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= +github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/apache/tinkerpop/gremlin-go/v3 v3.7.3 h1:QeFU7bC7p/fTo4FXl+ce7pQW3Pgx68hUQMWdnQIZlzc= +github.com/apache/tinkerpop/gremlin-go/v3 v3.7.3/go.mod h1:rMQiut0XlpFgaHLSbUgoP9QmGXjFJeXlh42Zxp4Fnno= +github.com/apache/tinkerpop/gremlin-go/v3 v3.7.4 h1:w4kbgY+klmw5WjcniKqhhfoSmbinhT3lc0CoF/AHMqI= +github.com/apache/tinkerpop/gremlin-go/v3 v3.7.4/go.mod h1:hw4is2yHBjGOOoa9Z1sKckEJsH2bCXvq2biORjo32sM= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/nicksnyder/go-i18n/v2 v2.4.1 h1:zwzjtX4uYyiaU02K5Ia3zSkpJZrByARkRB4V3YPrr0g= +github.com/nicksnyder/go-i18n/v2 v2.4.1/go.mod h1:++Pl70FR6Cki7hdzZRnEEqdc2dJt+SAGotyFg/SvZMk= +github.com/nicksnyder/go-i18n/v2 v2.6.0 h1:C/m2NNWNiTB6SK4Ao8df5EWm3JETSTIGNXBpMJTxzxQ= +github.com/nicksnyder/go-i18n/v2 v2.6.0/go.mod h1:88sRqr0C6OPyJn0/KRNaEz1uWorjxIKP7rUUcvycecE= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk= +golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/glv-examples/gremlin-go/modern_traversals.go b/glv-examples/gremlin-go/modern_traversals.go new file mode 100644 index 00000000000..a1c9ad83203 --- /dev/null +++ b/glv-examples/gremlin-go/modern_traversals.go @@ -0,0 +1,77 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/ + +package main + +import ( + "fmt" + + "github.com/apache/tinkerpop/gremlin-go/v3/driver" +) + +var __ = gremlingo.T__ +var T = gremlingo.T +var P = gremlingo.P + +func main() { + driverRemoteConnection, err := gremlingo.NewDriverRemoteConnection("ws://localhost:8182/gremlin") + if err != nil { + fmt.Println(err) + return + } + defer driverRemoteConnection.Close() + g := gremlingo.Traversal_().WithRemote(driverRemoteConnection) + + /* + This example requires the Modern toy graph to be preloaded upon launching the Gremlin server. + For details, see https://tinkerpop.apache.org/docs/current/reference/#gremlin-server-docker-image and use + conf/gremlin-server-modern.yaml. + */ + e1, err := g.V(1).BothE().ToList() // (1) + e2, err := g.V().BothE().Where(__.OtherV().HasId(2)).ToList() // (2) + v1, err := g.V(1).Next() + v2, err := g.V(2).Next() + v1Vertex, err := v1.GetVertex() + v2Vertex, err := v2.GetVertex() + e3, err := g.V(v1Vertex).BothE().Where(__.OtherV().Is(v2Vertex)).ToList() // (3) + e4, err := g.V(v1Vertex).OutE().Where(__.InV().Is(v2Vertex)).ToList() // (4) + e5, err := g.V(1).OutE().Where(__.InV().Has(T.Id, P.Within(2, 3))).ToList() // (5) + e6, err := g.V(1).Out().Where(__.In().HasId(6)).ToList() // (6) + + fmt.Println(e1) + fmt.Println(e2) + fmt.Println(e3) + fmt.Println(e4) + fmt.Println(e5) + fmt.Println(e6) + + /* + 1. There are three edges from the vertex with the identifier of "1". + 2. Filter those three edges using the Where()-step using the identifier of the vertex returned by OtherV() to + ensure it matches on the vertex of concern, which is the one with an identifier of "2". + 3. Note that the same traversal will work if there are actual Vertex instances rather than just vertex + identifiers. + 4. The vertex with identifier "1" has all outgoing edges, so it would also be acceptable to use the directional + steps of OutE() and InV() since the schema allows it. + 5. There is also no problem with filtering the terminating side of the traversal on multiple vertices, in this + case, vertices with identifiers "2" and "3". + 6. There’s no reason why the same pattern of exclusion used for edges with Where() can’t work for a vertex + between two vertices. + */ +} diff --git a/glv-examples/gremlin-java/BasicGremlin.java b/glv-examples/gremlin-java/BasicGremlin.java new file mode 100644 index 00000000000..a5075d46061 --- /dev/null +++ b/glv-examples/gremlin-java/BasicGremlin.java @@ -0,0 +1,56 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/ + +package examples; + +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.apache.tinkerpop.gremlin.structure.Graph; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph; + +import java.util.List; + +import static org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource.traversal; + +public class BasicGremlin { + public static void main(String[] args) { + Graph graph = TinkerGraph.open(); + GraphTraversalSource g = traversal().withEmbedded(graph); + + // Basic Gremlin: adding and retrieving data + Vertex v1 = g.addV("person").property("name","marko").next(); + Vertex v2 = g.addV("person").property("name","stephen").next(); + Vertex v3 = g.addV("person").property("name","vadas").next(); + + // Be sure to use a terminating step like next() or iterate() so that the traversal "executes" + // Iterate() does not return any data and is used to just generate side-effects (i.e. write data to the database) + g.V(v1).addE("knows").to(v2).property("weight",0.75).iterate(); + g.V(v1).addE("knows").to(v3).property("weight",0.75).iterate(); + + // Retrieve the data from the "marko" vertex + Object marko = g.V().has("person","name","marko").values("name").next(); + System.out.println("name: " + marko); + + // Find the "marko" vertex and then traverse to the people he "knows" and return their data + List peopleMarkoKnows = g.V().has("person","name","marko").out("knows").values("name").toList(); + for (Object person : peopleMarkoKnows) { + System.out.println("marko knows " + person); + } + } +} diff --git a/glv-examples/gremlin-java/Connections.java b/glv-examples/gremlin-java/Connections.java new file mode 100644 index 00000000000..458d5c8fd53 --- /dev/null +++ b/glv-examples/gremlin-java/Connections.java @@ -0,0 +1,116 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/ + +package examples; + +import org.apache.tinkerpop.gremlin.driver.Channelizer; +import org.apache.tinkerpop.gremlin.driver.Client; +import org.apache.tinkerpop.gremlin.driver.Cluster; +import org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteConnection; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.apache.tinkerpop.gremlin.structure.Graph; +import org.apache.tinkerpop.gremlin.structure.io.AbstractIoRegistry; +import org.apache.tinkerpop.gremlin.structure.io.IoRegistry; +import org.apache.tinkerpop.gremlin.structure.io.binary.TypeSerializerRegistry; +import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph; +import org.apache.tinkerpop.gremlin.util.MessageSerializer; +import org.apache.tinkerpop.gremlin.util.ser.GraphBinaryMessageSerializerV1; + +import static org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource.traversal; + +public class Connections { + public static void main(String[] args) throws Exception { + withEmbedded(); + withRemote(); + withCluster(); + withSerializer(); + } + + // Creating an embedded graph + private static void withEmbedded() throws Exception { + Graph graph = TinkerGraph.open(); + GraphTraversalSource g = traversal().withEmbedded(graph); + + g.addV().iterate(); + long count = g.V().count().next(); + System.out.println("Vertex count: " + count); + + g.close(); + } + + // Connecting to the server + private static void withRemote() throws Exception { + Cluster cluster = Cluster.build("localhost").port(8182).create(); + GraphTraversalSource g = traversal().withRemote(DriverRemoteConnection.using(cluster, "g")); + + // Drop existing vertices + g.V().drop().iterate(); + + // Simple query to verify connection + g.addV().iterate(); + long count = g.V().count().next(); + System.out.println("Vertex count: " + count); + + // Cleanup + cluster.close(); + g.close(); + } + + // Connecting and customizing configurations with a cluster + // See reference/#gremlin-java-configuration for full list of configurations + private static void withCluster() throws Exception { + Cluster cluster = Cluster.build("localhost"). + channelizer(Channelizer.WebSocketChannelizer.class). + keepAliveInterval(180000). + maxConnectionPoolSize(8). + path("/gremlin"). + port(8182). + serializer(new GraphBinaryMessageSerializerV1()). + create(); + GraphTraversalSource g = traversal().withRemote(DriverRemoteConnection.using(cluster, "g")); + + g.addV().iterate(); + long count = g.V().count().next(); + System.out.println("Vertex count: " + count); + + cluster.close(); + g.close(); + } + + // Connecting and specifying a serializer + private static void withSerializer() throws Exception { + IoRegistry registry = new FakeIoRegistry(); // 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("localhost"). + serializer(serializer). + create(); + Client client = cluster.connect(); + GraphTraversalSource g = traversal().withRemote(DriverRemoteConnection.using(client, "g")); + + g.addV().iterate(); + long count = g.V().count().next(); + System.out.println("Vertex count: " + count); + + cluster.close(); + g.close(); + } + + public static class FakeIoRegistry extends AbstractIoRegistry {} +} diff --git a/glv-examples/gremlin-java/ModernTraversals.java b/glv-examples/gremlin-java/ModernTraversals.java new file mode 100644 index 00000000000..c67b6daeb27 --- /dev/null +++ b/glv-examples/gremlin-java/ModernTraversals.java @@ -0,0 +1,71 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/ + +package examples; + +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.apache.tinkerpop.gremlin.structure.Graph; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerFactory; + +import java.util.List; + +import static org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource.traversal; +import static org.apache.tinkerpop.gremlin.process.traversal.P.within; +import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.*; +import static org.apache.tinkerpop.gremlin.structure.T.id; + +public class ModernTraversals { + public static void main(String[] args) { + // Performs basic traversals on the Modern toy graph which can be created using TinkerFactory + Graph modern = TinkerFactory.createModern(); + GraphTraversalSource g = traversal().withEmbedded(modern); + + List e1 = g.V(1).bothE().toList(); // (1) + List e2 = g.V(1).bothE().where(otherV().hasId(2)).toList(); // (2) + Vertex v1 = g.V(1).next(); + Vertex v2 = g.V(2).next(); + List e3 = g.V(v1).bothE().where(otherV().is(v2)).toList(); // (3) + List e4 = g.V(v1).outE().where(inV().is(v2)).toList(); // (4) + List e5 = g.V(1).outE().where(inV().has(id, within(2,3))).toList(); // (5) + List e6 = g.V(1).out().where(in().hasId(6)).toList(); // (6) + + System.out.println("1: " + e1.toString()); + System.out.println("2: " + e2.toString()); + System.out.println("3: " + e3.toString()); + System.out.println("4: " + e4.toString()); + System.out.println("5: " + e5.toString()); + System.out.println("6: " + e6.toString()); + + /* + 1. There are three edges from the vertex with the identifier of "1". + 2. Filter those three edges using the where()-step using the identifier of the vertex returned by otherV() to + ensure it matches on the vertex of concern, which is the one with an identifier of "2". + 3. Note that the same traversal will work if there are actual Vertex instances rather than just vertex + identifiers. + 4. The vertex with identifier "1" has all outgoing edges, so it would also be acceptable to use the directional + steps of outE() and inV() since the schema allows it. + 5. There is also no problem with filtering the terminating side of the traversal on multiple vertices, in this + case, vertices with identifiers "2" and "3". + 6. There’s no reason why the same pattern of exclusion used for edges with where() can’t work for a vertex + between two vertices. + */ + } +} diff --git a/glv-examples/gremlin-java/pom.xml b/glv-examples/gremlin-java/pom.xml new file mode 100644 index 00000000000..f11ec218775 --- /dev/null +++ b/glv-examples/gremlin-java/pom.xml @@ -0,0 +1,91 @@ + + + 4.0.0 + + org.apache.tinkerpop + run-examples + 3.7.4 + + + UTF-8 + 3.7.4 + + + + + org.apache.tinkerpop + gremlin-core + 3.7.4 + + + org.apache.tinkerpop + gremlin-driver + 3.7.4 + + + org.apache.tinkerpop + tinkergraph-gremlin + 3.7.4 + + + + + . + + + org.apache.maven.plugins + maven-compiler-plugin + + + org.apache.maven.plugins + maven-shade-plugin + 3.4.1 + + + package + + shade + + + run-examples-shaded + false + + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + + + + + + + + + \ No newline at end of file diff --git a/glv-examples/gremlin-javascript/.gitignore b/glv-examples/gremlin-javascript/.gitignore new file mode 100644 index 00000000000..2ccbe4656c6 --- /dev/null +++ b/glv-examples/gremlin-javascript/.gitignore @@ -0,0 +1 @@ +/node_modules/ diff --git a/glv-examples/gremlin-javascript/basic-gremlin.js b/glv-examples/gremlin-javascript/basic-gremlin.js new file mode 100644 index 00000000000..77e7f3b7d9f --- /dev/null +++ b/glv-examples/gremlin-javascript/basic-gremlin.js @@ -0,0 +1,51 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/ + +const gremlin = require('gremlin'); +const traversal = gremlin.process.AnonymousTraversalSource.traversal; +const DriverRemoteConnection = gremlin.driver.DriverRemoteConnection; + +async function main() { + const dc = new DriverRemoteConnection('ws://localhost:8182/gremlin'); + const g = traversal().withRemote(dc); + + // Basic Gremlin: adding and retrieving data + const v1 = await g.addV('person').property('name','marko').next(); + const v2 = await g.addV('person').property('name','stephen').next(); + const v3 = await g.addV('person').property('name','vadas').next(); + + // Be sure to use a terminating step like next() or iterate() so that the traversal "executes" + // Iterate() does not return any data and is used to just generate side-effects (i.e. write data to the database) + await g.V(v1.value).addE('knows').to(v2.value).property('weight',0.75).iterate(); + await g.V(v1.value).addE('knows').to(v3.value).property('weight',0.75).iterate(); + + // Retrieve the data from the "marko" vertex + const marko = await g.V().has('person','name','marko').values('name').toList(); + console.log("name: " + marko[0]); + + // Find the "marko" vertex and then traverse to the people he "knows" and return their data + const peopleMarkoKnows = await g.V().has('person','name','marko').out('knows').values('name').toList(); + peopleMarkoKnows.forEach((person) => { + console.log("marko knows " + person); + }); + + await dc.close(); +} + +main(); \ No newline at end of file diff --git a/glv-examples/gremlin-javascript/connections.js b/glv-examples/gremlin-javascript/connections.js new file mode 100644 index 00000000000..183f6404f6e --- /dev/null +++ b/glv-examples/gremlin-javascript/connections.js @@ -0,0 +1,65 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/ + +const gremlin = require('gremlin'); +const traversal = gremlin.process.AnonymousTraversalSource.traversal; +const DriverRemoteConnection = gremlin.driver.DriverRemoteConnection; +const serializer = gremlin.structure.io.graphserializer; + +async function main() { + await withRemote(); + await withConfigs(); +} + +async function withRemote() { + // Connecting to the server + const dc = new DriverRemoteConnection('ws://localhost:8182/gremlin'); + const g = traversal().withRemote(dc); + + // Drop existing vertices + await g.V().drop().iterate(); + + // Simple query to verify connection + const v = await g.addV().iterate(); + const count = await g.V().count().next(); + console.log("Vertex count: " + count.value); + + // Cleanup + await dc.close(); +} + +async function withConfigs() { + // Connecting and customizing configurations + const dc = new DriverRemoteConnection('ws://localhost:8182/gremlin', { + mimeType: 'application/vnd.gremlin-v3.0+json', + reader: serializer, + writer: serializer, + rejectUnauthorized: false, + traversalSource: 'g', + }); + const g = traversal().withRemote(dc); + + const v = await g.addV().iterate(); + const count = await g.V().count().next(); + console.log("Vertex count: " + count.value); + + await dc.close(); +} + +main(); \ No newline at end of file diff --git a/glv-examples/gremlin-javascript/modern-traversals.js b/glv-examples/gremlin-javascript/modern-traversals.js new file mode 100644 index 00000000000..66b039fca38 --- /dev/null +++ b/glv-examples/gremlin-javascript/modern-traversals.js @@ -0,0 +1,69 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/ + +const gremlin = require('gremlin'); +const traversal = gremlin.process.AnonymousTraversalSource.traversal; +const __ = gremlin.process.statics; +const DriverRemoteConnection = gremlin.driver.DriverRemoteConnection; +const p = gremlin.process.P; +const t = gremlin.process.t; + +async function main() { + /* + This example requires the Modern toy graph to be preloaded upon launching the Gremlin server. + For details, see https://tinkerpop.apache.org/docs/current/reference/#gremlin-server-docker-image and use + conf/gremlin-server-modern.yaml. + */ + const dc = new DriverRemoteConnection('ws://localhost:8182/gremlin'); + const g = traversal().withRemote(dc); + + const e1 = await g.V(1).bothE().toList(); // (1) + const e2 = await g.V(1).bothE().where(__.otherV().hasId(2)).toList(); // (2) + const v1 = await g.V(1).next(); + const v2 = await g.V(2).next(); + const e3 = await g.V(v1.value).bothE().where(__.otherV().is(v2.value)).toList(); // (3) + const e4 = await g.V(v1.value).outE().where(__.inV().is(v2.value)).toList(); // (4) + const e5 = await g.V(1).outE().where(__.inV().has(t.id, p.within(2,3))).toList(); // (5) + const e6 = await g.V(1).out().where(__.in_().hasId(6)).toList(); // (6) + + console.log("1: " + e1.toString()); + console.log("2: " + e2.toString()); + console.log("3: " + e3.toString()); + console.log("4: " + e4.toString()); + console.log("5: " + e5.toString()); + console.log("6: " + e6.toString()); + + /* + 1. There are three edges from the vertex with the identifier of "1". + 2. Filter those three edges using the where()-step using the identifier of the vertex returned by otherV() to + ensure it matches on the vertex of concern, which is the one with an identifier of "2". + 3. Note that the same traversal will work if there are actual Vertex instances rather than just vertex + identifiers. + 4. The vertex with identifier "1" has all outgoing edges, so it would also be acceptable to use the directional + steps of outE() and inV() since the schema allows it. + 5. There is also no problem with filtering the terminating side of the traversal on multiple vertices, in this + case, vertices with identifiers "2" and "3". + 6. There’s no reason why the same pattern of exclusion used for edges with where() can’t work for a vertex + between two vertices. + */ + + await dc.close(); +} + +main(); \ No newline at end of file diff --git a/glv-examples/gremlin-javascript/package-lock.json b/glv-examples/gremlin-javascript/package-lock.json new file mode 100644 index 00000000000..2466a0d15b8 --- /dev/null +++ b/glv-examples/gremlin-javascript/package-lock.json @@ -0,0 +1,220 @@ +{ + "name": "examples", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "examples", + "version": "1.0.0", + "license": "Apache-2.0", + "dependencies": { + "gremlin": "^3.7.4" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "license": "MIT" + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/gremlin": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/gremlin/-/gremlin-3.7.4.tgz", + "integrity": "sha512-BC/6q97uFcyJGjf1xVq0Uy5q06bJVbrb4KpAAOu8lfGV2RalGuvsIG7svlWatS/3q8b/HuwqHrMESVEDNBkBhw==", + "license": "Apache-2.0", + "dependencies": { + "buffer": "^6.0.3", + "eventemitter3": "^5.0.1", + "readable-stream": "^4.5.2", + "uuid": "^9.0.1", + "ws": "^8.16.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + } + } +} diff --git a/glv-examples/gremlin-javascript/package.json b/glv-examples/gremlin-javascript/package.json new file mode 100644 index 00000000000..e25408f3e9c --- /dev/null +++ b/glv-examples/gremlin-javascript/package.json @@ -0,0 +1,14 @@ +{ + "name": "examples", + "version": "1.0.0", + "description": "GLV example for JavaScript with Node", + "main": "connections.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "Ryan Tan", + "license": "Apache-2.0", + "dependencies": { + "gremlin": "^3.7.4" + } +} diff --git a/glv-examples/gremlin-python/basic_gremlin.py b/glv-examples/gremlin-python/basic_gremlin.py new file mode 100644 index 00000000000..256ed984416 --- /dev/null +++ b/glv-examples/gremlin-python/basic_gremlin.py @@ -0,0 +1,54 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +import sys + +sys.path.append("..") + +from gremlin_python.process.anonymous_traversal import traversal +from gremlin_python.process.strategies import * +from gremlin_python.driver.driver_remote_connection import DriverRemoteConnection + + +def main(): + rc = DriverRemoteConnection('ws://localhost:8182/gremlin', 'g') + g = traversal().with_remote(rc) + + # basic Gremlin: adding and retrieving data + v1 = g.add_v('person').property('name', 'marko').next() + v2 = g.add_v('person').property('name', 'stephen').next() + v3 = g.add_v('person').property('name', 'vadas').next() + + # be sure to use a terminating step like next() or iterate() so that the traversal "executes" + # iterate() does not return any data and is used to just generate side-effects (i.e. write data to the database) + g.V(v1).add_e('knows').to(v2).property('weight', 0.75).iterate() + g.V(v1).add_e('knows').to(v3).property('weight', 0.75).iterate() + + # retrieve the data from the "marko" vertex + marko = g.V().has('person', 'name', 'marko').values('name').next() + print("name: " + marko) + + # find the "marko" vertex and then traverse to the people he "knows" and return their data + people_marko_knows = g.V().has('person', 'name', 'marko').out('knows').values('name').to_list() + for person in people_marko_knows: + print("marko knows " + person) + + rc.close() + + +if __name__ == "__main__": + main() diff --git a/glv-examples/gremlin-python/connections.py b/glv-examples/gremlin-python/connections.py new file mode 100644 index 00000000000..f268e6c27d5 --- /dev/null +++ b/glv-examples/gremlin-python/connections.py @@ -0,0 +1,101 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +import sys + +sys.path.append("..") + +from gremlin_python.process.anonymous_traversal import traversal +from gremlin_python.process.strategies import * +from gremlin_python.driver.driver_remote_connection import DriverRemoteConnection +from gremlin_python.driver.serializer import GraphBinarySerializersV1 + + +def main(): + with_remote() + with_auth() + with_kerberos() + with_configs() + + +def with_remote(): + # connect to a remote server that is compatible with the Gremlin Server protocol. for those who + # downloaded and are using Gremlin Server directly be sure that it is running locally with: + # + # bin/gremlin-server.sh console + # + # which starts it in "console" mode with an empty in-memory TinkerGraph ready to go bound to a + # variable named "g" as referenced in the following line. + rc = DriverRemoteConnection('ws://localhost:8182/gremlin', 'g') + g = traversal().with_remote(rc) + + # drop existing vertices + g.V().drop().iterate() + + # simple query to verify connection + v = g.add_v().iterate() + count = g.V().count().next() + print("Vertex count: " + str(count)) + + # cleanup + rc.close() + + +# connecting with plain text authentication +def with_auth(): + rc = DriverRemoteConnection('ws://localhost:8182/gremlin', 'g', username='stephen', password='password') + g = traversal().with_remote(rc) + + v = g.add_v().iterate() + count = g.V().count().next() + print("Vertex count: " + str(count)) + + rc.close() + + +# connecting with Kerberos SASL authentication +def with_kerberos(): + rc = DriverRemoteConnection('ws://localhost:8182/gremlin', 'g', kerberized_service='gremlin@hostname.your.org') + g = traversal().with_remote(rc) + + v = g.add_v().iterate() + count = g.V().count().next() + print("Vertex count: " + str(count)) + + rc.close() + + +# connecting with customized configurations +def with_configs(): + rc = DriverRemoteConnection( + 'ws://localhost:8182/gremlin', 'g', + username="", password="", kerberized_service='', + message_serializer=GraphBinarySerializersV1(), graphson_reader=None, + graphson_writer=None, headers=None, session=None, + enable_user_agent_on_connect=True + ) + g = traversal().with_remote(rc) + + v = g.add_v().iterate() + count = g.V().count().next() + print("Vertex count: " + str(count)) + + rc.close() + + +if __name__ == "__main__": + main() diff --git a/glv-examples/gremlin-python/modern_traversals.py b/glv-examples/gremlin-python/modern_traversals.py new file mode 100644 index 00000000000..ae757b10b4f --- /dev/null +++ b/glv-examples/gremlin-python/modern_traversals.py @@ -0,0 +1,69 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +import sys + +sys.path.append("..") + +from gremlin_python.process.anonymous_traversal import traversal +from gremlin_python.process.graph_traversal import __ +from gremlin_python.process.strategies import * +from gremlin_python.driver.driver_remote_connection import DriverRemoteConnection +from gremlin_python.process.traversal import T +from gremlin_python.process.traversal import P + + +def main(): + # This example requires the Modern toy graph to be preloaded upon launching the Gremlin server. + # For details, see https://tinkerpop.apache.org/docs/current/reference/#gremlin-server-docker-image and use + # conf/gremlin-server-modern.yaml. + rc = DriverRemoteConnection('ws://localhost:8182/gremlin', 'g') + g = traversal().with_remote(rc) + + e1 = g.V(1).both_e().to_list() # (1) + e2 = g.V(1).both_e().where(__.other_v().has_id(2)).to_list() # (2) + v1 = g.V(1).next() + v2 = g.V(2).next() + e3 = g.V(v1).both_e().where(__.other_v().is_(v2)).to_list() # (3) + e4 = g.V(v1).out_e().where(__.in_v().is_(v2)).to_list() # (4) + e5 = g.V(1).out_e().where(__.in_v().has(T.id, P.within(2, 3))).to_list() # (5) + e6 = g.V(1).out().where(__.in_().has_id(6)).to_list() # (6) + + print("1: " + str(e1)) + print("2: " + str(e2)) + print("3: " + str(e3)) + print("4: " + str(e4)) + print("5: " + str(e5)) + print("6: " + str(e6)) + + # 1. There are three edges from the vertex with the identifier of "1". + # 2. Filter those three edges using the where()-step using the identifier of the vertex returned by other_v() to + # ensure it matches on the vertex of concern, which is the one with an identifier of "2". + # 3. Note that the same traversal will work if there are actual Vertex instances rather than just vertex + # identifiers. + # 4. The vertex with identifier "1" has all outgoing edges, so it would also be acceptable to use the directional + # steps of out_e() and in_v() since the schema allows it. + # 5. There is also no problem with filtering the terminating side of the traversal on multiple vertices, in this + # case, vertices with identifiers "2" and "3". + # 6. There’s no reason why the same pattern of exclusion used for edges with where() can’t work for a vertex + # between two vertices. + + rc.close() + + +if __name__ == "__main__": + main() diff --git a/glv-examples/gremlin-python/requirements.txt b/glv-examples/gremlin-python/requirements.txt new file mode 100644 index 00000000000..2cc382fb07f --- /dev/null +++ b/glv-examples/gremlin-python/requirements.txt @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +gremlinpython==3.7.4 diff --git a/gremlin-dotnet/Examples/BasicGremlin/BasicGremlin.csproj b/gremlin-dotnet/Examples/BasicGremlin/BasicGremlin.csproj index 3dcaf373ca0..a57cf622606 100644 --- a/gremlin-dotnet/Examples/BasicGremlin/BasicGremlin.csproj +++ b/gremlin-dotnet/Examples/BasicGremlin/BasicGremlin.csproj @@ -25,6 +25,6 @@ limitations under the License. - + diff --git a/gremlin-dotnet/Examples/Connections/Connections.csproj b/gremlin-dotnet/Examples/Connections/Connections.csproj index 3dcaf373ca0..a57cf622606 100644 --- a/gremlin-dotnet/Examples/Connections/Connections.csproj +++ b/gremlin-dotnet/Examples/Connections/Connections.csproj @@ -25,6 +25,6 @@ limitations under the License. - + diff --git a/gremlin-dotnet/Examples/ModernTraversals/ModernTraversals.csproj b/gremlin-dotnet/Examples/ModernTraversals/ModernTraversals.csproj index 4ba70d70981..5ca63e8dfa4 100644 --- a/gremlin-dotnet/Examples/ModernTraversals/ModernTraversals.csproj +++ b/gremlin-dotnet/Examples/ModernTraversals/ModernTraversals.csproj @@ -25,6 +25,6 @@ limitations under the License. - + diff --git a/gremlin-go/driver/gorillaTransporter.go b/gremlin-go/driver/gorillaTransporter.go index 85ac0326dfd..b0ac873ba48 100644 --- a/gremlin-go/driver/gorillaTransporter.go +++ b/gremlin-go/driver/gorillaTransporter.go @@ -106,7 +106,9 @@ func (transporter *gorillaTransporter) Write(data []byte) error { return err } } - if len(data) > transporter.connSettings.writeBufferSize { + // Only validate buffer size if writeBufferSize is explicitly set (> 0) + // When writeBufferSize is 0, let Gorilla WebSocket handle it with its own defaults + if transporter.connSettings.writeBufferSize > 0 && len(data) > transporter.connSettings.writeBufferSize { return newError(err1201RequestSizeExceedsWriteBufferError) } transporter.writeChannel <- data diff --git a/gremlin-go/examples/go.mod b/gremlin-go/examples/go.mod index 0fa02be0d84..b5993ebe57a 100644 --- a/gremlin-go/examples/go.mod +++ b/gremlin-go/examples/go.mod @@ -21,9 +21,11 @@ go 1.24 require github.com/apache/tinkerpop/gremlin-go/v3 v3.7.3 +replace github.com/apache/tinkerpop/gremlin-go/v3 => ../ + require ( github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect - github.com/nicksnyder/go-i18n/v2 v2.4.1 // indirect - golang.org/x/text v0.19.0 // indirect + github.com/nicksnyder/go-i18n/v2 v2.5.0 // indirect + golang.org/x/text v0.21.0 // indirect ) diff --git a/gremlin-go/examples/go.sum b/gremlin-go/examples/go.sum index 085fe9b591b..b3d1c347c84 100644 --- a/gremlin-go/examples/go.sum +++ b/gremlin-go/examples/go.sum @@ -1,22 +1,20 @@ github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= -github.com/apache/tinkerpop/gremlin-go/v3 v3.7.3 h1:QeFU7bC7p/fTo4FXl+ce7pQW3Pgx68hUQMWdnQIZlzc= -github.com/apache/tinkerpop/gremlin-go/v3 v3.7.3/go.mod h1:rMQiut0XlpFgaHLSbUgoP9QmGXjFJeXlh42Zxp4Fnno= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/nicksnyder/go-i18n/v2 v2.4.1 h1:zwzjtX4uYyiaU02K5Ia3zSkpJZrByARkRB4V3YPrr0g= -github.com/nicksnyder/go-i18n/v2 v2.4.1/go.mod h1:++Pl70FR6Cki7hdzZRnEEqdc2dJt+SAGotyFg/SvZMk= +github.com/nicksnyder/go-i18n/v2 v2.5.0 h1:3wH1gpaekcgGuwzWdSu7JwJhH9Tk87k1ezt0i1p2/Is= +github.com/nicksnyder/go-i18n/v2 v2.5.0/go.mod h1:DrhgsSDZxoAfvVrBVLXoxZn/pN5TXqaDbq7ju94viiQ= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= -golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/gremlin-javascript/examples/node/package-lock.json b/gremlin-javascript/examples/node/package-lock.json index e5fa1fed514..10574edf7d5 100644 --- a/gremlin-javascript/examples/node/package-lock.json +++ b/gremlin-javascript/examples/node/package-lock.json @@ -9,39 +9,42 @@ "version": "1.0.0", "license": "Apache-2.0", "dependencies": { - "gremlin": "^3.7.0" + "gremlin": "file:../../src/main/javascript/gremlin-javascript" } }, - "node_modules/gremlin": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/gremlin/-/gremlin-3.7.0.tgz", - "integrity": "sha512-LEjUtDEJB3ddij3VSb769b2TkLu29h30G+zrz/T9hyrnSouiOCzvgTHoMZq3wUig2O+oYLCgcPRw0iquBUoqnw==", + "../../src/main/javascript/gremlin-javascript": { + "name": "gremlin", + "version": "3.7.5-alpha1", + "license": "Apache-2.0", "dependencies": { - "ws": "^8.11.0" + "buffer": "^6.0.3", + "eventemitter3": "^5.0.1", + "readable-stream": "^4.5.2", + "uuid": "^9.0.1", + "ws": "^8.16.0" + }, + "devDependencies": { + "chai": "~4.5.0", + "chai-string": "~1.5.0", + "colors": "1.4.0", + "cross-env": "^7.0.3", + "cucumber": "~6.0.7", + "eslint": "^8.42.0", + "eslint-config-prettier": "^10.0.1", + "eslint-plugin-prettier": "^5.0.0", + "grunt": "^1.5.3", + "grunt-cli": "~1.5.0", + "grunt-jsdoc": "~2.4.1", + "mocha": "^10.2.0", + "prettier": "^3.0.0" }, "engines": { "node": ">=20" } }, - "node_modules/ws": { - "version": "8.14.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.1.tgz", - "integrity": "sha512-4OOseMUq8AzRBI/7SLMUwO+FEDnguetSk7KMb1sHwvF2w2Wv5Hoj0nlifx8vtGsftE/jWHojPy8sMMzYLJ2G/A==", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } + "node_modules/gremlin": { + "resolved": "../../src/main/javascript/gremlin-javascript", + "link": true } } } diff --git a/gremlin-javascript/examples/node/package.json b/gremlin-javascript/examples/node/package.json index d4f92289b8c..16880da7008 100644 --- a/gremlin-javascript/examples/node/package.json +++ b/gremlin-javascript/examples/node/package.json @@ -9,6 +9,6 @@ "author": "Ryan Tan", "license": "Apache-2.0", "dependencies": { - "gremlin": "^3.7.3" + "gremlin": "file:../../src/main/javascript/gremlin-javascript" } } diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/connection.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/connection.js index 8e5d1786394..deb99f13b06 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/connection.js +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/connection.js @@ -163,7 +163,13 @@ class Connection extends EventEmitter { this._ws.addEventListener('open', this.#handleOpen); this._ws.addEventListener('error', this.#handleError); - this._ws.on('unexpected-response', this.#handleUnexpectedResponse); + // Only attach unexpected-response listener if WebSocket supports .on() method + // Browser WebSocket does not have this event and .on() method + if (this._ws && 'on' in this._ws) { + // The following listener needs to use `.on` and `.off` because the `ws` package's addEventListener only accepts certain event types + // Ref: https://github.com/websockets/ws/blob/8.16.0/lib/event-target.js#L202-L241 + this._ws.on('unexpected-response', this.#handleUnexpectedResponse); + } this._ws.addEventListener('message', this.#handleMessage); this._ws.addEventListener('close', this.#handleClose); @@ -415,7 +421,13 @@ class Connection extends EventEmitter { }); this._ws.removeEventListener('open', this.#handleOpen); this._ws.removeEventListener('error', this.#handleError); - this._ws.off('unexpected-response', this.#handleUnexpectedResponse); + // Only remove unexpected-response listener for Node.js WebSocket (ws package) + // Browser WebSocket does not have this event and .off() method + if (this._ws && 'off' in this._ws) { + // The following listener needs to use `.on` and `.off` because the `ws` package's addEventListener only accepts certain event types + // Ref: https://github.com/websockets/ws/blob/8.16.0/lib/event-target.js#L202-L241 + this._ws.off('unexpected-response', this.#handleUnexpectedResponse); + } this._ws.removeEventListener('message', this.#handleMessage); this._ws.removeEventListener('close', this.#handleClose); this._openPromise = null; diff --git a/gremlin-python/src/main/python/examples/requirements.txt b/gremlin-python/src/main/python/examples/requirements.txt index 2d2674e3e19..9b1a4d3ea39 100644 --- a/gremlin-python/src/main/python/examples/requirements.txt +++ b/gremlin-python/src/main/python/examples/requirements.txt @@ -15,14 +15,4 @@ # specific language governing permissions and limitations # under the License. -aenum==3.1.15 -aiohttp==3.8.0 -aiosignal==1.3.1 -async-timeout==4.0.3 -attrs==23.2.0 -charset-normalizer==3.3.2 -frozenlist==1.4.1 -idna==3.10 -isodate==0.6.1 -multidict==6.0.5 -yarl==1.13.1 +-e ../ diff --git a/gremlin-python/src/main/python/setup.py b/gremlin-python/src/main/python/setup.py index 9bc306cb159..3fce91c278f 100644 --- a/gremlin-python/src/main/python/setup.py +++ b/gremlin-python/src/main/python/setup.py @@ -35,7 +35,7 @@ fd.write("'''") fd.write(__doc__) fd.write("'''\n") - fd.write('version = %r\n' % os.getenv('VERSION', '?').replace('-SNAPSHOT', '.dev-%d' % timestamp)) + fd.write('version = %r\n' % os.getenv('VERSION', '999.999.999.dev0').replace('-SNAPSHOT', '.dev-%d' % timestamp)) fd.write('timestamp = %d\n' % timestamp) fd.close() # Load version