From 75506b33c05687df7f7c60275290f51538a723dc Mon Sep 17 00:00:00 2001 From: Ken Hu <106191785+kenhuuu@users.noreply.github.com> Date: Wed, 1 Jul 2026 17:29:03 -0700 Subject: [PATCH] TINKERPOP-3262 Rename request "bindings" field to "parameters" Standardize on "parameter" for the gremlin-lang query parameter map across the wire (JSON/GraphBinary/GraphSON), server internals and error messages, and the public driver APIs of all five GLVs. Bounded to that one concept. "binding" is kept where it names something else, since renaming those would be wrong rather than churn: javax.script.Bindings and its ecosystem (BindingsCustomizer, script-engine and global TraversalSource bindings), where the server still hands parameters to a javax.script.Bindings for evaluation as a boundary with a foreign API; GQL pattern-match bindings in gql-gremlin; the gremlin-lang grammar's "variable" vocabulary (VariableResolver); and gremlin-core's step Parameters, disambiguated in docs as "step parameters". Assisted-by: Claude Code:claude-opus-4-8 --- CHANGELOG.asciidoc | 1 + docs/src/dev/io/graphson.asciidoc | 4 +- docs/src/dev/provider/index.asciidoc | 6 +- .../reference/gremlin-applications.asciidoc | 23 +++---- docs/src/reference/gremlin-variants.asciidoc | 6 +- docs/src/upgrade/release-4.x.x.asciidoc | 33 +++++++++ .../Driver/GremlinClientExtensions.cs | 26 +++---- .../Driver/Messages/RequestMessage.cs | 60 ++++++++-------- .../Driver/Remote/DriverRemoteConnection.cs | 2 +- .../Remote/TransactionRemoteConnection.cs | 2 +- .../src/Gremlin.Net/Driver/Tokens.cs | 4 +- .../MessageSerializerBenchmarks.cs | 2 +- .../Reference/GremlinApplicationsTests.cs | 4 +- .../Driver/GremlinClientTests.cs | 2 +- .../Driver/DriverRemoteConnectionTests.cs | 6 +- .../Driver/HttpRequestContextTests.cs | 6 +- .../Driver/Messages/RequestMessageTests.cs | 30 ++++---- .../tinkerpop/gremlin/driver/Client.java | 2 +- gremlin-go/driver/client.go | 20 +++--- gremlin-go/driver/client_test.go | 12 ++-- gremlin-go/driver/gremlinlang_test.go | 4 +- gremlin-go/driver/request.go | 6 +- gremlin-go/driver/requestOptions.go | 44 ++++++------ gremlin-go/driver/requestOptions_test.go | 48 ++++++------- gremlin-go/driver/request_test.go | 32 ++++----- .../gremlin-javascript/lib/driver/client.ts | 32 ++++----- .../lib/driver/driver-remote-connection.ts | 2 +- .../lib/driver/request-message.ts | 68 +++++++++---------- .../lib/process/transaction.ts | 4 +- .../io/binary/internals/GraphBinaryWriter.js | 6 +- .../test/integration/client-tests.js | 2 +- .../python/gremlin_python/driver/client.py | 33 +++++---- .../driver/driver_remote_connection.py | 6 +- .../python/gremlin_python/driver/request.py | 2 +- .../gremlin_python/driver/transaction.py | 4 +- .../tests/integration/driver/test_client.py | 30 ++++---- .../driver/test_driver_remote_connection.py | 2 +- .../handler/HttpGremlinEndpointHandler.java | 46 ++++++------- .../handler/HttpRequestMessageDecoder.java | 4 +- .../gremlin/server/util/GremlinError.java | 14 ++-- .../GremlinServerHttpIntegrateTest.java | 26 +++---- .../server/GremlinServerIntegrateTest.java | 14 ++-- .../server/GremlinServerSslIntegrateTest.java | 2 +- .../HttpRequestMessageDecoderTest.java | 8 +-- .../apache/tinkerpop/gremlin/util/Tokens.java | 4 +- .../gremlin/util/message/RequestMessage.java | 20 +++--- .../AbstractGraphSONMessageSerializerV4.java | 4 +- .../tinkerpop/gremlin/util/ser/SerTokens.java | 2 +- .../ser/binary/RequestMessageSerializer.java | 4 +- .../io/AbstractCompatibilityTest.java | 4 +- .../util/message/RequestMessageTest.java | 64 ++++++++--------- .../ser/binary/MessageSerializerTest.java | 2 +- 52 files changed, 410 insertions(+), 384 deletions(-) diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index 61a65871e04..1833354e01a 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -89,6 +89,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima * Updated all default Gremlin Server configs to remove Groovy dependency from initialization. * Added script engine allowlist to Gremlin Server - the `scriptEngines` YAML configuration now restricts which engines can serve requests; `gremlin-lang` is always available. * Modified request parameters from `Map` to gremlin-lang compatible `String`. +* Renamed the request `bindings` field to `parameters` across the HTTP request body, GraphBinary, and GraphSON, standardizing terminology for query parameters. * Modified HTTP API to expect gremlin-lang strings for parameters and update all GLVs to send requests in new format. * Added string parameter parsing to `GremlinServer` to prevent traversal injection and excessive nesting depths. * Modified all GLVs to detect unsupported types in `GremlinLang` and throw consistent error for that case. diff --git a/docs/src/dev/io/graphson.asciidoc b/docs/src/dev/io/graphson.asciidoc index 7b3a872d9b0..d9a66071926 100644 --- a/docs/src/dev/io/graphson.asciidoc +++ b/docs/src/dev/io/graphson.asciidoc @@ -2751,7 +2751,7 @@ The following `RequestMessage` is an example of a simple sessionless request for "@value": 1000 }, "g": "g", - "bindings": { + "parameters": { "@type": "g:Map", "@value": [ "x", @@ -2772,7 +2772,7 @@ The following `RequestMessage` is an example of a simple sessionless request for "materializeProperties": "tokens", "timeoutMs": 1000, "g": "g", - "bindings": { + "parameters": { "x": 1 }, "language": "gremlin-groovy" diff --git a/docs/src/dev/provider/index.asciidoc b/docs/src/dev/provider/index.asciidoc index 1e2c7411090..7bffb865db9 100644 --- a/docs/src/dev/provider/index.asciidoc +++ b/docs/src/dev/provider/index.asciidoc @@ -1198,7 +1198,7 @@ Gremlin-Hints: { "gremlin": string, "timeoutMs": number, - "bindings": string, + "parameters": string, "g": string, "language" : string, "materializeProperties": string, @@ -1258,7 +1258,7 @@ the serializer specified by the `Content-Type` header. The following are the key |Key |Description |Value |Required |gremlin |The Gremlin query to execute. |String containing script |Yes |timeoutMs |The maximum time a query is allowed to execute in milliseconds. |Number between 0 and 2^31-1 |No -|bindings |A gremlin-lang string that contains a map used during query execution. Its usage depends on "language". For "gremlin-groovy", these are the variable bindings. For "gremlin-lang", these are the parameter bindings. |Object (Map) |No +|parameters |A gremlin-lang string that encodes a map of key/value pairs used during query execution. Its usage depends on "language". For "gremlin-groovy", these are applied as script variable bindings. For "gremlin-lang", these are the query parameters. |String containing a gremlin-lang map literal |No |g |The name of the graph traversal source to which the query applies. Default: "g" |String containing traversal source name |No |language |The name of the ScriptEngine to use to parse the gremlin query. Default: "gremlin-lang" |String containing ScriptEngine name |No |materializeProperties |Whether to include all properties for results. One of "tokens" or "all". |String |No @@ -1270,7 +1270,7 @@ the serializer specified by the `Content-Type` header. The following are the key When Gremlin Server receives that request, it will decode it given the "mime type", and execute it using the `ScriptEngine` specified by the `language` field. In this case, it will evaluate the script `g.V(x).out()` using the -`bindings` supplied in the `args` and stream back the results in HTTP chunks. When the chunks are combined, they will +`parameters` supplied in the `args` and stream back the results in HTTP chunks. When the chunks are combined, they will form a single `ResponseMessage`. The HTTP response containing the `ResponseMessage` has the following form: [source,text] diff --git a/docs/src/reference/gremlin-applications.asciidoc b/docs/src/reference/gremlin-applications.asciidoc index eaa9950b697..77e76e1f27b 100644 --- a/docs/src/reference/gremlin-applications.asciidoc +++ b/docs/src/reference/gremlin-applications.asciidoc @@ -682,7 +682,7 @@ list = g.V().has("person","name","marko").out("knows").toList() // script client, err := NewClient("http://localhost:8182/gremlin") resultSet, err := client.SubmitWithOptions("g.V().has('person','name',name).out('knows')", - new(RequestOptionsBuilder).AddBinding("name", "marko").Create()) + new(RequestOptionsBuilder).AddParameter("name", "marko").Create()) result, err := resultSet.All() // traversal @@ -805,21 +805,14 @@ returns: `POST` is the only supported method for this endpoint. This means that `GET` with query parameters is not supported. -It is also preferred that Gremlin scripts be parameterized when possible via `bindings`: +It is also preferred that Gremlin scripts be parameterized when possible via `parameters`: [source,text] -curl -X POST -d "{\"gremlin\":\"100-x\", \"bindings\":{\"x\":1}}" "http://localhost:8182" +curl -X POST -d "{\"gremlin\":\"100-x\", \"parameters\":\"[x:1]\"}" "http://localhost:8182" -The `bindings` argument is a `Map` of variables where the keys become available as variables in the Gremlin script. -Note that parameterization of requests is critical to performance, as repeated script compilation can be avoided on -each request. - -NOTE: It is possible to pass bindings via `GET` based requests. Query string arguments prefixed with "bindings." will -be treated as parameters, where that prefix will be removed and the value following the period will become the -parameter name. In other words, `bindings.x` will create a parameter named "x" that can be referenced in the submitted -Gremlin script. The caveat is that these arguments will always be treated as `String` values. To ensure that data -types are preserved or to pass complex objects such as lists or maps, use `POST` which will at least support the -allowed JSON data types. +The `parameters` argument is a gremlin-lang string that encodes a map of key/value pairs where the keys become available +as variables in the Gremlin script. Note that parameterization of requests is critical to performance, as repeated +script compilation can be avoided on each request. NOTE: The Gremlin Server does not support link:https://en.wikipedia.org/wiki/HTTP_pipelining[HTTP pipelining]. Sending a second request on the same connection before the first response completes will cause the server to close the @@ -845,7 +838,7 @@ Finally, as Gremlin Server can host multiple `ScriptEngine` instances (e.g. `gre possible to define the language to utilize to process the request: [source,text] -curl -X POST -d "{\"gremlin\":\"100-x\", \"language\":\"gremlin-groovy\", \"bindings\":{\"x\":1}}" "http://localhost:8182" +curl -X POST -d "{\"gremlin\":\"100-x\", \"language\":\"gremlin-groovy\", \"parameters\":\"[x:1]\"}" "http://localhost:8182" By default this value is set to `gremlin-groovy`. If using a `GET` operation, this value can be set as a query string argument with by setting the `language` key. @@ -1769,7 +1762,7 @@ continuously: client = Cluster.build("localhost").port(8182).create().connect() ==>org.apache.tinkerpop.gremlin.driver.Client$ClusteredClient@42ff9a77 client.submit("while(true) { }") -org.apache.tinkerpop.gremlin.driver.exception.ResponseException: A timeout occurred during traversal evaluation of [RequestMessage{, fields={bindings={}, language=gremlin-groovy, batchSize=64}, gremlin=while(true) { }}] - consider increasing the limit given to evaluationTimeout +org.apache.tinkerpop.gremlin.driver.exception.ResponseException: A timeout occurred during traversal evaluation of [RequestMessage{, fields={parameters={}, language=gremlin-groovy, batchSize=64}, gremlin=while(true) { }}] - consider increasing the limit given to evaluationTimeout The `GroovyCompilerGremlinPlugin` has a number of configuration options: diff --git a/docs/src/reference/gremlin-variants.asciidoc b/docs/src/reference/gremlin-variants.asciidoc index 51cb6178dee..a001ce52781 100644 --- a/docs/src/reference/gremlin-variants.asciidoc +++ b/docs/src/reference/gremlin-variants.asciidoc @@ -518,14 +518,14 @@ options := new(RequestOptionsBuilder). SetEvaluationTimeout(5000). SetBatchSize(32). SetMaterializeProperties("tokens"). - AddBinding("x", 100). + AddParameter("x", 100). Create() resultSet, err := client.SubmitWithOptions("g.V(x).count()", options) ---- The following options are allowed on a per-request basis in this fashion: `batchSize`, `bulkResults`, `userAgent`, `evaluationTimeout` and `materializeProperties`. -`RequestOptions` may also contain a map of variable `bindings` to be applied to the supplied +`RequestOptions` may also contain a map of query `parameters` to be applied to the supplied traversal string. [source,go] @@ -2316,7 +2316,7 @@ for await (const item of client.stream('g.V()', null)) { } ---- -`client.stream()` accepts the same parameters as `client.submit()`: a script string, optional bindings, and optional +`client.stream()` accepts the same arguments as `client.submit()`: a script string, optional parameters, and optional per-request settings. [source,javascript] diff --git a/docs/src/upgrade/release-4.x.x.asciidoc b/docs/src/upgrade/release-4.x.x.asciidoc index 983c662e4cb..cc7dfe1cec4 100644 --- a/docs/src/upgrade/release-4.x.x.asciidoc +++ b/docs/src/upgrade/release-4.x.x.asciidoc @@ -32,6 +32,39 @@ complete list of all the modifications that are part of this release. === Upgrading for Users +==== Bindings are now Parameters + +The map of named values substituted into a Gremlin query was previously called "bindings" in some places and +"parameters" in others. TinkerPop now refers to these consistently as *query parameters*, reserving "bindings" for +the distinct concept of `ScriptEngine` variable bindings. As a result, the driver methods for supplying query +parameters have been renamed. Update any code that sets them: + +- Java: `RequestMessage.Builder.addBindings(...)` is now `addParameters(...)`. +- Python: `client.submit(..., bindings=...)` is now `submit(..., parameters=...)`, and the `request_options` +key `bindings` is now `parameters`. +- Go: `SetBindings`/`SetBindingsString`/`AddBinding` are now +`SetParameters`/`SetParametersString`/`AddParameter`. +- .NET: `AddBinding`/`AddBindings`/`AddBindingsString` are now +`AddParameter`/`AddParameters`/`AddParametersString`. +- JavaScript: `addBinding`/`addBindings`/`addBindingsString` are now +`addParameter`/`addParameters`/`addParametersString`, and the `RequestOptions.bindings` field is now `parameters`. + +For example, in the Java driver: + +[source,java] +---- +final Map params = new HashMap<>(); +params.put("x", 1); + +// 3.x +RequestMessage.build("g.V(x)").addBindings(params).create(); + +// 4.x +RequestMessage.build("g.V(x)").addParameters(params).create(); +---- + +See: link:https://issues.apache.org/jira/browse/TINKERPOP-3262[TINKERPOP-3262] + ==== Standardizing GLV Connection Options TinkerPop 4.x standardizes connection option names and defaults across all five Gremlin Language Variants (Java, Python, diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/GremlinClientExtensions.cs b/gremlin-dotnet/src/Gremlin.Net/Driver/GremlinClientExtensions.cs index 66927c5b171..da13259bb2a 100644 --- a/gremlin-dotnet/src/Gremlin.Net/Driver/GremlinClientExtensions.cs +++ b/gremlin-dotnet/src/Gremlin.Net/Driver/GremlinClientExtensions.cs @@ -34,7 +34,7 @@ namespace Gremlin.Net.Driver public static class GremlinClientExtensions { /// - /// Submits a request message that consists of a script with bindings as an asynchronous operation where only a single + /// Submits a request message that consists of a script with parameters as an asynchronous operation where only a single /// result gets returned. /// /// @@ -44,7 +44,7 @@ public static class GremlinClientExtensions /// The type of the expected result. /// The that submits the request. /// The Gremlin request script to send. - /// Bindings for parameters used in the requestScript. + /// Parameters used in the requestScript. /// The token to cancel the operation. The default value is None. /// A single result received from the Gremlin Server. /// @@ -53,10 +53,10 @@ public static class GremlinClientExtensions /// public static async Task SubmitWithSingleResultAsync(this IGremlinClient gremlinClient, string requestScript, - Dictionary? bindings = null, + Dictionary? parameters = null, CancellationToken cancellationToken = default) { - await using var resultSet = await gremlinClient.SubmitAsync(requestScript, bindings, cancellationToken) + await using var resultSet = await gremlinClient.SubmitAsync(requestScript, parameters, cancellationToken) .ConfigureAwait(false); await foreach (var item in resultSet.WithCancellation(cancellationToken).ConfigureAwait(false)) { @@ -94,12 +94,12 @@ public static class GremlinClientExtensions } /// - /// Submits a request message that consists of a script with bindings as an asynchronous operation without returning + /// Submits a request message that consists of a script with parameters as an asynchronous operation without returning /// the result received from the Gremlin Server. /// /// The that submits the request. /// The Gremlin request script to send. - /// Bindings for parameters used in the requestScript. + /// Parameters used in the requestScript. /// The token to cancel the operation. The default value is None. /// The task object representing the asynchronous operation. /// @@ -107,9 +107,9 @@ public static class GremlinClientExtensions /// that an error occurred. /// public static async Task SubmitAsync(this IGremlinClient gremlinClient, string requestScript, - Dictionary? bindings = null, CancellationToken cancellationToken = default) + Dictionary? parameters = null, CancellationToken cancellationToken = default) { - await using var resultSet = await gremlinClient.SubmitAsync(requestScript, bindings, cancellationToken).ConfigureAwait(false); + await using var resultSet = await gremlinClient.SubmitAsync(requestScript, parameters, cancellationToken).ConfigureAwait(false); // Drain the stream to ensure the background task completes and resources are released. await foreach (var _ in resultSet.WithCancellation(cancellationToken).ConfigureAwait(false)) { @@ -139,12 +139,12 @@ public static async Task SubmitAsync(this IGremlinClient gremlinClient, RequestM } /// - /// Submits a request message that consists of a script with bindings as an asynchronous operation. + /// Submits a request message that consists of a script with parameters as an asynchronous operation. /// /// The type of the expected results. /// The that submits the request. /// The Gremlin request script to send. - /// Bindings for parameters used in the requestScript. + /// Parameters used in the requestScript. /// The token to cancel the operation. The default value is None. /// A containing the data and status attributes returned from the server. /// @@ -153,12 +153,12 @@ public static async Task SubmitAsync(this IGremlinClient gremlinClient, RequestM /// public static async Task> SubmitAsync(this IGremlinClient gremlinClient, string requestScript, - Dictionary? bindings = null, + Dictionary? parameters = null, CancellationToken cancellationToken = default) { var msgBuilder = RequestMessage.Build(requestScript); - if (bindings != null) - msgBuilder.AddBindings(bindings); + if (parameters != null) + msgBuilder.AddParameters(parameters); var msg = msgBuilder.Create(); return await gremlinClient.SubmitAsync(msg, cancellationToken).ConfigureAwait(false); } diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/Messages/RequestMessage.cs b/gremlin-dotnet/src/Gremlin.Net/Driver/Messages/RequestMessage.cs index e843f43d9e4..c301adb701e 100644 --- a/gremlin-dotnet/src/Gremlin.Net/Driver/Messages/RequestMessage.cs +++ b/gremlin-dotnet/src/Gremlin.Net/Driver/Messages/RequestMessage.cs @@ -48,7 +48,7 @@ private RequestMessage(string gremlin, Dictionary fields) public string Gremlin { get; } /// - /// Gets the fields map containing language, g, bindings, and other options. + /// Gets the fields map containing language, g, parameters, and other options. /// public Dictionary Fields { get; } @@ -84,8 +84,8 @@ public class Builder { private readonly string _gremlin; private readonly Dictionary _fields = new Dictionary(); - private readonly Dictionary _bindings = new Dictionary(); - private string? _bindingsString; + private readonly Dictionary _parameters = new Dictionary(); + private string? _parametersString; internal Builder(string gremlin) { @@ -104,48 +104,48 @@ public Builder AddG(string g) } /// - /// Adds a single binding parameter. + /// Adds a single query parameter. /// - /// The binding key. - /// The binding value. + /// The parameter key. + /// The parameter value. /// The . - public Builder AddBinding(string key, object val) + public Builder AddParameter(string key, object val) { - if (_bindingsString != null) - throw new InvalidOperationException("Cannot mix AddBinding() with AddBindingsString()."); - _bindings[key] = val; + if (_parametersString != null) + throw new InvalidOperationException("Cannot mix AddParameter() with AddParametersString()."); + _parameters[key] = val; return this; } /// - /// Adds multiple binding parameters from a dictionary. The values will be + /// Adds multiple query parameters from a dictionary. The values will be /// converted to a gremlin-lang string when the message is created. - /// Cannot be mixed with . + /// Cannot be mixed with . /// - /// The bindings to add. + /// The parameters to add. /// The . - public Builder AddBindings(Dictionary bindings) + public Builder AddParameters(Dictionary parameters) { - if (_bindingsString != null) - throw new InvalidOperationException("Cannot mix AddBindings() with AddBindingsString()."); - foreach (var kvp in bindings) + if (_parametersString != null) + throw new InvalidOperationException("Cannot mix AddParameters() with AddParametersString()."); + foreach (var kvp in parameters) { - _bindings[kvp.Key] = kvp.Value; + _parameters[kvp.Key] = kvp.Value; } return this; } /// - /// Sets the bindings as a pre-serialized gremlin-lang map literal string. - /// Cannot be mixed with or . + /// Sets the query parameters as a pre-serialized gremlin-lang map literal string. + /// Cannot be mixed with or . /// - /// The gremlin-lang bindings string. + /// The gremlin-lang parameters string. /// The . - public Builder AddBindingsString(string bindingsString) + public Builder AddParametersString(string parametersString) { - if (_bindings.Count > 0) - throw new InvalidOperationException("Cannot mix AddBindingsString() with AddBinding()/AddBindings()."); - _bindingsString = bindingsString; + if (_parameters.Count > 0) + throw new InvalidOperationException("Cannot mix AddParametersString() with AddParameter()/AddParameters()."); + _parametersString = parametersString; return this; } @@ -240,14 +240,14 @@ public Builder AddLanguage(string language) /// The built . public RequestMessage Create() { - // prefer pre-serialized bindings string over raw map - if (_bindingsString != null) + // prefer pre-serialized parameters string over raw map + if (_parametersString != null) { - _fields[Tokens.ArgsBindings] = _bindingsString; + _fields[Tokens.ArgsParameters] = _parametersString; } - else if (_bindings.Count > 0) + else if (_parameters.Count > 0) { - _fields[Tokens.ArgsBindings] = GremlinLang.ConvertParametersToString(_bindings); + _fields[Tokens.ArgsParameters] = GremlinLang.ConvertParametersToString(_parameters); } return new RequestMessage(_gremlin, _fields); } diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/Remote/DriverRemoteConnection.cs b/gremlin-dotnet/src/Gremlin.Net/Driver/Remote/DriverRemoteConnection.cs index ec99053b5b1..c473260b5c9 100644 --- a/gremlin-dotnet/src/Gremlin.Net/Driver/Remote/DriverRemoteConnection.cs +++ b/gremlin-dotnet/src/Gremlin.Net/Driver/Remote/DriverRemoteConnection.cs @@ -126,7 +126,7 @@ public async Task> SubmitAsync(GremlinLan var parametersString = gremlinLang.GetParametersAsString(); if (parametersString != "[:]") { - requestMsg.AddBindingsString(parametersString); + requestMsg.AddParametersString(parametersString); } foreach (var optionsStrategy in gremlinLang.OptionsStrategies) diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/Remote/TransactionRemoteConnection.cs b/gremlin-dotnet/src/Gremlin.Net/Driver/Remote/TransactionRemoteConnection.cs index d63ec834f7d..404f4ffe00f 100644 --- a/gremlin-dotnet/src/Gremlin.Net/Driver/Remote/TransactionRemoteConnection.cs +++ b/gremlin-dotnet/src/Gremlin.Net/Driver/Remote/TransactionRemoteConnection.cs @@ -68,7 +68,7 @@ public async Task> SubmitAsync(GremlinLan var parametersString = gremlinLang.GetParametersAsString(); if (parametersString != "[:]") { - requestMsg.AddBindingsString(parametersString); + requestMsg.AddParametersString(parametersString); } foreach (var optionsStrategy in gremlinLang.OptionsStrategies) diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/Tokens.cs b/gremlin-dotnet/src/Gremlin.Net/Driver/Tokens.cs index 7f39308ec00..0f57f873800 100644 --- a/gremlin-dotnet/src/Gremlin.Net/Driver/Tokens.cs +++ b/gremlin-dotnet/src/Gremlin.Net/Driver/Tokens.cs @@ -47,10 +47,10 @@ public class Tokens public const string ArgsBatchSize = "batchSize"; /// - /// Argument name that allows definition of a map of key/value pairs to apply as variables in the + /// Argument name that allows definition of a map of key/value pairs to apply as query parameters in the /// context of the Gremlin request sent to the server. /// - public const string ArgsBindings = "bindings"; + public const string ArgsParameters = "parameters"; /// /// Argument name that corresponds to the Gremlin to evaluate. diff --git a/gremlin-dotnet/test/Gremlin.Net.Benchmarks/MessageSerializerBenchmarks.cs b/gremlin-dotnet/test/Gremlin.Net.Benchmarks/MessageSerializerBenchmarks.cs index dfbf0082db8..02510f68a93 100644 --- a/gremlin-dotnet/test/Gremlin.Net.Benchmarks/MessageSerializerBenchmarks.cs +++ b/gremlin-dotnet/test/Gremlin.Net.Benchmarks/MessageSerializerBenchmarks.cs @@ -66,7 +66,7 @@ private static GremlinLang BuildSomeGremlinLang() private static RequestMessage RequestMessageFor(GremlinLang gremlinLang) => Gremlin.Net.Driver.Messages.RequestMessage.Build(gremlinLang.GetGremlin()) .AddG("g") - .AddBindings(gremlinLang.Parameters) + .AddParameters(gremlinLang.Parameters) .Create(); private static readonly GraphBinary4MessageSerializer BinaryMessageSerializer = new(); diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinApplicationsTests.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinApplicationsTests.cs index 6851e8aa661..29954c80908 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinApplicationsTests.cs +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinApplicationsTests.cs @@ -40,14 +40,14 @@ public async Task ConnectingViaDriversTest() var gremlinServer = new GremlinServer("localhost", 8182); using (var gremlinClient = new GremlinClient(gremlinServer)) { - var bindings = new Dictionary + var parameters = new Dictionary { {"name", "marko"} }; var response = await gremlinClient.SubmitWithSingleResultAsync("g.V().has('person','name',name).out('knows')", - bindings); + parameters); } // traversal diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Driver/GremlinClientTests.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Driver/GremlinClientTests.cs index 5ae086e1390..a35f026522c 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Driver/GremlinClientTests.cs +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Driver/GremlinClientTests.cs @@ -164,7 +164,7 @@ public async Task ShouldHandleSimpleScriptWithoutErrors() } [Fact] - public async Task ShouldUseBindingsForScript() + public async Task ShouldUseParametersForScript() { var gremlinServer = new GremlinServer(TestHost, TestPort); using (var gremlinClient = new GremlinClient(gremlinServer)) diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/DriverRemoteConnectionTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/DriverRemoteConnectionTests.cs index e7ea25f6480..fd489fcf929 100644 --- a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/DriverRemoteConnectionTests.cs +++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/DriverRemoteConnectionTests.cs @@ -103,7 +103,7 @@ public async Task ShouldBuildRequestWithDefaultLanguage() } [Fact] - public async Task ShouldBuildRequestWithBindings() + public async Task ShouldBuildRequestWithParameters() { RequestMessage? capturedRequest = null; var client = CreateCapturingClient(msg => capturedRequest = msg); @@ -116,8 +116,8 @@ public async Task ShouldBuildRequestWithBindings() await connection.SubmitAsync(gl); Assert.NotNull(capturedRequest); - var bindingsString = (string)capturedRequest!.Fields[Tokens.ArgsBindings]; - Assert.Contains("\"x\":42", bindingsString); + var parametersString = (string)capturedRequest!.Fields[Tokens.ArgsParameters]; + Assert.Contains("\"x\":42", parametersString); } [Fact] diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/HttpRequestContextTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/HttpRequestContextTests.cs index 10522026445..05bcf870f20 100644 --- a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/HttpRequestContextTests.cs +++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/HttpRequestContextTests.cs @@ -278,10 +278,10 @@ public void SerializeBodyShouldReflectBodyReplacement() } [Fact] - public void SerializeBodyShouldIncludeBindingsField() + public void SerializeBodyShouldIncludeParametersField() { var message = RequestMessage.Build("g.V(x)") - .AddBindingsString("[x:1,y:'marko']") + .AddParametersString("[x:1,y:'marko']") .Create(); var context = new HttpRequestContext("POST", new Uri("http://localhost:8182/gremlin"), new Dictionary(), message); @@ -289,7 +289,7 @@ public void SerializeBodyShouldIncludeBindingsField() var result = context.SerializeBody(); var json = JsonDocument.Parse(result); - Assert.Equal("[x:1,y:'marko']", json.RootElement.GetProperty("bindings").GetString()); + Assert.Equal("[x:1,y:'marko']", json.RootElement.GetProperty("parameters").GetString()); } #endregion diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/Messages/RequestMessageTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/Messages/RequestMessageTests.cs index 4d669841b56..29a6ac0ff46 100644 --- a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/Messages/RequestMessageTests.cs +++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/Messages/RequestMessageTests.cs @@ -55,27 +55,27 @@ public void ShouldSetGField() } [Fact] - public void ShouldSetBindings() + public void ShouldSetParameters() { var msg = RequestMessage.Build("g.V(x)") - .AddBinding("x", 1) + .AddParameter("x", 1) .Create(); - var bindingsString = (string)msg.Fields[Tokens.ArgsBindings]; - Assert.Contains("\"x\":1", bindingsString); + var parametersString = (string)msg.Fields[Tokens.ArgsParameters]; + Assert.Contains("\"x\":1", parametersString); } [Fact] - public void ShouldSetMultipleBindings() + public void ShouldSetMultipleParameters() { - var bindings = new Dictionary { { "x", 1 }, { "name", "test" } }; + var parameters = new Dictionary { { "x", 1 }, { "name", "test" } }; var msg = RequestMessage.Build("g.V(x).has(name)") - .AddBindings(bindings) + .AddParameters(parameters) .Create(); - var bindingsString = (string)msg.Fields[Tokens.ArgsBindings]; - Assert.Contains("\"x\":1", bindingsString); - Assert.Contains("\"name\":\"test\"", bindingsString); + var parametersString = (string)msg.Fields[Tokens.ArgsParameters]; + Assert.Contains("\"x\":1", parametersString); + Assert.Contains("\"name\":\"test\"", parametersString); } [Fact] @@ -99,21 +99,21 @@ public void ShouldReportHasField() } [Fact] - public void ShouldNotContainBindingsWhenNoneAdded() + public void ShouldNotContainParametersWhenNoneAdded() { var msg = RequestMessage.Build("g.V()").Create(); - Assert.False(msg.Fields.ContainsKey(Tokens.ArgsBindings)); + Assert.False(msg.Fields.ContainsKey(Tokens.ArgsParameters)); } [Fact] - public void ShouldSetBindingsString() + public void ShouldSetParametersString() { var msg = RequestMessage.Build("g.V(x)") - .AddBindingsString("[\"x\":1]") + .AddParametersString("[\"x\":1]") .Create(); - Assert.Equal("[\"x\":1]", msg.Fields[Tokens.ArgsBindings]); + Assert.Equal("[\"x\":1]", msg.Fields[Tokens.ArgsParameters]); } } } diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Client.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Client.java index a8b1b49ad69..00c1037cda2 100644 --- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Client.java +++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Client.java @@ -235,7 +235,7 @@ public CompletableFuture submitAsync(final String gremlin, final Requ // apply settings if they were made available options.getTimeout().ifPresent(timeout -> request.addTimeoutMillis(timeout)); - options.getParameters().ifPresent(params -> request.addBindings(params)); + options.getParameters().ifPresent(params -> request.addParameters(params)); options.getG().ifPresent(g -> request.addG(g)); options.getLanguage().ifPresent(lang -> request.addLanguage(lang)); options.getMaterializeProperties().ifPresent(mp -> request.addMaterializeProperties(mp)); diff --git a/gremlin-go/driver/client.go b/gremlin-go/driver/client.go index 08eb7760aad..80e400a25df 100644 --- a/gremlin-go/driver/client.go +++ b/gremlin-go/driver/client.go @@ -273,13 +273,13 @@ func (client *Client) SubmitWithOptions(traversalString string, requestOptions R return rs, err } -// Submit submits a Gremlin script to the server and returns a ResultSet. Submit can optionally accept a map of bindings -// to be applied to the traversalString, it is preferred however to instead wrap any bindings into a RequestOptions +// Submit submits a Gremlin script to the server and returns a ResultSet. Submit can optionally accept a map of parameters +// to be applied to the traversalString, it is preferred however to instead wrap any parameters into a RequestOptions // struct and use SubmitWithOptions(). -func (client *Client) Submit(traversalString string, bindings ...map[string]interface{}) (ResultSet, error) { +func (client *Client) Submit(traversalString string, parameters ...map[string]interface{}) (ResultSet, error) { requestOptionsBuilder := new(RequestOptionsBuilder) - if len(bindings) > 0 { - requestOptionsBuilder.SetBindings(bindings[0]) + if len(parameters) > 0 { + requestOptionsBuilder.SetParameters(parameters[0]) } return client.SubmitWithOptions(traversalString, requestOptionsBuilder.Create()) } @@ -289,7 +289,7 @@ func (client *Client) submitGremlinLang(gremlinLang *GremlinLang) (ResultSet, er return client.submitGremlinLangWithBuilder(gremlinLang, new(RequestOptionsBuilder)) } -// submitGremlinLangWithBuilder is the core submission function. It extracts bindings +// submitGremlinLangWithBuilder is the core submission function. It extracts parameters // and options strategies from the GremlinLang, merges them into the provided builder, // then builds and sends the request. func (client *Client) submitGremlinLangWithBuilder(gremlinLang *GremlinLang, builder *RequestOptionsBuilder) (ResultSet, error) { @@ -297,7 +297,7 @@ func (client *Client) submitGremlinLangWithBuilder(gremlinLang *GremlinLang, bui parametersString := gremlinLang.GetParametersAsString() if parametersString != "[:]" { - builder.SetBindingsString(parametersString) + builder.SetParametersString(parametersString) } if len(gremlinLang.optionsStrategies) > 0 { @@ -320,9 +320,9 @@ func applyOptionsConfig(builder *RequestOptionsBuilder, config map[string]interf builderValue := reflect.ValueOf(builder) // Map configuration keys to setter method names. - // "bindings" is intentionally excluded because bindings are handled separately - // via SetBindingsString in submitGremlinLang, and including it here would - // trigger the mutual exclusion panic between SetBindings and SetBindingsString. + // "parameters" is intentionally excluded because parameters are handled separately + // via SetParametersString in submitGremlinLang, and including it here would + // trigger the mutual exclusion panic between SetParameters and SetParametersString. setterMap := map[string]string{ "evaluationTimeout": "SetEvaluationTimeout", "batchSize": "SetBatchSize", diff --git a/gremlin-go/driver/client_test.go b/gremlin-go/driver/client_test.go index db3c7d6091a..73aff14a880 100644 --- a/gremlin-go/driver/client_test.go +++ b/gremlin-go/driver/client_test.go @@ -89,7 +89,7 @@ func TestClient(t *testing.T) { AssertMarkoVertexWithProperties(t, result) }) - t.Run("Test client.Submit() with bindings", func(t *testing.T) { + t.Run("Test client.Submit() with parameters", func(t *testing.T) { skipTestsIfNotEnabled(t, integrationTestSuiteName, testNoAuthEnable) client, err := NewClient(testNoAuthUrl, func(settings *ClientSettings) { @@ -100,9 +100,9 @@ func TestClient(t *testing.T) { assert.NotNil(t, client) defer client.Close() - bindings := map[string]interface{}{"x": 1} + parameters := map[string]interface{}{"x": 1} - resultSet, err := client.Submit("g.V(x).values(\"name\")", bindings) + resultSet, err := client.Submit("g.V(x).values(\"name\")", parameters) assert.NoError(t, err) assert.NotNil(t, resultSet) @@ -113,7 +113,7 @@ func TestClient(t *testing.T) { assert.Equal(t, "marko", result.Data) }) - t.Run("Test client.SubmitWithOptions() with bindings", func(t *testing.T) { + t.Run("Test client.SubmitWithOptions() with parameters", func(t *testing.T) { skipTestsIfNotEnabled(t, integrationTestSuiteName, testNoAuthEnable) client, err := NewClient(testNoAuthUrl, func(settings *ClientSettings) { @@ -124,9 +124,9 @@ func TestClient(t *testing.T) { assert.NotNil(t, client) defer client.Close() - bindings := map[string]interface{}{"x": 1} + parameters := map[string]interface{}{"x": 1} - resultSet, err := client.SubmitWithOptions("g.V(x).values(\"name\")", new(RequestOptionsBuilder).SetBindings(bindings).Create()) + resultSet, err := client.SubmitWithOptions("g.V(x).values(\"name\")", new(RequestOptionsBuilder).SetParameters(parameters).Create()) assert.NoError(t, err) assert.NotNil(t, resultSet) diff --git a/gremlin-go/driver/gremlinlang_test.go b/gremlin-go/driver/gremlinlang_test.go index 496ae4228f9..f15607ad20d 100644 --- a/gremlin-go/driver/gremlinlang_test.go +++ b/gremlin-go/driver/gremlinlang_test.go @@ -881,10 +881,10 @@ func Test_ConvertParametersToString(t *testing.T) { t.Run("should panic on unsupported type via RequestOptionsBuilder.Create()", func(t *testing.T) { defer func() { if r := recover(); r == nil { - t.Error("expected panic for unsupported type in bindings") + t.Error("expected panic for unsupported type in parameters") } }() - new(RequestOptionsBuilder).SetBindings(map[string]interface{}{"x": struct{}{}}).Create() + new(RequestOptionsBuilder).SetParameters(map[string]interface{}{"x": struct{}{}}).Create() }) } diff --git a/gremlin-go/driver/request.go b/gremlin-go/driver/request.go index ebf375d49bf..402e816e099 100644 --- a/gremlin-go/driver/request.go +++ b/gremlin-go/driver/request.go @@ -34,7 +34,7 @@ type RequestMessage struct { // Parameters: // - stringGremlin: The Gremlin query string to execute // - traversalSource: The name of the traversal source (typically "g") -// - requestOptions: Options such as bindings, timeout, batch size, etc. +// - requestOptions: Options such as parameters, timeout, batch size, etc. // // Returns: // - request: A request structure ready for serialization @@ -52,8 +52,8 @@ func MakeStringRequest(stringGremlin string, traversalSource string, requestOpti "g": traversalSource, } - if requestOptions.bindingsString != "" && requestOptions.bindingsString != "[:]" { - newFields["bindings"] = requestOptions.bindingsString + if requestOptions.parametersString != "" && requestOptions.parametersString != "[:]" { + newFields["parameters"] = requestOptions.parametersString } if requestOptions.evaluationTimeout != 0 { diff --git a/gremlin-go/driver/requestOptions.go b/gremlin-go/driver/requestOptions.go index 53863276d92..b419d13c1a1 100644 --- a/gremlin-go/driver/requestOptions.go +++ b/gremlin-go/driver/requestOptions.go @@ -23,7 +23,7 @@ type RequestOptions struct { evaluationTimeout int batchSize int userAgent string - bindingsString string + parametersString string materializeProperties string bulkResults *bool transactionId string @@ -33,8 +33,8 @@ type RequestOptionsBuilder struct { evaluationTimeout int batchSize int userAgent string - bindings map[string]interface{} - bindingsString string + parameters map[string]interface{} + parametersString string materializeProperties string bulkResults *bool transactionId string @@ -55,19 +55,19 @@ func (builder *RequestOptionsBuilder) SetUserAgent(userAgent string) *RequestOpt return builder } -func (builder *RequestOptionsBuilder) SetBindings(bindings map[string]interface{}) *RequestOptionsBuilder { - if builder.bindingsString != "" { - panic("cannot mix SetBindings() with SetBindingsString()") +func (builder *RequestOptionsBuilder) SetParameters(parameters map[string]interface{}) *RequestOptionsBuilder { + if builder.parametersString != "" { + panic("cannot mix SetParameters() with SetParametersString()") } - builder.bindings = bindings + builder.parameters = parameters return builder } -func (builder *RequestOptionsBuilder) SetBindingsString(bindingsString string) *RequestOptionsBuilder { - if builder.bindings != nil { - panic("cannot mix SetBindingsString() with SetBindings()") +func (builder *RequestOptionsBuilder) SetParametersString(parametersString string) *RequestOptionsBuilder { + if builder.parameters != nil { + panic("cannot mix SetParametersString() with SetParameters()") } - builder.bindingsString = bindingsString + builder.parametersString = parametersString return builder } @@ -86,14 +86,14 @@ func (builder *RequestOptionsBuilder) SetTransactionId(transactionId string) *Re return builder } -func (builder *RequestOptionsBuilder) AddBinding(key string, binding interface{}) *RequestOptionsBuilder { - if builder.bindingsString != "" { - panic("cannot mix AddBinding() with SetBindingsString()") +func (builder *RequestOptionsBuilder) AddParameter(key string, parameter interface{}) *RequestOptionsBuilder { + if builder.parametersString != "" { + panic("cannot mix AddParameter() with SetParametersString()") } - if builder.bindings == nil { - builder.bindings = make(map[string]interface{}) + if builder.parameters == nil { + builder.parameters = make(map[string]interface{}) } - builder.bindings[key] = binding + builder.parameters[key] = parameter return builder } @@ -107,11 +107,11 @@ func (builder *RequestOptionsBuilder) Create() RequestOptions { requestOptions.bulkResults = builder.bulkResults requestOptions.transactionId = builder.transactionId - // convert map bindings to string at creation time, matching Java's RequestOptions.Builder.create() - if builder.bindingsString != "" { - requestOptions.bindingsString = builder.bindingsString - } else if builder.bindings != nil { - requestOptions.bindingsString = ConvertParametersToString(builder.bindings) + // convert map parameters to string at creation time, matching Java's RequestOptions.Builder.create() + if builder.parametersString != "" { + requestOptions.parametersString = builder.parametersString + } else if builder.parameters != nil { + requestOptions.parametersString = ConvertParametersToString(builder.parameters) } return *requestOptions diff --git a/gremlin-go/driver/requestOptions_test.go b/gremlin-go/driver/requestOptions_test.go index 851e4d02e1a..f8e7213de1b 100644 --- a/gremlin-go/driver/requestOptions_test.go +++ b/gremlin-go/driver/requestOptions_test.go @@ -42,33 +42,33 @@ func TestRequestOptions(t *testing.T) { r := new(RequestOptionsBuilder).SetMaterializeProperties("TestMaterializeProperties").Create() assert.Equal(t, "TestMaterializeProperties", r.materializeProperties) }) - t.Run("Test RequestOptionsBuilder with custom bindings", func(t *testing.T) { - bindings := map[string]interface{}{"x": int32(2), "y": int32(5)} - r := new(RequestOptionsBuilder).SetBindings(bindings).Create() - assert.Contains(t, r.bindingsString, "\"x\":2") - assert.Contains(t, r.bindingsString, "\"y\":5") + t.Run("Test RequestOptionsBuilder with custom parameters", func(t *testing.T) { + parameters := map[string]interface{}{"x": int32(2), "y": int32(5)} + r := new(RequestOptionsBuilder).SetParameters(parameters).Create() + assert.Contains(t, r.parametersString, "\"x\":2") + assert.Contains(t, r.parametersString, "\"y\":5") }) - t.Run("Test RequestOptionsBuilder AddBinding() with no other bindings", func(t *testing.T) { - r := new(RequestOptionsBuilder).AddBinding("x", int32(2)).AddBinding("y", int32(5)).Create() - assert.Contains(t, r.bindingsString, "\"x\":2") - assert.Contains(t, r.bindingsString, "\"y\":5") + t.Run("Test RequestOptionsBuilder AddParameter() with no other parameters", func(t *testing.T) { + r := new(RequestOptionsBuilder).AddParameter("x", int32(2)).AddParameter("y", int32(5)).Create() + assert.Contains(t, r.parametersString, "\"x\":2") + assert.Contains(t, r.parametersString, "\"y\":5") }) - t.Run("Test RequestOptionsBuilder AddBinding() overwriting existing key", func(t *testing.T) { - r := new(RequestOptionsBuilder).AddBinding("x", int32(2)).AddBinding("x", int32(5)).Create() - assert.Contains(t, r.bindingsString, "\"x\":5") + t.Run("Test RequestOptionsBuilder AddParameter() overwriting existing key", func(t *testing.T) { + r := new(RequestOptionsBuilder).AddParameter("x", int32(2)).AddParameter("x", int32(5)).Create() + assert.Contains(t, r.parametersString, "\"x\":5") }) - t.Run("Test RequestOptionsBuilder AddBinding() with existing bindings", func(t *testing.T) { - bindings := map[string]interface{}{"x": int32(2), "y": int32(5)} - r := new(RequestOptionsBuilder).SetBindings(bindings).AddBinding("z", int32(7)).Create() - assert.Contains(t, r.bindingsString, "\"x\":2") - assert.Contains(t, r.bindingsString, "\"y\":5") - assert.Contains(t, r.bindingsString, "\"z\":7") + t.Run("Test RequestOptionsBuilder AddParameter() with existing parameters", func(t *testing.T) { + parameters := map[string]interface{}{"x": int32(2), "y": int32(5)} + r := new(RequestOptionsBuilder).SetParameters(parameters).AddParameter("z", int32(7)).Create() + assert.Contains(t, r.parametersString, "\"x\":2") + assert.Contains(t, r.parametersString, "\"y\":5") + assert.Contains(t, r.parametersString, "\"z\":7") }) - t.Run("Test RequestOptionsBuilder SetBindings resets previous bindings", func(t *testing.T) { - bindings1 := map[string]interface{}{"x": int32(2)} - bindings2 := map[string]interface{}{"z": int32(7)} - r := new(RequestOptionsBuilder).SetBindings(bindings1).SetBindings(bindings2).Create() - assert.Contains(t, r.bindingsString, "\"z\":7") - assert.NotContains(t, r.bindingsString, "\"x\"") + t.Run("Test RequestOptionsBuilder SetParameters resets previous parameters", func(t *testing.T) { + parameters1 := map[string]interface{}{"x": int32(2)} + parameters2 := map[string]interface{}{"z": int32(7)} + r := new(RequestOptionsBuilder).SetParameters(parameters1).SetParameters(parameters2).Create() + assert.Contains(t, r.parametersString, "\"z\":7") + assert.NotContains(t, r.parametersString, "\"x\"") }) } diff --git a/gremlin-go/driver/request_test.go b/gremlin-go/driver/request_test.go index f1752b0f6c7..a738d627a69 100644 --- a/gremlin-go/driver/request_test.go +++ b/gremlin-go/driver/request_test.go @@ -26,12 +26,12 @@ import ( ) func TestRequest(t *testing.T) { - t.Run("Test makeStringRequest() with no bindings", func(t *testing.T) { + t.Run("Test makeStringRequest() with no parameters", func(t *testing.T) { r := MakeStringRequest("g.V()", "g", *new(RequestOptions)) assert.Equal(t, "g.V()", r.Gremlin) assert.Equal(t, "g", r.Fields["g"]) assert.Equal(t, "gremlin-lang", r.Fields["language"]) - assert.Nil(t, r.Fields["bindings"]) + assert.Nil(t, r.Fields["parameters"]) }) t.Run("Test makeStringRequest() with custom evaluationTimeout", func(t *testing.T) { @@ -58,32 +58,32 @@ func TestRequest(t *testing.T) { assert.Equal(t, true, r.Fields["bulkResults"]) }) - t.Run("Test makeStringRequest() with string bindings", func(t *testing.T) { + t.Run("Test makeStringRequest() with string parameters", func(t *testing.T) { r := MakeStringRequest("g.V(x)", "g", - new(RequestOptionsBuilder).SetBindingsString("[\"x\":1]").Create()) - assert.Equal(t, "[\"x\":1]", r.Fields["bindings"]) + new(RequestOptionsBuilder).SetParametersString("[\"x\":1]").Create()) + assert.Equal(t, "[\"x\":1]", r.Fields["parameters"]) }) - t.Run("Test makeStringRequest() with map bindings converted to string", func(t *testing.T) { + t.Run("Test makeStringRequest() with map parameters converted to string", func(t *testing.T) { r := MakeStringRequest("g.V(x)", "g", - new(RequestOptionsBuilder).SetBindings(map[string]interface{}{"x": int32(1)}).Create()) - assert.Contains(t, r.Fields["bindings"], "\"x\":1") + new(RequestOptionsBuilder).SetParameters(map[string]interface{}{"x": int32(1)}).Create()) + assert.Contains(t, r.Fields["parameters"], "\"x\":1") }) - t.Run("Test RequestOptionsBuilder.Create() converts map bindings to string", func(t *testing.T) { - opts := new(RequestOptionsBuilder).SetBindings(map[string]interface{}{"x": int32(1)}).Create() - assert.NotEmpty(t, opts.bindingsString) - assert.Contains(t, opts.bindingsString, "\"x\":1") + t.Run("Test RequestOptionsBuilder.Create() converts map parameters to string", func(t *testing.T) { + opts := new(RequestOptionsBuilder).SetParameters(map[string]interface{}{"x": int32(1)}).Create() + assert.NotEmpty(t, opts.parametersString) + assert.Contains(t, opts.parametersString, "\"x\":1") }) - t.Run("Test RequestOptionsBuilder rejects mixing SetBindings and SetBindingsString", func(t *testing.T) { + t.Run("Test RequestOptionsBuilder rejects mixing SetParameters and SetParametersString", func(t *testing.T) { defer func() { if r := recover(); r == nil { - t.Error("expected panic when mixing SetBindings and SetBindingsString") + t.Error("expected panic when mixing SetParameters and SetParametersString") } }() new(RequestOptionsBuilder). - SetBindings(map[string]interface{}{"x": int32(1)}). - SetBindingsString("[\"y\":2]") + SetParameters(map[string]interface{}{"x": int32(1)}). + SetParametersString("[\"y\":2]") }) } diff --git a/gremlin-js/gremlin-javascript/lib/driver/client.ts b/gremlin-js/gremlin-javascript/lib/driver/client.ts index b13493b208e..131e7ae8d68 100644 --- a/gremlin-js/gremlin-javascript/lib/driver/client.ts +++ b/gremlin-js/gremlin-javascript/lib/driver/client.ts @@ -22,7 +22,7 @@ import {RequestMessage} from "./request-message.js"; import { Transaction } from '../process/transaction.js'; export type RequestOptions = { - bindings?: any; + parameters?: any; language?: string; accept?: string; evaluationTimeout?: number; @@ -78,12 +78,12 @@ export default class Client { /** * Send a request to the Gremlin Server and buffer the entire response. * @param {string} message The script to send - * @param {Object|null} [bindings] The script bindings, if any. + * @param {Object|null} [parameters] The query parameters, if any. * @param {RequestOptions} [requestOptions] Configuration specific to the current request. * @returns {Promise} */ - submit(message: string, bindings: any | null, requestOptions?: RequestOptions): Promise { - return this._connection.submit(this.#buildRequest(message, bindings, requestOptions)); + submit(message: string, parameters: any | null, requestOptions?: RequestOptions): Promise { + return this._connection.submit(this.#buildRequest(message, parameters, requestOptions)); } /** @@ -91,33 +91,33 @@ export default class Client { * Returns an AsyncGenerator that yields individual result items as they are * deserialized from the response. For bulked responses, yields Traverser objects. * @param {string} message The script to send - * @param {Object|null} [bindings] The script bindings, if any. + * @param {Object|null} [parameters] The query parameters, if any. * @param {RequestOptions} [requestOptions] Configuration specific to the current request. * @returns {AsyncGenerator} */ - async *stream(message: string, bindings: any | null, requestOptions?: RequestOptions): AsyncGenerator { - return yield* this._connection.stream(this.#buildRequest(message, bindings, requestOptions)); + async *stream(message: string, parameters: any | null, requestOptions?: RequestOptions): AsyncGenerator { + return yield* this._connection.stream(this.#buildRequest(message, parameters, requestOptions)); } - #buildRequest(message: string, bindings: any | null, requestOptions?: RequestOptions): RequestMessage { + #buildRequest(message: string, parameters: any | null, requestOptions?: RequestOptions): RequestMessage { const requestBuilder = RequestMessage.build(message) .addG(this.options.traversalSource || 'g'); if (requestOptions?.language) { requestBuilder.addLanguage(requestOptions.language); } - if (requestOptions?.bindings) { - if (typeof requestOptions.bindings === 'string') { - requestBuilder.addBindingsString(requestOptions.bindings); + if (requestOptions?.parameters) { + if (typeof requestOptions.parameters === 'string') { + requestBuilder.addParametersString(requestOptions.parameters); } else { - requestBuilder.addBindings(requestOptions.bindings); + requestBuilder.addParameters(requestOptions.parameters); } } - if (bindings) { - if (typeof bindings === 'string') { - requestBuilder.addBindingsString(bindings); + if (parameters) { + if (typeof parameters === 'string') { + requestBuilder.addParametersString(parameters); } else { - requestBuilder.addBindings(bindings); + requestBuilder.addParameters(parameters); } } if (requestOptions?.materializeProperties) { diff --git a/gremlin-js/gremlin-javascript/lib/driver/driver-remote-connection.ts b/gremlin-js/gremlin-javascript/lib/driver/driver-remote-connection.ts index 78caf3bec89..06e2f8c6490 100644 --- a/gremlin-js/gremlin-javascript/lib/driver/driver-remote-connection.ts +++ b/gremlin-js/gremlin-javascript/lib/driver/driver-remote-connection.ts @@ -109,7 +109,7 @@ export default class DriverRemoteConnection extends RemoteConnection { const parametersString = gremlinLang.getParametersAsString(); if (parametersString !== '[:]') { - requestOptions.bindings = parametersString; + requestOptions.parameters = parametersString; } // If this connection is bound to a transaction, attach the transactionId diff --git a/gremlin-js/gremlin-javascript/lib/driver/request-message.ts b/gremlin-js/gremlin-javascript/lib/driver/request-message.ts index 29dc55219c6..9064b524b0f 100644 --- a/gremlin-js/gremlin-javascript/lib/driver/request-message.ts +++ b/gremlin-js/gremlin-javascript/lib/driver/request-message.ts @@ -22,7 +22,7 @@ import GremlinLang from '../process/gremlin-lang.js'; // Token constants const Tokens = { ARGS_LANGUAGE: 'language', - ARGS_BINDINGS: 'bindings', + ARGS_PARAMETERS: 'parameters', ARGS_G: 'g', ARGS_MATERIALIZE_PROPERTIES: 'materializeProperties', TIMEOUT_MS: 'timeoutMs', @@ -39,7 +39,7 @@ export class RequestMessage { private gremlin: string; private language: string; private timeoutMs?: number; - private bindings?: object; + private parameters?: object; private g?: string; private materializeProperties?: string; private bulkResults?: boolean; @@ -50,7 +50,7 @@ export class RequestMessage { gremlin: string, language: string, timeoutMs: number | undefined, - bindings: object | undefined, + parameters: object | undefined, g: string | undefined, materializeProperties: string | undefined, bulkResults: boolean | undefined, @@ -64,7 +64,7 @@ export class RequestMessage { this.gremlin = gremlin; this.language = language; this.timeoutMs = timeoutMs; - this.bindings = bindings; + this.parameters = parameters; this.g = g; this.materializeProperties = materializeProperties; this.bulkResults = bulkResults; @@ -84,8 +84,8 @@ export class RequestMessage { return this.timeoutMs; } - getBindings(): object | undefined { - return this.bindings; + getParameters(): object | undefined { + return this.parameters; } getG(): string | undefined { @@ -125,8 +125,8 @@ export class RequestMessage { if (this.g) { payload['g'] = this.g; } - if (this.bindings !== undefined) { - payload['bindings'] = this.bindings; + if (this.parameters !== undefined) { + payload['parameters'] = this.parameters; } if (this.timeoutMs !== undefined) { payload['timeoutMs'] = this.timeoutMs; @@ -159,8 +159,8 @@ export class RequestMessage { */ export class Builder { private readonly gremlin: string; - private readonly bindings = {}; - private bindingsString?: string; + private readonly parameters = {}; + private parametersString?: string; public language: string; public timeoutMs?: number; public g?: string; @@ -181,36 +181,36 @@ export class Builder { } /** - * Adds a single binding parameter. The accumulated bindings map is converted to a gremlin-lang + * Adds a single query parameter. The accumulated parameters map is converted to a gremlin-lang * map literal string when the message is created. - * Cannot be mixed with {@link addBindingsString}. + * Cannot be mixed with {@link addParametersString}. */ - addBinding(key: string, value: any): Builder { - if (this.bindingsString) throw new Error('Cannot mix addBinding() with addBindingsString().'); - Object.assign(this.bindings, {[key]: value}) + addParameter(key: string, value: any): Builder { + if (this.parametersString) throw new Error('Cannot mix addParameter() with addParametersString().'); + Object.assign(this.parameters, {[key]: value}) return this; } /** - * Merges the provided bindings into the accumulated bindings map. The values are converted to a + * Merges the provided parameters into the accumulated parameters map. The values are converted to a * gremlin-lang map literal string when the message is created. - * Cannot be mixed with {@link addBindingsString}. + * Cannot be mixed with {@link addParametersString}. */ - addBindings(otherBindings: object): Builder { - if (!otherBindings) throw new Error('bindings argument cannot be null.'); - if (this.bindingsString) throw new Error('Cannot mix addBindings() with addBindingsString().'); - Object.assign(this.bindings, otherBindings) + addParameters(otherParameters: object): Builder { + if (!otherParameters) throw new Error('parameters argument cannot be null.'); + if (this.parametersString) throw new Error('Cannot mix addParameters() with addParametersString().'); + Object.assign(this.parameters, otherParameters) return this; } /** - * Sets the bindings as a pre-formatted gremlin-lang map literal string (e.g. `'["x":1,"y":"knows"]'`). - * Calling this method replaces any previously set bindings string (last-one-wins). - * Cannot be mixed with {@link addBinding} or {@link addBindings}. + * Sets the query parameters as a pre-formatted gremlin-lang map literal string (e.g. `'["x":1,"y":"knows"]'`). + * Calling this method replaces any previously set parameters string (last-one-wins). + * Cannot be mixed with {@link addParameter} or {@link addParameters}. */ - addBindingsString(bindingsString: string): Builder { - if (Object.keys(this.bindings).length > 0) throw new Error('Cannot mix addBindingsString() with addBinding()/addBindings().'); - this.bindingsString = bindingsString; + addParametersString(parametersString: string): Builder { + if (Object.keys(this.parameters).length > 0) throw new Error('Cannot mix addParametersString() with addParameter()/addParameters().'); + this.parametersString = parametersString; return this; } @@ -257,20 +257,20 @@ export class Builder { * Create the request message given the settings provided to the Builder. */ create(): RequestMessage { - // mutual exclusion between addBindings/addBinding and addBindingsString is + // mutual exclusion between addParameters/addParameter and addParametersString is // enforced at call time, so only one path can be set here - let bindings: string | undefined; - if (this.bindingsString) { - bindings = this.bindingsString; - } else if (Object.keys(this.bindings).length > 0) { - bindings = GremlinLang.convertParametersToString(new Map(Object.entries(this.bindings))); + let parameters: string | undefined; + if (this.parametersString) { + parameters = this.parametersString; + } else if (Object.keys(this.parameters).length > 0) { + parameters = GremlinLang.convertParametersToString(new Map(Object.entries(this.parameters))); } // @ts-ignore - accessing private constructor from Builder return new RequestMessage( this.gremlin, this.language || 'gremlin-lang', this.timeoutMs, - bindings, + parameters, this.g, this.materializeProperties, this.bulkResults, diff --git a/gremlin-js/gremlin-javascript/lib/process/transaction.ts b/gremlin-js/gremlin-javascript/lib/process/transaction.ts index 57b77022b27..0ce89842277 100644 --- a/gremlin-js/gremlin-javascript/lib/process/transaction.ts +++ b/gremlin-js/gremlin-javascript/lib/process/transaction.ts @@ -160,7 +160,7 @@ export class Transaction { * Submits a gremlin-lang string within this transaction. The transactionId * is automatically attached. Has the same signature as Client.submit(). */ - async submit(gremlin: string, bindings?: any, requestOptions?: any): Promise { + async submit(gremlin: string, parameters?: any, requestOptions?: any): Promise { if (!this._isOpen) { throw new Error('Transaction is not open'); } @@ -168,7 +168,7 @@ export class Transaction { ...requestOptions, transactionId: this._transactionId, }; - return this._client.submit(gremlin, bindings || null, opts); + return this._client.submit(gremlin, parameters || null, opts); } async #closeTransaction(script: string): Promise { diff --git a/gremlin-js/gremlin-javascript/lib/structure/io/binary/internals/GraphBinaryWriter.js b/gremlin-js/gremlin-javascript/lib/structure/io/binary/internals/GraphBinaryWriter.js index 5a9cae0db8a..d9a1d8f7927 100644 --- a/gremlin-js/gremlin-javascript/lib/structure/io/binary/internals/GraphBinaryWriter.js +++ b/gremlin-js/gremlin-javascript/lib/structure/io/binary/internals/GraphBinaryWriter.js @@ -48,9 +48,9 @@ export default class GraphBinaryWriter { if (g) { fields.set('g', g); } - const bindings = requestMessage.getBindings(); - if (bindings && Object.keys(bindings).length > 0) { - fields.set('bindings', bindings); + const parameters = requestMessage.getParameters(); + if (parameters && Object.keys(parameters).length > 0) { + fields.set('parameters', parameters); } const timeoutMs = requestMessage.getTimeoutMs(); if (timeoutMs !== undefined) { diff --git a/gremlin-js/gremlin-javascript/test/integration/client-tests.js b/gremlin-js/gremlin-javascript/test/integration/client-tests.js index 32a3fb4468f..9194fa20221 100644 --- a/gremlin-js/gremlin-javascript/test/integration/client-tests.js +++ b/gremlin-js/gremlin-javascript/test/integration/client-tests.js @@ -45,7 +45,7 @@ describe('Client', function () { assert.ok(result.first() instanceof Vertex); }); }); - it('should send and parse a script with bindings', function () { + it('should send and parse a script with parameters', function () { return client.submit('g.V().has("name", x).values("age")', { x: 'marko' }) .then(function (result) { assert.ok(result); diff --git a/gremlin-python/src/main/python/gremlin_python/driver/client.py b/gremlin-python/src/main/python/gremlin_python/driver/client.py index 7cb073f696c..6f39f59c6c0 100644 --- a/gremlin-python/src/main/python/gremlin_python/driver/client.py +++ b/gremlin-python/src/main/python/gremlin_python/driver/client.py @@ -153,31 +153,30 @@ def _get_connection(self): max_connections=self._max_connections, **self._transport_kwargs) - def submit(self, message, bindings=None, request_options=None): - return self.submit_async(message, bindings=bindings, request_options=request_options).result() + def submit(self, message, parameters=None, request_options=None): + return self.submit_async(message, parameters=parameters, request_options=request_options).result() - def submitAsync(self, message, bindings=None, request_options=None): + def submitAsync(self, message, parameters=None, request_options=None): warnings.warn( "gremlin_python.driver.client.Client.submitAsync will be replaced by " "gremlin_python.driver.client.Client.submit_async.", DeprecationWarning) - return self.submit_async(message, bindings, request_options) + return self.submit_async(message, parameters, request_options) - def submit_async(self, message, bindings=None, request_options=None): + def submit_async(self, message, parameters=None, request_options=None): if self.is_closed(): raise Exception("Client is closed") log.debug("message '%s'", str(message)) fields = {'g': self._traversal_source} - # TODO: bindings is now part of request_options, evaluate the need to keep it separate in python. - # Note this bindings parameter only applies to string script submissions - if isinstance(message, str) and bindings: + # Note this parameters argument only applies to string script submissions + if isinstance(message, str) and parameters: from gremlin_python.process.traversal import GremlinLang - if isinstance(bindings, dict): - fields['bindings'] = GremlinLang.convert_parameters_to_string(bindings) + if isinstance(parameters, dict): + fields['parameters'] = GremlinLang.convert_parameters_to_string(parameters) else: - fields['bindings'] = bindings + fields['parameters'] = parameters if isinstance(message, str): log.debug("fields='%s', gremlin='%s'", str(fields), str(message)) @@ -194,13 +193,13 @@ def submit_async(self, message, bindings=None, request_options=None): conn = self._pool.get(True) if request_options: message.fields.update({token: request_options[token] for token in request.Tokens - if token in request_options and token != 'bindings'}) - if 'bindings' in request_options: - bindings_val = request_options['bindings'] - if isinstance(bindings_val, dict): + if token in request_options and token != 'parameters'}) + if 'parameters' in request_options: + parameters_val = request_options['parameters'] + if isinstance(parameters_val, dict): from gremlin_python.process.traversal import GremlinLang - bindings_val = GremlinLang.convert_parameters_to_string(bindings_val) - message.fields['bindings'] = bindings_val + parameters_val = GremlinLang.convert_parameters_to_string(parameters_val) + message.fields['parameters'] = parameters_val # Fill in the connection-level default batch size when the caller did # not set a per-request batchSize. diff --git a/gremlin-python/src/main/python/gremlin_python/driver/driver_remote_connection.py b/gremlin-python/src/main/python/gremlin_python/driver/driver_remote_connection.py index 3c0f094569e..e911720a3a2 100644 --- a/gremlin-python/src/main/python/gremlin_python/driver/driver_remote_connection.py +++ b/gremlin-python/src/main/python/gremlin_python/driver/driver_remote_connection.py @@ -75,12 +75,12 @@ def submit(self, gremlin_lang): request_options=self.extract_request_options(gremlin_lang)) return RemoteTraversal(result_set) - def submitAsync(self, message, bindings=None, request_options=None): + def submitAsync(self, message, parameters=None, request_options=None): warnings.warn( "gremlin_python.driver.driver_remote_connection.DriverRemoteConnection.submitAsync will be replaced by " "gremlin_python.driver.driver_remote_connection.DriverRemoteConnection.submit_async.", DeprecationWarning) - self.submit_async(message, bindings, request_options) + self.submit_async(message, parameters, request_options) def submit_async(self, gremlin_lang): log.debug("submit_async with gremlin lang script '%s'", gremlin_lang.get_gremlin()) @@ -114,6 +114,6 @@ def extract_request_options(gremlin_lang): parameters_string = gremlin_lang.get_parameters_as_string() if parameters_string != '[:]': - request_options["bindings"] = parameters_string + request_options["parameters"] = parameters_string return request_options diff --git a/gremlin-python/src/main/python/gremlin_python/driver/request.py b/gremlin-python/src/main/python/gremlin_python/driver/request.py index 119c76c0a94..b596cfccb54 100644 --- a/gremlin-python/src/main/python/gremlin_python/driver/request.py +++ b/gremlin-python/src/main/python/gremlin_python/driver/request.py @@ -23,6 +23,6 @@ RequestMessage = collections.namedtuple( 'RequestMessage', ['fields', 'gremlin']) -Tokens = ['batchSize', 'bindings', 'g', 'gremlin', 'language', +Tokens = ['batchSize', 'parameters', 'g', 'gremlin', 'language', 'evaluationTimeout', 'materializeProperties', 'timeoutMs', 'userAgent', 'bulkResults', 'transactionId'] diff --git a/gremlin-python/src/main/python/gremlin_python/driver/transaction.py b/gremlin-python/src/main/python/gremlin_python/driver/transaction.py index 857f1a2e3d6..d83ded122bc 100644 --- a/gremlin-python/src/main/python/gremlin_python/driver/transaction.py +++ b/gremlin-python/src/main/python/gremlin_python/driver/transaction.py @@ -98,7 +98,7 @@ def begin(self): strategies.add_strategies([RemoteStrategy(tx_connection)]) return GraphTraversalSource(None, strategies, GremlinLang()) - def submit(self, gremlin, bindings=None, request_options=None): + def submit(self, gremlin, parameters=None, request_options=None): """Submits a gremlin-lang string within this transaction. The transactionId is automatically attached. Has the same signature @@ -109,7 +109,7 @@ def submit(self, gremlin, bindings=None, request_options=None): opts = {'transactionId': self._transaction_id} if request_options: opts.update(request_options) - return self._client.submit(gremlin, bindings=bindings, request_options=opts) + return self._client.submit(gremlin, parameters=parameters, request_options=opts) def commit(self): """Commits the transaction.""" diff --git a/gremlin-python/src/main/python/tests/integration/driver/test_client.py b/gremlin-python/src/main/python/tests/integration/driver/test_client.py index 5afefa11979..308c010219b 100644 --- a/gremlin-python/src/main/python/tests/integration/driver/test_client.py +++ b/gremlin-python/src/main/python/tests/integration/driver/test_client.py @@ -97,7 +97,7 @@ def capture(http_request): client.close() -def test_client_simple_eval_bindings(client): +def test_client_simple_eval_parameters(client): assert client.submit('g.V(x).values("age")', {'x': 1}).all().result()[0] == 29 @@ -105,18 +105,18 @@ def test_client_eval_traversal(client): assert len(client.submit('g.V()').all().result()) == 6 -def test_client_eval_traversal_bindings(client): - assert client.submit('g.V(x).values("name")', bindings={'x': 1}).all().result()[0] == 'marko' +def test_client_eval_traversal_parameters(client): + assert client.submit('g.V(x).values("name")', parameters={'x': 1}).all().result()[0] == 'marko' -def test_client_eval_traversal_request_options_bindings(client): - assert client.submit('g.V(x).values("name")', request_options={'bindings': {'x': 1}}).all().result()[0] == 'marko' +def test_client_eval_traversal_request_options_parameters(client): + assert client.submit('g.V(x).values("name")', request_options={'parameters': {'x': 1}}).all().result()[0] == 'marko' -def test_client_eval_traversal_bindings_request_options_bindings(client): - # Note that parameters from request_options[bindings] is applied later and will replace bindings if key is the same - assert client.submit('g.V(x).values("name")', bindings={'x': 1}, - request_options={'bindings': {'x': 2}}).all().result()[0] == 'vadas' +def test_client_eval_traversal_parameters_request_options_parameters(client): + # Note that parameters from request_options[parameters] is applied later and will replace parameters if key is the same + assert client.submit('g.V(x).values("name")', parameters={'x': 1}, + request_options={'parameters': {'x': 2}}).all().result()[0] == 'vadas' def test_client_error(client): @@ -272,22 +272,22 @@ def test_client_gremlin_lang_options(client): assert len(result_set.all().result()) == 6 -def test_client_gremlin_lang_request_options_with_binding(client): +def test_client_gremlin_lang_request_options_with_parameter(client): g = GraphTraversalSource(Graph(), TraversalStrategies()) - # Note that bindings for constructed traversals is done via Parameter only + # Note that parameters for constructed traversals is done via Parameter only t = g.with_('language', 'gremlin-lang').V(GValue('x', [1, 2, 3])).count() - request_opts = {'language': 'gremlin-lang', 'bindings': {'x': [1, 2, 3]}} + request_opts = {'language': 'gremlin-lang', 'parameters': {'x': [1, 2, 3]}} message = create_basic_request_message(t) result_set = client.submit(message, request_options=request_opts) assert result_set.all().result()[0] == 3 # We can re-use the extracted request options in script submission result_set = client.submit('g.V(x).values("name")', request_options=request_opts) assert result_set.all().result()[0] == 'marko' - # For script submission only, we can also add bindings to request options and they will be applied - request_opts2 = {'language': 'gremlin-lang', 'bindings': {'y': 4}} + # For script submission only, we can also add parameters to request options and they will be applied + request_opts2 = {'language': 'gremlin-lang', 'parameters': {'y': 4}} result_set = client.submit('g.V(y).values("name")', request_options=request_opts2) assert result_set.all().result()[0] == 'josh' - result_set = client.submit('g.V(z).values("name")', bindings={'z': 5}) + result_set = client.submit('g.V(z).values("name")', parameters={'z': 5}) assert result_set.all().result()[0] == 'ripple' diff --git a/gremlin-python/src/main/python/tests/integration/driver/test_driver_remote_connection.py b/gremlin-python/src/main/python/tests/integration/driver/test_driver_remote_connection.py index ac852114830..3ca85e66f44 100644 --- a/gremlin-python/src/main/python/tests/integration/driver/test_driver_remote_connection.py +++ b/gremlin-python/src/main/python/tests/integration/driver/test_driver_remote_connection.py @@ -62,7 +62,7 @@ def test_extract_request_options_with_params(self, remote_connection): 'evaluationTimeout': 1000, 'userAgent': 'test', 'bulkResults': True, - 'bindings': "['ids':[1,2,3]]"} + 'parameters': "['ids':[1,2,3]]"} assert 3 == t.to_list()[0] def test_traversals(self, remote_connection): diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpGremlinEndpointHandler.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpGremlinEndpointHandler.java index eed9428c1d9..4540de73037 100644 --- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpGremlinEndpointHandler.java +++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpGremlinEndpointHandler.java @@ -124,10 +124,10 @@ public class HttpGremlinEndpointHandler extends SimpleChannelInboundHandler INVALID_BINDINGS_KEYS = new HashSet<>(); + protected static final Set INVALID_PARAMETERS_KEYS = new HashSet<>(); static { - INVALID_BINDINGS_KEYS.addAll(Arrays.asList( + INVALID_PARAMETERS_KEYS.addAll(Arrays.asList( T.id.name(), T.key.name(), T.label.name(), T.value.name(), T.id.getAccessor(), T.key.getAccessor(), @@ -136,23 +136,23 @@ public class HttpGremlinEndpointHandler extends SimpleChannelInboundHandler evalFuture = new FutureTask<>(() -> { try { - logger.debug("Processing request containing script [{}] and bindings of [{}] on {}", + logger.debug("Processing request containing script [{}] and parameters of [{}] on {}", requestMessage.getFieldOrDefault(Tokens.ARGS_GREMLIN, ""), - requestMessage.getFieldOrDefault(Tokens.ARGS_BINDINGS, "[:]"), + requestMessage.getFieldOrDefault(Tokens.ARGS_PARAMETERS, "[:]"), Thread.currentThread().getName()); if (settings.enableAuditLog) { AuthenticatedUser user = ctx.channel().attr(StateKey.AUTHENTICATED_USER).get(); @@ -254,30 +254,30 @@ public void channelRead0(final ChannelHandlerContext ctx, final RequestMessage r throw new ProcessingException(GremlinError.scriptEngineNotAvailable(language)); } - // Guard against bad parameters while trying to parse string-based bindings into a Map - if (requestMessage.optionalField(Tokens.ARGS_BINDINGS).isPresent()) { - Map bindings = null; - final String bindingsString = (String) requestMessage.getFields().get(Tokens.ARGS_BINDINGS); + // Guard against bad parameters while trying to parse string-based parameters into a Map + if (requestMessage.optionalField(Tokens.ARGS_PARAMETERS).isPresent()) { + Map parameters = null; + final String parametersString = (String) requestMessage.getFields().get(Tokens.ARGS_PARAMETERS); try { - bindings = GremlinQueryParser.parseParameters(bindingsString); + parameters = GremlinQueryParser.parseParameters(parametersString); } catch (GremlinParserException e) { - throw new ProcessingException(GremlinError.incorrectParameterFormat(bindingsString, e)); + throw new ProcessingException(GremlinError.incorrectParameterFormat(parametersString, e)); } if ("gremlin-groovy".equals(language)) { - final Set badBindings = IteratorUtils.set(IteratorUtils.filter( - bindings.keySet().iterator(), - INVALID_BINDINGS_KEYS::contains)); - if (!badBindings.isEmpty()) { - throw new ProcessingException(GremlinError.binding(badBindings)); + final Set badParameters = IteratorUtils.set(IteratorUtils.filter( + parameters.keySet().iterator(), + INVALID_PARAMETERS_KEYS::contains)); + if (!badParameters.isEmpty()) { + throw new ProcessingException(GremlinError.parameter(badParameters)); } } - if (bindings.size() > settings.maxParameters) { - throw new ProcessingException(GremlinError.binding(bindings.size(), settings.maxParameters)); + if (parameters.size() > settings.maxParameters) { + throw new ProcessingException(GremlinError.parameter(parameters.size(), settings.maxParameters)); } - requestCtx.setParameters(bindings); + requestCtx.setParameters(parameters); } // Send back the 200 OK response header here since the response is always chunk transfer encoded. Any diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpRequestMessageDecoder.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpRequestMessageDecoder.java index 8a688b6d6bd..a47683fbf56 100644 --- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpRequestMessageDecoder.java +++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpRequestMessageDecoder.java @@ -189,8 +189,8 @@ private RequestMessage getRequestMessageFromHttpRequest(final FullHttpRequest re final RequestMessage.Builder builder = RequestMessage.build(scriptNode.asText()); - final JsonNode bindingsNode = body.get(Tokens.ARGS_BINDINGS); - if (bindingsNode != null) builder.addBindings(bindingsNode.asText()); + final JsonNode parametersNode = body.get(Tokens.ARGS_PARAMETERS); + if (parametersNode != null) builder.addParameters(parametersNode.asText()); final JsonNode gNode = body.get(Tokens.ARGS_G); if (null != gNode) builder.addG(gNode.asText()); diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/util/GremlinError.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/util/GremlinError.java index e0e74c26d0c..301a26f5b95 100644 --- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/util/GremlinError.java +++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/util/GremlinError.java @@ -64,8 +64,8 @@ public static GremlinError invalidGremlinType(final RequestMessage requestMessag } // script errors - public static GremlinError binding() { - final String message = String.format("The message is using one or more invalid binding keys - they must be of type String and cannot be null"); + public static GremlinError parameter() { + final String message = String.format("The message is using one or more invalid parameter keys - they must be of type String and cannot be null"); return new GremlinError(HttpResponseStatus.BAD_REQUEST, message, "InvalidRequestException"); } @@ -76,15 +76,15 @@ public static GremlinError incorrectParameterFormat(final String parameters, fin return new GremlinError(HttpResponseStatus.BAD_REQUEST, message, "InvalidRequestException"); } - public static GremlinError binding(final Set badBindings) { + public static GremlinError parameter(final Set badParameters) { final String message = String.format("The message supplies one or more invalid parameters key of [%s] - these are reserved names.", - badBindings); + badParameters); return new GremlinError(HttpResponseStatus.BAD_REQUEST, message, "InvalidRequestException"); } - public static GremlinError binding(final int bindingsCount, final int allowedSize) { - final String message = String.format("The message contains %s bindings which is more than is allowed by the server %s configuration", - bindingsCount, allowedSize); + public static GremlinError parameter(final int parametersCount, final int allowedSize) { + final String message = String.format("The message contains %s parameters which is more than is allowed by the server %s configuration", + parametersCount, allowedSize); return new GremlinError(HttpResponseStatus.BAD_REQUEST, message, "InvalidRequestException"); } diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerHttpIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerHttpIntegrateTest.java index c67a0add0d3..e381d6c46a4 100644 --- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerHttpIntegrateTest.java +++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerHttpIntegrateTest.java @@ -193,7 +193,7 @@ public void should413OnPostWithResultTooLarge() throws Exception { final HttpPost httppost = new HttpPost(TestClientFactory.createURLString()); httppost.addHeader("Content-Type", "application/json"); final String bigPost = RandomStringUtils.random(32); - httppost.setEntity(new StringEntity("{\"gremlin\":\""+ String.format("g.inject('%s')", bigPost) + "\", \"bindings\":{\"x\":\"10\"}}", Consts.UTF_8)); + httppost.setEntity(new StringEntity("{\"gremlin\":\""+ String.format("g.inject('%s')", bigPost) + "\", \"parameters\":{\"x\":\"10\"}}", Consts.UTF_8)); try (final CloseableHttpResponse response = httpclient.execute(httppost)) { assertEquals(413, response.getStatusLine().getStatusCode()); @@ -336,7 +336,7 @@ public void should200OnPOSTWithAuthorizationHeaderExplicitHandlerSetting() throw public void should200OnPOSTWithGremlinQueryStringArgumentWithBindingsAndFunction() throws Exception { final CloseableHttpClient httpclient = HttpClients.createDefault(); final HttpPost httppost = new HttpPost(TestClientFactory.createURLString()); - httppost.setEntity(new StringEntity("{\"gremlin\":\"addItUp(Integer.parseInt(x),Integer.parseInt(y))\",\"language\":\"gremlin-groovy\",\"bindings\":\"[x:\\\"10\\\",y:\\\"10\\\"]\"}", Consts.UTF_8)); + httppost.setEntity(new StringEntity("{\"gremlin\":\"addItUp(Integer.parseInt(x),Integer.parseInt(y))\",\"language\":\"gremlin-groovy\",\"parameters\":\"[x:\\\"10\\\",y:\\\"10\\\"]\"}", Consts.UTF_8)); try (final CloseableHttpResponse response = httpclient.execute(httppost)) { assertEquals(200, response.getStatusLine().getStatusCode()); @@ -664,7 +664,7 @@ public void should200OnPOSTWithGremlinJsonEndcodedBodyAndBindings() throws Excep final CloseableHttpClient httpclient = HttpClients.createDefault(); final HttpPost httppost = new HttpPost(TestClientFactory.createURLString()); httppost.addHeader("Content-Type", "application/json"); - httppost.setEntity(new StringEntity("{\"gremlin\":\"x+y\", \"bindings\":\"[x:10,y:10]\", \"language\":\"gremlin-groovy\"}", Consts.UTF_8)); + httppost.setEntity(new StringEntity("{\"gremlin\":\"x+y\", \"parameters\":\"[x:10,y:10]\", \"language\":\"gremlin-groovy\"}", Consts.UTF_8)); try (final CloseableHttpResponse response = httpclient.execute(httppost)) { assertEquals(200, response.getStatusLine().getStatusCode()); @@ -680,7 +680,7 @@ public void should200OnPOSTWithGremlinJsonEndcodedBodyAndLongBindings() throws E final CloseableHttpClient httpclient = HttpClients.createDefault(); final HttpPost httppost = new HttpPost(TestClientFactory.createURLString()); httppost.addHeader("Content-Type", "application/json"); - httppost.setEntity(new StringEntity("{\"gremlin\":\"g.inject(x)\", \"bindings\":\"[x:10]\", \"language\":\"gremlin-groovy\"}", Consts.UTF_8)); + httppost.setEntity(new StringEntity("{\"gremlin\":\"g.inject(x)\", \"parameters\":\"[x:10]\", \"language\":\"gremlin-groovy\"}", Consts.UTF_8)); try (final CloseableHttpResponse response = httpclient.execute(httppost)) { assertEquals(200, response.getStatusLine().getStatusCode()); @@ -696,7 +696,7 @@ public void should200OnPOSTWithGremlinJsonEndcodedBodyAndDoubleBindings() throws final CloseableHttpClient httpclient = HttpClients.createDefault(); final HttpPost httppost = new HttpPost(TestClientFactory.createURLString()); httppost.addHeader("Content-Type", "application/json"); - httppost.setEntity(new StringEntity("{\"gremlin\":\"g.inject(x)\", \"bindings\":\"[x:10.5]\", \"language\":\"gremlin-groovy\"}", Consts.UTF_8)); + httppost.setEntity(new StringEntity("{\"gremlin\":\"g.inject(x)\", \"parameters\":\"[x:10.5]\", \"language\":\"gremlin-groovy\"}", Consts.UTF_8)); try (final CloseableHttpResponse response = httpclient.execute(httppost)) { assertEquals(200, response.getStatusLine().getStatusCode()); @@ -712,7 +712,7 @@ public void should200OnPOSTWithGremlinJsonEndcodedBodyAndStringBindings() throws final CloseableHttpClient httpclient = HttpClients.createDefault(); final HttpPost httppost = new HttpPost(TestClientFactory.createURLString()); httppost.addHeader("Content-Type", "application/json"); - httppost.setEntity(new StringEntity("{\"gremlin\":\"g.V(1).out(x).values('name')\", \"bindings\":\"[x:\\\"knows\\\"]\", \"g\":\"gmodern\"}", Consts.UTF_8)); + httppost.setEntity(new StringEntity("{\"gremlin\":\"g.V(1).out(x).values('name')\", \"parameters\":\"[x:\\\"knows\\\"]\", \"g\":\"gmodern\"}", Consts.UTF_8)); try (final CloseableHttpResponse response = httpclient.execute(httppost)) { assertEquals(200, response.getStatusLine().getStatusCode()); @@ -728,7 +728,7 @@ public void should200OnPOSTWithGremlinJsonEndcodedBodyAndBooleanBindings() throw final CloseableHttpClient httpclient = HttpClients.createDefault(); final HttpPost httppost = new HttpPost(TestClientFactory.createURLString()); httppost.addHeader("Content-Type", "application/json"); - httppost.setEntity(new StringEntity("{\"gremlin\":\"g.inject(x)\", \"bindings\":\"[x:true]\", \"language\":\"gremlin-groovy\"}", Consts.UTF_8)); + httppost.setEntity(new StringEntity("{\"gremlin\":\"g.inject(x)\", \"parameters\":\"[x:true]\", \"language\":\"gremlin-groovy\"}", Consts.UTF_8)); try (final CloseableHttpResponse response = httpclient.execute(httppost)) { assertEquals(200, response.getStatusLine().getStatusCode()); @@ -744,7 +744,7 @@ public void should200OnPOSTWithGremlinJsonEndcodedBodyAndNullBindings() throws E final CloseableHttpClient httpclient = HttpClients.createDefault(); final HttpPost httppost = new HttpPost(TestClientFactory.createURLString()); httppost.addHeader("Content-Type", "application/json"); - httppost.setEntity(new StringEntity("{\"gremlin\":\"g.inject(x)\", \"bindings\":\"[x:null]\", \"language\":\"gremlin-groovy\"}", Consts.UTF_8)); + httppost.setEntity(new StringEntity("{\"gremlin\":\"g.inject(x)\", \"parameters\":\"[x:null]\", \"language\":\"gremlin-groovy\"}", Consts.UTF_8)); try (final CloseableHttpResponse response = httpclient.execute(httppost)) { assertEquals(200, response.getStatusLine().getStatusCode()); @@ -760,7 +760,7 @@ public void should200OnPOSTWithGremlinJsonEndcodedBodyAndArrayBindings() throws final CloseableHttpClient httpclient = HttpClients.createDefault(); final HttpPost httppost = new HttpPost(TestClientFactory.createURLString()); httppost.addHeader("Content-Type", "application/json"); - httppost.setEntity(new StringEntity("{\"gremlin\":\"g.inject(x).unfold()\", \"bindings\":\"[x:[1,2,3]]\", \"language\":\"gremlin-groovy\"}", Consts.UTF_8)); + httppost.setEntity(new StringEntity("{\"gremlin\":\"g.inject(x).unfold()\", \"parameters\":\"[x:[1,2,3]]\", \"language\":\"gremlin-groovy\"}", Consts.UTF_8)); try (final CloseableHttpResponse response = httpclient.execute(httppost)) { assertEquals(200, response.getStatusLine().getStatusCode()); @@ -779,7 +779,7 @@ public void should200OnPOSTWithGremlinJsonEndcodedBodyAndMapBindings() throws Ex final CloseableHttpClient httpclient = HttpClients.createDefault(); final HttpPost httppost = new HttpPost(TestClientFactory.createURLString()); httppost.addHeader("Content-Type", "application/json"); - httppost.setEntity(new StringEntity("{\"gremlin\":\"g.inject(x)\", \"bindings\":\"[x:[\\\"y\\\":1]]\", \"language\":\"gremlin-groovy\"}", Consts.UTF_8)); + httppost.setEntity(new StringEntity("{\"gremlin\":\"g.inject(x)\", \"parameters\":\"[x:[\\\"y\\\":1]]\", \"language\":\"gremlin-groovy\"}", Consts.UTF_8)); try (final CloseableHttpResponse response = httpclient.execute(httppost)) { assertEquals(200, response.getStatusLine().getStatusCode()); @@ -796,7 +796,7 @@ public void should400OnPOSTWithGremlinJsonEndcodedBodyAndBadBindings() throws Ex final CloseableHttpClient httpclient = HttpClients.createDefault(); final HttpPost httppost = new HttpPost(TestClientFactory.createURLString()); httppost.addHeader("Content-Type", "application/json"); - httppost.setEntity(new StringEntity("{\"gremlin\":\"g.inject(x, y)\", \"bindings\":10}, \"language\":\"gremlin-groovy\"}", Consts.UTF_8)); + httppost.setEntity(new StringEntity("{\"gremlin\":\"g.inject(x, y)\", \"parameters\":10}, \"language\":\"gremlin-groovy\"}", Consts.UTF_8)); try (final CloseableHttpResponse response = httpclient.execute(httppost)) { assertEquals(400, response.getStatusLine().getStatusCode()); @@ -1218,7 +1218,7 @@ public void should200OnPOSTWithGremlinGraphSONEndcodedBodyAndDoubleBindings() th final SimpleBindings bindings = new SimpleBindings(); bindings.put("x", 10.5d); final ByteBuf serializedRequest = serializer.serializeRequestAsBinary( - RequestMessage.build("g.inject(x)").addBindings(bindings).addLanguage("gremlin-groovy").create(), + RequestMessage.build("g.inject(x)").addParameters(bindings).addLanguage("gremlin-groovy").create(), new UnpooledByteBufAllocator(false)); final CloseableHttpClient httpclient = HttpClients.createDefault(); @@ -1240,7 +1240,7 @@ public void should200OnPOSTWithGremlinGraphSONEndcodedBodyAndDoubleBindings() th public void should400OnPOSTWithInvalidRequestArgsWhenInvalidBindingsSupplied() throws Exception { final GraphSONMessageSerializerV4 serializer = new GraphSONMessageSerializerV4(); final ByteBuf serializedRequest = serializer.serializeRequestAsBinary( - RequestMessage.build("g.V(id)").addBindings("[id:1]").addLanguage("gremlin-groovy").create(), + RequestMessage.build("g.V(id)").addParameters("[id:1]").addLanguage("gremlin-groovy").create(), new UnpooledByteBufAllocator(false)); final CloseableHttpClient httpclient = HttpClients.createDefault(); diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java index 07e8e4ce717..56e04a3c268 100644 --- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java +++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java @@ -531,7 +531,7 @@ public void shouldReturnInvalidRequestArgsWhenInvalidReservedBindingKeyIsUsed() final Map bindings = new HashMap<>(); bindings.put(T.id.getAccessor(), "123"); final RequestMessage request = RequestMessage.build("g.inject(1,2,3,4,5,6,7,8,9,0)") - .addBindings(bindings).create(); + .addParameters(bindings).create(); final CountDownLatch latch = new CountDownLatch(1); final AtomicBoolean pass = new AtomicBoolean(false); client.submit(request, result -> { @@ -550,7 +550,7 @@ public void shouldReturnInvalidRequestArgsWhenInvalidReservedBindingKeyIsUsed() final Map bindings = new HashMap<>(); bindings.put("id", "123"); // "id" is invalid for gremlin-groovy, but not gremlin-lang final RequestMessage request = RequestMessage.build("g.inject(1,2,3,4,5,6,7,8,9,0)") - .addBindings(bindings).addLanguage("gremlin-groovy").create(); + .addParameters(bindings).addLanguage("gremlin-groovy").create(); final CountDownLatch latch = new CountDownLatch(1); final AtomicBoolean pass = new AtomicBoolean(false); client.submit(request, result -> { @@ -573,7 +573,7 @@ public void shouldReturnInvalidRequestArgsWhenBindingCountExceedsAllowable() thr bindings.put("x", 1); bindings.put("y", "knows"); final RequestMessage request = RequestMessage.build("g.V(x).out(y).values('name')") - .addBindings(bindings).addG("gmodern").create(); + .addParameters(bindings).addG("gmodern").create(); final CountDownLatch latch = new CountDownLatch(1); final AtomicBoolean pass = new AtomicBoolean(false); client.submit(request, result -> { @@ -592,7 +592,7 @@ public void shouldReturnInvalidRequestArgsWhenBindingCountExceedsAllowable() thr final Map bindings = new HashMap<>(); bindings.put("x", 1); final RequestMessage request = RequestMessage.build("g.V(x).out('knows').values('name')") - .addBindings(bindings).addG("gmodern").create(); + .addParameters(bindings).addG("gmodern").create(); final CountDownLatch latch = new CountDownLatch(1); final AtomicBoolean pass = new AtomicBoolean(false); client.submit(request, result -> { @@ -614,7 +614,7 @@ public void shouldReturnInvalidRequestArgsWhenInvalidNullBindingKeyIsUsed() thro final Map bindings = new HashMap<>(); bindings.put(null, "123"); final RequestMessage request = RequestMessage.build("g.inject(1,2,3,4,5,6,7,8,9,0)") - .addBindings(bindings).create(); + .addParameters(bindings).create(); final CountDownLatch latch = new CountDownLatch(1); final AtomicBoolean pass = new AtomicBoolean(false); client.submit(request, result -> { @@ -1150,7 +1150,7 @@ public void ensureScriptEngineDefaultsToGremlinLang() { public void shouldSubmitWithStringBindingsViaRequestMessage() throws Exception { try (SimpleClient client = TestClientFactory.createSimpleHttpClient()) { final RequestMessage request = RequestMessage.build("g.V(x).out(y).values('name')") - .addBindings("[\"x\":1,\"y\":\"knows\"]").addG("gmodern").create(); + .addParameters("[\"x\":1,\"y\":\"knows\"]").addG("gmodern").create(); final List responses = client.submit(request); assertEquals(HttpResponseStatus.OK, responses.get(0).getStatus().getCode()); assertEquals("vadas", responses.get(0).getResult().getData().get(0)); @@ -1161,7 +1161,7 @@ public void shouldSubmitWithStringBindingsViaRequestMessage() throws Exception { public void shouldRejectTraversalInjectionInStringBindings() throws Exception { try (SimpleClient client = TestClientFactory.createSimpleHttpClient()) { final RequestMessage request = RequestMessage.build("g.V(x)") - .addBindings("[x:__.V().drop()]").addG("gmodern").create(); + .addParameters("[x:__.V().drop()]").addG("gmodern").create(); final List responses = client.submit(request); assertEquals(HttpResponseStatus.BAD_REQUEST, responses.get(0).getStatus().getCode()); } diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerSslIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerSslIntegrateTest.java index 2e73cca38e5..a1b13c68983 100644 --- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerSslIntegrateTest.java +++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerSslIntegrateTest.java @@ -172,7 +172,7 @@ public void shouldEnableWebSocketSsl() throws Exception { bindings.put("x", 123); bindings.put("y", 123); final RequestMessage request = RequestMessage.build("x+y") - .addBindings(bindings).addLanguage("gremlin-groovy").create(); + .addParameters(bindings).addLanguage("gremlin-groovy").create(); final CountDownLatch latch = new CountDownLatch(1); final AtomicBoolean pass = new AtomicBoolean(false); client.submit(request, result -> { diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/handler/HttpRequestMessageDecoderTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/handler/HttpRequestMessageDecoderTest.java index 62045069bc1..52f8cdd4cc6 100644 --- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/handler/HttpRequestMessageDecoderTest.java +++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/handler/HttpRequestMessageDecoderTest.java @@ -147,7 +147,7 @@ public void shouldCorrectlyDeserializeGremlinFromPostRequestWithAllScriptFieldsS final String gremlin = "g.V(x)"; final ByteBuf buffer = allocator.buffer(); buffer.writeCharSequence("{ \"gremlin\": \"" + gremlin + - "\", \"bindings\":\"[\\\"x\\\":\\\"2\\\"]\"" + + "\", \"parameters\":\"[\\\"x\\\":\\\"2\\\"]\"" + ", \"language\": \"gremlin-groovy\"}", CharsetUtil.UTF_8); @@ -163,7 +163,7 @@ public void shouldCorrectlyDeserializeGremlinFromPostRequestWithAllScriptFieldsS final RequestMessage decodedRequestMessage = testChannel.readInbound(); assertEquals(gremlin, decodedRequestMessage.getGremlin()); assertEquals("gremlin-groovy", decodedRequestMessage.getField(Tokens.ARGS_LANGUAGE)); - assertEquals("[\"x\":\"2\"]", decodedRequestMessage.getField(Tokens.ARGS_BINDINGS)); + assertEquals("[\"x\":\"2\"]", decodedRequestMessage.getField(Tokens.ARGS_PARAMETERS)); } @Test @@ -314,7 +314,7 @@ public void shouldAddValidFieldsToRequestMessage() throws SerializationException final UUID rid = UUID.randomUUID(); final ByteBuf buffer = allocator.buffer(); buffer.writeCharSequence("{\"gremlin\":\"g.V().limit(2)\",\"batchSize\":\"10\",\"language\":\"gremlin-lang\"," + - "\"g\":\"gmodern\",\"bindings\":\"[\\\"x\\\":1]\",\"timeoutMs\":\"12\"," + + "\"g\":\"gmodern\",\"parameters\":\"[\\\"x\\\":1]\",\"timeoutMs\":\"12\"," + "\"materializeProperties\":\"" + Tokens.MATERIALIZE_PROPERTIES_TOKENS + "\"}", CharsetUtil.UTF_8); final HttpHeaders headers = new DefaultHttpHeaders(); @@ -331,7 +331,7 @@ public void shouldAddValidFieldsToRequestMessage() throws SerializationException assertEquals(10, (int) decodedRequest.getField(Tokens.ARGS_BATCH_SIZE)); assertEquals("gremlin-lang", decodedRequest.getField(Tokens.ARGS_LANGUAGE)); assertEquals("gmodern", decodedRequest.getField(Tokens.ARGS_G)); - assertEquals("[\"x\":1]", decodedRequest.getField(Tokens.ARGS_BINDINGS)); + assertEquals("[\"x\":1]", decodedRequest.getField(Tokens.ARGS_PARAMETERS)); assertEquals(12, (long) decodedRequest.getField(Tokens.TIMEOUT_MS)); assertEquals(Tokens.MATERIALIZE_PROPERTIES_TOKENS, decodedRequest.getField(Tokens.ARGS_MATERIALIZE_PROPERTIES)); } diff --git a/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/Tokens.java b/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/Tokens.java index 2668b8c66df..8654e3dad02 100644 --- a/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/Tokens.java +++ b/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/Tokens.java @@ -47,10 +47,10 @@ public static final class Headers { public static final String ARGS_BATCH_SIZE = "batchSize"; /** - * Argument name that allows to provide a map of key/value pairs to apply as variables in the context of + * Argument name that allows to provide a map of key/value pairs to apply as query parameters in the context of * the Gremlin request sent to the server. */ - public static final String ARGS_BINDINGS = "bindings"; + public static final String ARGS_PARAMETERS = "parameters"; /** * Argument name that allows definition of alias names for {@link Graph} and {@link TraversalSource} objects on diff --git a/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/message/RequestMessage.java b/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/message/RequestMessage.java index a08c4abada7..5b974926f2d 100644 --- a/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/message/RequestMessage.java +++ b/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/message/RequestMessage.java @@ -125,23 +125,23 @@ public Builder addLanguage(final String language) { } /** - * Sets the bindings as a gremlin-lang map literal string. Calling this method multiple - * times will replace the previous bindings (last-one-wins). + * Sets the query parameters as a gremlin-lang map literal string. Calling this method multiple + * times will replace the previous parameters (last-one-wins). */ - public Builder addBindings(final String bindingsString) { - Objects.requireNonNull(bindingsString, "bindings argument cannot be null."); - this.fields.put(Tokens.ARGS_BINDINGS, bindingsString); + public Builder addParameters(final String parametersString) { + Objects.requireNonNull(parametersString, "parameters argument cannot be null."); + this.fields.put(Tokens.ARGS_PARAMETERS, parametersString); return this; } /** - * Sets the bindings from a map by converting it to a gremlin-lang map literal string + * Sets the query parameters from a map by converting it to a gremlin-lang map literal string * using {@link GremlinLang#convertParametersToString(Map)}. Calling this method multiple - * times will replace the previous bindings (last-one-wins). + * times will replace the previous parameters (last-one-wins). */ - public Builder addBindings(final Map otherBindings) { - Objects.requireNonNull(otherBindings, "bindings argument cannot be null."); - this.fields.put(Tokens.ARGS_BINDINGS, GremlinLang.convertParametersToString(otherBindings)); + public Builder addParameters(final Map otherParameters) { + Objects.requireNonNull(otherParameters, "parameters argument cannot be null."); + this.fields.put(Tokens.ARGS_PARAMETERS, GremlinLang.convertParametersToString(otherParameters)); return this; } diff --git a/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/AbstractGraphSONMessageSerializerV4.java b/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/AbstractGraphSONMessageSerializerV4.java index 22e580086a3..d14168c216e 100644 --- a/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/AbstractGraphSONMessageSerializerV4.java +++ b/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/AbstractGraphSONMessageSerializerV4.java @@ -324,8 +324,8 @@ public RequestMessage createObject(final Map data) { if (data.containsKey(SerTokens.TOKEN_G)) { builder.addG(data.get(SerTokens.TOKEN_G).toString()); } - if (data.containsKey(SerTokens.TOKEN_BINDINGS)) { - builder.addBindings(data.get(SerTokens.TOKEN_BINDINGS).toString()); + if (data.containsKey(SerTokens.TOKEN_PARAMETERS)) { + builder.addParameters(data.get(SerTokens.TOKEN_PARAMETERS).toString()); } if (data.containsKey(Tokens.TIMEOUT_MS)) { // Can be int for untyped JSON and long for typed GraphSON. diff --git a/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/SerTokens.java b/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/SerTokens.java index 34243c29e09..69a32cc88f5 100644 --- a/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/SerTokens.java +++ b/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/SerTokens.java @@ -32,7 +32,7 @@ private SerTokens() {} public static final String TOKEN_MESSAGE = "message"; public static final String TOKEN_GREMLIN = "gremlin"; public static final String TOKEN_LANGUAGE = "language"; - public static final String TOKEN_BINDINGS = "bindings"; + public static final String TOKEN_PARAMETERS = "parameters"; public static final String TOKEN_G = "g"; public static final String TOKEN_TIMEOUT_MS = "timeoutMs"; public static final String TOKEN_MATERIALIZE_PROPERTIES = "materializeProperties"; diff --git a/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/binary/RequestMessageSerializer.java b/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/binary/RequestMessageSerializer.java index 2f30d43b1df..6b523dd5f8f 100644 --- a/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/binary/RequestMessageSerializer.java +++ b/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/binary/RequestMessageSerializer.java @@ -58,8 +58,8 @@ public RequestMessage readValue(final ByteBuf byteBuf, final GraphBinaryReader c if (fields.containsKey(SerTokens.TOKEN_G)) { builder.addG(fields.get(SerTokens.TOKEN_G).toString()); } - if (fields.containsKey(SerTokens.TOKEN_BINDINGS)) { - builder.addBindings(fields.get(SerTokens.TOKEN_BINDINGS).toString()); + if (fields.containsKey(SerTokens.TOKEN_PARAMETERS)) { + builder.addParameters(fields.get(SerTokens.TOKEN_PARAMETERS).toString()); } if (fields.containsKey(Tokens.TIMEOUT_MS)) { builder.addTimeoutMillis(((Number) fields.get(Tokens.TIMEOUT_MS)).longValue()); diff --git a/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/structure/io/AbstractCompatibilityTest.java b/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/structure/io/AbstractCompatibilityTest.java index 01837126145..f4363c208df 100644 --- a/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/structure/io/AbstractCompatibilityTest.java +++ b/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/structure/io/AbstractCompatibilityTest.java @@ -138,14 +138,14 @@ protected static void assertRequestMessage(final RequestMessage resource, final final RequestMessage recycled) { // Check per field rather than map equals since a new field may get added later. assertEquals(resource.getGremlin(), recycled.getGremlin()); - assertEquals(resource.getField(SerTokens.TOKEN_BINDINGS), recycled.getField(SerTokens.TOKEN_BINDINGS)); + assertEquals(resource.getField(SerTokens.TOKEN_PARAMETERS), recycled.getField(SerTokens.TOKEN_PARAMETERS)); assertEquals(resource.getField(SerTokens.TOKEN_LANGUAGE), recycled.getField(SerTokens.TOKEN_LANGUAGE)); assertEquals(resource.getField(SerTokens.TOKEN_G), recycled.getField(SerTokens.TOKEN_G)); assertEquals(resource.getField(SerTokens.TOKEN_TIMEOUT_MS), recycled.getField(SerTokens.TOKEN_TIMEOUT_MS)); assertEquals(resource.getField(SerTokens.TOKEN_MATERIALIZE_PROPERTIES), recycled.getField(SerTokens.TOKEN_MATERIALIZE_PROPERTIES)); assertEquals(resource.getGremlin(), fromStatic.getGremlin()); - assertEquals(resource.getField(SerTokens.TOKEN_BINDINGS), fromStatic.getField(SerTokens.TOKEN_BINDINGS)); + assertEquals(resource.getField(SerTokens.TOKEN_PARAMETERS), fromStatic.getField(SerTokens.TOKEN_PARAMETERS)); assertEquals(resource.getField(SerTokens.TOKEN_LANGUAGE), fromStatic.getField(SerTokens.TOKEN_LANGUAGE)); assertEquals(resource.getField(SerTokens.TOKEN_G), fromStatic.getField(SerTokens.TOKEN_G)); assertEquals(resource.getField(SerTokens.TOKEN_TIMEOUT_MS), fromStatic.getField(SerTokens.TOKEN_TIMEOUT_MS)); diff --git a/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/message/RequestMessageTest.java b/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/message/RequestMessageTest.java index 13376778a8d..77a67b14b3d 100644 --- a/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/message/RequestMessageTest.java +++ b/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/message/RequestMessageTest.java @@ -38,47 +38,47 @@ public void shouldSetScriptGremlin() { } @Test - public void shouldSetBindingsWithMap() { - final Map bindings = new HashMap<>(); - bindings.put("a", "b"); - bindings.put("g", "gmodern"); - final RequestMessage msg = RequestMessage.build("gremlin").addBindings(bindings).create(); - // bindings are now stored as a gremlin-lang map literal string - final String bindingsString = msg.getField(Tokens.ARGS_BINDINGS); - assertTrue(bindingsString.startsWith("[")); - assertTrue(bindingsString.endsWith("]")); - assertTrue(bindingsString.contains("\"a\":\"b\"")); - assertTrue(bindingsString.contains("\"g\":\"gmodern\"")); + public void shouldSetParametersWithMap() { + final Map parameters = new HashMap<>(); + parameters.put("a", "b"); + parameters.put("g", "gmodern"); + final RequestMessage msg = RequestMessage.build("gremlin").addParameters(parameters).create(); + // parameters are now stored as a gremlin-lang map literal string + final String parametersString = msg.getField(Tokens.ARGS_PARAMETERS); + assertTrue(parametersString.startsWith("[")); + assertTrue(parametersString.endsWith("]")); + assertTrue(parametersString.contains("\"a\":\"b\"")); + assertTrue(parametersString.contains("\"g\":\"gmodern\"")); } @Test - public void shouldSetBindingsWithString() { + public void shouldSetParametersWithString() { final RequestMessage msg = RequestMessage.build("gremlin") - .addBindings("[a:\"b\",g:\"gmodern\"]") + .addParameters("[a:\"b\",g:\"gmodern\"]") .create(); - assertEquals("[a:\"b\",g:\"gmodern\"]", msg.getField(Tokens.ARGS_BINDINGS)); + assertEquals("[a:\"b\",g:\"gmodern\"]", msg.getField(Tokens.ARGS_PARAMETERS)); } @Test - public void shouldNotContainBindingsWhenNoneSet() { + public void shouldNotContainParametersWhenNoneSet() { final RequestMessage msg = RequestMessage.build("g.V()").create(); - assertNull(msg.getField(Tokens.ARGS_BINDINGS)); + assertNull(msg.getField(Tokens.ARGS_PARAMETERS)); } @Test - public void shouldOverwriteBindingsOnMultipleCalls() { + public void shouldOverwriteParametersOnMultipleCalls() { final RequestMessage msg = RequestMessage.build("gremlin") - .addBindings("[x:1]") - .addBindings("[y:2]") + .addParameters("[x:1]") + .addParameters("[y:2]") .create(); - assertEquals("[y:2]", msg.getField(Tokens.ARGS_BINDINGS)); + assertEquals("[y:2]", msg.getField(Tokens.ARGS_PARAMETERS)); } @Test(expected = IllegalArgumentException.class) - public void shouldRejectUnsupportedTypeInBindingsMap() { - final Map bindings = new HashMap<>(); - bindings.put("x", new Thread()); - RequestMessage.build("g.V()").addBindings(bindings); + public void shouldRejectUnsupportedTypeInParametersMap() { + final Map parameters = new HashMap<>(); + parameters.put("x", new Thread()); + RequestMessage.build("g.V()").addParameters(parameters); } @Test @@ -126,18 +126,18 @@ public void shouldGetFields() { final String g = "gmodern"; final String lang = "lang"; final String query = "g.V()"; - final Map bindings = new HashMap<>(); - bindings.put("b", "c"); - bindings.put("g", "gmodern"); + final Map parameters = new HashMap<>(); + parameters.put("b", "c"); + parameters.put("g", "gmodern"); - final RequestMessage msg = RequestMessage.build(query).addG(g).addBindings(bindings).addLanguage(lang).create(); + final RequestMessage msg = RequestMessage.build(query).addG(g).addParameters(parameters).addLanguage(lang).create(); final Map fields = msg.getFields(); assertEquals(g, fields.get(Tokens.ARGS_G)); assertEquals(lang, fields.get(Tokens.ARGS_LANGUAGE)); - // bindings are now a gremlin-lang string, not the original map - final String bindingsString = (String) fields.get(Tokens.ARGS_BINDINGS); - assertTrue(bindingsString.contains("\"b\":\"c\"")); - assertTrue(bindingsString.contains("\"g\":\"gmodern\"")); + // parameters are now a gremlin-lang string, not the original map + final String parametersString = (String) fields.get(Tokens.ARGS_PARAMETERS); + assertTrue(parametersString.contains("\"b\":\"c\"")); + assertTrue(parametersString.contains("\"g\":\"gmodern\"")); assertEquals(query, msg.getGremlin()); } diff --git a/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/binary/MessageSerializerTest.java b/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/binary/MessageSerializerTest.java index e8874bf5026..e38ed20f01e 100644 --- a/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/binary/MessageSerializerTest.java +++ b/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/binary/MessageSerializerTest.java @@ -81,7 +81,7 @@ public void shouldSerializeAndDeserializeRequest() throws SerializationException .addTimeoutMillis(500) .addG("g1") .addLanguage("some-lang") - .addBindings("['k':'v']") + .addParameters("['k':'v']") .create(); final ByteBuf buffer = serializer.serializeRequestAsBinary(request, allocator);