You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by xi...@apache.org on 2023/02/22 00:08:55 UTC

[tinkerpop] branch 3.5-dev updated: Add RequestOptions to Go GLV (#1968)

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

xiazcy pushed a commit to branch 3.5-dev
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git


The following commit(s) were added to refs/heads/3.5-dev by this push:
     new a5142eeac6 Add RequestOptions to Go GLV (#1968)
a5142eeac6 is described below

commit a5142eeac6e9471e4c01cd3c9dd4771fcefbd7a8
Author: Cole Greer <11...@users.noreply.github.com>
AuthorDate: Tue Feb 21 16:08:48 2023 -0800

    Add RequestOptions to Go GLV (#1968)
    
    Go was previously not sending per-request options correctly to the server.
    Go was passing request options inside the gremlin script bindings map instead of
    within the args portion of the request message.
    
    This commit resolves this issue by encapsulating all per-request settings as well as
    script bindings into a new RequestOptions struct which has an accompanying RequestOptionsBuilder.
    
    This can now be passed in through new Client.SubmitWithOptions() and DriverRemoteConnection.SubmitWithOptions() methods.
    Both original Submit() methods are unchanged in their behavior so this will not break any users.
---
 CHANGELOG.asciidoc                               |  2 +
 docs/src/reference/gremlin-applications.asciidoc |  3 +-
 docs/src/reference/gremlin-variants.asciidoc     | 23 ++++---
 gremlin-go/driver/client.go                      | 17 ++++-
 gremlin-go/driver/client_test.go                 | 23 ++++++-
 gremlin-go/driver/connection_test.go             |  8 +--
 gremlin-go/driver/driverRemoteConnection.go      | 11 ++-
 gremlin-go/driver/request.go                     | 32 ++++++---
 gremlin-go/driver/requestOptions.go              | 85 ++++++++++++++++++++++++
 gremlin-go/driver/requestOptions_test.go         | 75 +++++++++++++++++++++
 gremlin-go/driver/request_test.go                | 32 ++++++---
 11 files changed, 272 insertions(+), 39 deletions(-)

diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 1bfacbda70..7a14f6aa8b 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -26,6 +26,8 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 * Added `GraphFilter` support to `GraphSONRecordReader`.
 * gremlin-python aiohttp dependency requirement upper bound relaxed to <4.0.0
 * Changed `PartitionStrategy` to force its filters to the end of the chain for `Vertex` and `Edge` read steps, thus preserving order of the `has()`.
+* Added `RequestOptions` and `RequestOptionsBuilder` types to Go GLV to encapsulate per-request settings and bindings.
+* Added `SubmitWithOptions()` methods to `Client` and `DriverRemoteConnection` in Go GLV to pass `RequestOptions` to the server.
 
 [[release-3-5-5]]
 === TinkerPop 3.5.5 (Release Date: January 16, 2023)
diff --git a/docs/src/reference/gremlin-applications.asciidoc b/docs/src/reference/gremlin-applications.asciidoc
index a3dabeac0c..103071575b 100644
--- a/docs/src/reference/gremlin-applications.asciidoc
+++ b/docs/src/reference/gremlin-applications.asciidoc
@@ -612,7 +612,8 @@ list = g.V().has("person","name","marko").out("knows").toList()
 ----
 // script
 client, err := NewClient("ws://localhost:8182/gremlin")
-resultSet, err := client.Submit("g.V().has('person','name',name).out('knows')", map[string]interface{}{"name": "marko"})
+resultSet, err := client.SubmitWithOptions("g.V().has('person','name',name).out('knows')",
+	new(RequestOptionsBuilder).AddBinding("name", "marko").Create())
 result, err := resultSet.All()
 
 // bytecode
diff --git a/docs/src/reference/gremlin-variants.asciidoc b/docs/src/reference/gremlin-variants.asciidoc
index 30590dcd87..bb079ed714 100644
--- a/docs/src/reference/gremlin-variants.asciidoc
+++ b/docs/src/reference/gremlin-variants.asciidoc
@@ -293,22 +293,29 @@ fmt.Println(result[0].GetString()) <3>
 ----
 
 <1> Submit a script that simply returns a Count of vertexes.
-<2> Get results from resultSet. Block until the the script is evaluated and results are sent back by the server.
+<2> Get results from resultSet. Block until the script is evaluated and results are sent back by the server.
 <3> Use the result.
 
 ==== Per Request Settings
 
-The `client.Submit()` functions accept a `bindings` which expects a map. The `bindings` provide a way to include options
-that are specific to the request made with the call to `Submit()`. A good use-case for this feature is to set a per-request
-override to the `evaluationTimeout` so that it only applies to the current request.
+Both the `Client` and `DriverRemoteConnection` types have a `SubmitWithOptions(traversalString, requestOptions)` variant
+of the standard `Submit()` method. These methods allow a `RequestOptions` struct to be passed in which will augment the
+execution on the server. `RequestOptions` can be constructed
+using `RequestOptionsBuilder`. A good use-case for this feature is to set a per-request override to the
+`evaluationTimeout` so that it only applies to the current request.
 
 [source,go]
 ----
-resultSet, err := client.Submit("g.V().repeat(both()).times(100)", map[string]interface{}{"evaluationTimeout": 5000})
+options := new(RequestOptionsBuilder).
+			SetEvaluationTimeout(5000).
+			AddBinding("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`, `requestId`, `userAgent` and
-`evaluationTimeout`.
+`evaluationTimeout`. `RequestOptions` may also contain a map of variable `bindings` to be applied to the supplied
+traversal string.
 
 IMPORTANT: The preferred method for setting a per-request timeout for scripts is demonstrated above, but those familiar
 with bytecode may try `g.with("evaluationTimeout", 500)` within a script. Scripts with multiple traversals and multiple
@@ -316,9 +323,9 @@ timeouts will be interpreted as a sum of all timeouts identified in the script f
 
 [source,go]
 ----
-resultSet, err := client.Submit("g.with('evaluationTimeout', 500).addV().iterate();"+
+resultSet, err := client.SubmitWithOptions("g.with('evaluationTimeout', 500).addV().iterate();"+
   "g.addV().iterate();"+
-  "g.with('evaluationTimeout', 500).addV();", map[string]interface{}{"evaluationTimeout": 500})
+  "g.with('evaluationTimeout', 500).addV();", new(RequestOptionsBuilder).SetEvaluationTimeout(500).Create())
 results, err := resultSet.All()
 ----
 
diff --git a/gremlin-go/driver/client.go b/gremlin-go/driver/client.go
index 8e2f2cf7d2..872db55773 100644
--- a/gremlin-go/driver/client.go
+++ b/gremlin-go/driver/client.go
@@ -147,10 +147,10 @@ func (client *Client) Close() {
 	client.connections.close()
 }
 
-// Submit submits a Gremlin script to the server and returns a ResultSet.
-func (client *Client) Submit(traversalString string, bindings ...map[string]interface{}) (ResultSet, error) {
+// SubmitWithOptions submits a Gremlin script to the server with specified RequestOptions and returns a ResultSet.
+func (client *Client) SubmitWithOptions(traversalString string, requestOptions RequestOptions) (ResultSet, error) {
 	client.logHandler.logf(Debug, submitStartedString, traversalString)
-	request := makeStringRequest(traversalString, client.traversalSource, client.session, bindings...)
+	request := makeStringRequest(traversalString, client.traversalSource, client.session, requestOptions)
 	result, err := client.connections.write(&request)
 	if err != nil {
 		client.logHandler.logf(Error, logErrorGeneric, "Client.Submit()", err.Error())
@@ -158,6 +158,17 @@ func (client *Client) Submit(traversalString string, bindings ...map[string]inte
 	return result, 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
+// struct and use SubmitWithOptions().
+func (client *Client) Submit(traversalString string, bindings ...map[string]interface{}) (ResultSet, error) {
+	requestOptionsBuilder := new(RequestOptionsBuilder)
+	if len(bindings) > 0 {
+		requestOptionsBuilder.SetBindings(bindings[0])
+	}
+	return client.SubmitWithOptions(traversalString, requestOptionsBuilder.Create())
+}
+
 // submitBytecode submits Bytecode to the server to execute and returns a ResultSet.
 func (client *Client) submitBytecode(bytecode *Bytecode) (ResultSet, error) {
 	client.logHandler.logf(Debug, submitStartedBytecode, *bytecode)
diff --git a/gremlin-go/driver/client_test.go b/gremlin-go/driver/client_test.go
index 472d081e8a..76cc6d03ec 100644
--- a/gremlin-go/driver/client_test.go
+++ b/gremlin-go/driver/client_test.go
@@ -32,13 +32,14 @@ func TestClient(t *testing.T) {
 	testNoAuthAuthInfo := &AuthInfo{}
 	testNoAuthTlsConfig := &tls.Config{}
 
-	t.Run("Test client.submit()", func(t *testing.T) {
+	t.Run("Test client.Submit()", func(t *testing.T) {
 		skipTestsIfNotEnabled(t, integrationTestSuiteName, testNoAuthEnable)
 		client, err := NewClient(testNoAuthUrl,
 			func(settings *ClientSettings) {
 				settings.TlsConfig = testNoAuthTlsConfig
 				settings.AuthInfo = testNoAuthAuthInfo
 			})
+		defer client.Close()
 		assert.Nil(t, err)
 		assert.NotNil(t, client)
 		resultSet, err := client.Submit("g.V().count()")
@@ -48,6 +49,24 @@ func TestClient(t *testing.T) {
 		assert.Nil(t, err)
 		assert.True(t, ok)
 		assert.NotNil(t, result)
-		client.Close()
+	})
+
+	t.Run("Test client.SubmitWithOptions()", func(t *testing.T) {
+		skipTestsIfNotEnabled(t, integrationTestSuiteName, testNoAuthEnable)
+		client, err := NewClient(testNoAuthUrl,
+			func(settings *ClientSettings) {
+				settings.TlsConfig = testNoAuthTlsConfig
+				settings.AuthInfo = testNoAuthAuthInfo
+			})
+		defer client.Close()
+		assert.Nil(t, err)
+		assert.NotNil(t, client)
+		resultSet, err := client.SubmitWithOptions("g.V().count()", *new(RequestOptions))
+		assert.Nil(t, err)
+		assert.NotNil(t, resultSet)
+		result, ok, err := resultSet.One()
+		assert.Nil(t, err)
+		assert.True(t, ok)
+		assert.NotNil(t, result)
 	})
 }
diff --git a/gremlin-go/driver/connection_test.go b/gremlin-go/driver/connection_test.go
index 9c142d8bb3..b6e0045b2a 100644
--- a/gremlin-go/driver/connection_test.go
+++ b/gremlin-go/driver/connection_test.go
@@ -381,7 +381,7 @@ func TestConnection(t *testing.T) {
 		assert.NotNil(t, connection)
 		assert.Equal(t, established, connection.state)
 		defer deferredCleanup(t, connection)
-		request := makeStringRequest("g.V().count()", "g", "")
+		request := makeStringRequest("g.V().count()", "g", "", *new(RequestOptions))
 		resultSet, err := connection.write(&request)
 		assert.Nil(t, err)
 		assert.NotNil(t, resultSet)
@@ -399,7 +399,7 @@ func TestConnection(t *testing.T) {
 		assert.NotNil(t, connection)
 		assert.Equal(t, established, connection.state)
 		defer deferredCleanup(t, connection)
-		request := makeStringRequest("g.V().count()", "g", "")
+		request := makeStringRequest("g.V().count()", "g", "", *new(RequestOptions))
 		resultSet, err := connection.write(&request)
 		assert.Nil(t, err)
 		assert.NotNil(t, resultSet)
@@ -435,7 +435,7 @@ func TestConnection(t *testing.T) {
 		err = connection.close()
 		assert.Nil(t, err)
 		assert.Equal(t, closed, connection.state)
-		request := makeStringRequest("g.V().count()", "g", "")
+		request := makeStringRequest("g.V().count()", "g", "", *new(RequestOptions))
 		resultSet, err := connection.write(&request)
 		assert.Nil(t, resultSet)
 		assert.Equal(t, newError(err0102WriteConnectionClosedError), err)
@@ -451,7 +451,7 @@ func TestConnection(t *testing.T) {
 		assert.Equal(t, established, connection.state)
 		assert.Nil(t, err)
 		time.Sleep(120 * time.Second)
-		request := makeStringRequest("g.V().count()", "g", "")
+		request := makeStringRequest("g.V().count()", "g", "", *new(RequestOptions))
 		resultSet, err := connection.write(&request)
 		assert.Nil(t, resultSet)
 		assert.NotNil(t, err)
diff --git a/gremlin-go/driver/driverRemoteConnection.go b/gremlin-go/driver/driverRemoteConnection.go
index 4677c6c38d..cce81dbb25 100644
--- a/gremlin-go/driver/driverRemoteConnection.go
+++ b/gremlin-go/driver/driverRemoteConnection.go
@@ -163,15 +163,20 @@ func (driver *DriverRemoteConnection) Close() {
 	driver.isClosed = true
 }
 
-// Submit sends a string traversal to the server.
-func (driver *DriverRemoteConnection) Submit(traversalString string) (ResultSet, error) {
-	result, err := driver.client.Submit(traversalString)
+// SubmitWithOptions sends a string traversal to the server along with specified RequestOptions.
+func (driver *DriverRemoteConnection) SubmitWithOptions(traversalString string, requestOptions RequestOptions) (ResultSet, error) {
+	result, err := driver.client.SubmitWithOptions(traversalString, requestOptions)
 	if err != nil {
 		driver.client.logHandler.logf(Error, logErrorGeneric, "Driver.Submit()", err.Error())
 	}
 	return result, err
 }
 
+// Submit sends a string traversal to the server.
+func (driver *DriverRemoteConnection) Submit(traversalString string) (ResultSet, error) {
+	return driver.SubmitWithOptions(traversalString, *new(RequestOptions))
+}
+
 // submitBytecode sends a Bytecode traversal to the server.
 func (driver *DriverRemoteConnection) submitBytecode(bytecode *Bytecode) (ResultSet, error) {
 	if driver.isClosed {
diff --git a/gremlin-go/driver/request.go b/gremlin-go/driver/request.go
index 304317d9a3..d1cd8a9ee5 100644
--- a/gremlin-go/driver/request.go
+++ b/gremlin-go/driver/request.go
@@ -20,7 +20,6 @@ under the License.
 package gremlingo
 
 import (
-	"fmt"
 	"github.com/google/uuid"
 )
 
@@ -37,8 +36,7 @@ const sessionProcessor = "session"
 const stringOp = "eval"
 const stringProcessor = ""
 
-// Bindings should be a key-object map (different from Binding class in Bytecode).
-func makeStringRequest(stringGremlin string, traversalSource string, sessionId string, bindings ...map[string]interface{}) (req request) {
+func makeStringRequest(stringGremlin string, traversalSource string, sessionId string, requestOptions RequestOptions) (req request) {
 	newProcessor := stringProcessor
 	newArgs := map[string]interface{}{
 		"gremlin": stringGremlin,
@@ -50,13 +48,27 @@ func makeStringRequest(stringGremlin string, traversalSource string, sessionId s
 		newProcessor = sessionProcessor
 		newArgs["session"] = sessionId
 	}
-	requestId := uuid.New()
-	if len(bindings) > 0 {
-		newArgs["bindings"] = bindings[0]
-		customRequestId, err := uuid.Parse(fmt.Sprintf("%v", bindings[0]["requestId"]))
-		if err == nil {
-			requestId = customRequestId
-		}
+	var requestId uuid.UUID
+	if requestOptions.requestID == uuid.Nil {
+		requestId = uuid.New()
+	} else {
+		requestId = requestOptions.requestID
+	}
+
+	if requestOptions.bindings != nil {
+		newArgs["bindings"] = requestOptions.bindings
+	}
+
+	if requestOptions.evaluationTimeout != 0 {
+		newArgs["evaluationTimeout"] = requestOptions.evaluationTimeout
+	}
+
+	if requestOptions.batchSize != 0 {
+		newArgs["batchSize"] = requestOptions.batchSize
+	}
+
+	if requestOptions.userAgent != "" {
+		newArgs["userAgent"] = requestOptions.userAgent
 	}
 
 	return request{
diff --git a/gremlin-go/driver/requestOptions.go b/gremlin-go/driver/requestOptions.go
new file mode 100644
index 0000000000..4153eb162a
--- /dev/null
+++ b/gremlin-go/driver/requestOptions.go
@@ -0,0 +1,85 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+package gremlingo
+
+import (
+	"github.com/google/uuid"
+)
+
+type RequestOptions struct {
+	requestID         uuid.UUID
+	evaluationTimeout int
+	batchSize         int
+	userAgent         string
+	bindings          map[string]interface{}
+}
+
+type RequestOptionsBuilder struct {
+	requestID         uuid.UUID
+	evaluationTimeout int
+	batchSize         int
+	userAgent         string
+	bindings          map[string]interface{}
+}
+
+func (builder *RequestOptionsBuilder) SetRequestId(requestId uuid.UUID) *RequestOptionsBuilder {
+	builder.requestID = requestId
+	return builder
+}
+
+func (builder *RequestOptionsBuilder) SetEvaluationTimeout(evaluationTimeout int) *RequestOptionsBuilder {
+	builder.evaluationTimeout = evaluationTimeout
+	return builder
+}
+
+func (builder *RequestOptionsBuilder) SetBatchSize(batchSize int) *RequestOptionsBuilder {
+	builder.batchSize = batchSize
+	return builder
+}
+
+func (builder *RequestOptionsBuilder) SetUserAgent(userAgent string) *RequestOptionsBuilder {
+	builder.userAgent = userAgent
+	return builder
+}
+
+func (builder *RequestOptionsBuilder) SetBindings(bindings map[string]interface{}) *RequestOptionsBuilder {
+	builder.bindings = bindings
+	return builder
+}
+
+func (builder *RequestOptionsBuilder) AddBinding(key string, binding interface{}) *RequestOptionsBuilder {
+	if builder.bindings == nil {
+		builder.bindings = make(map[string]interface{})
+	}
+	builder.bindings[key] = binding
+	return builder
+}
+
+func (builder *RequestOptionsBuilder) Create() RequestOptions {
+	requestOptions := new(RequestOptions)
+
+	requestOptions.requestID = builder.requestID
+	requestOptions.evaluationTimeout = builder.evaluationTimeout
+	requestOptions.batchSize = builder.batchSize
+	requestOptions.userAgent = builder.userAgent
+	requestOptions.bindings = builder.bindings
+
+	return *requestOptions
+}
diff --git a/gremlin-go/driver/requestOptions_test.go b/gremlin-go/driver/requestOptions_test.go
new file mode 100644
index 0000000000..6eb6259262
--- /dev/null
+++ b/gremlin-go/driver/requestOptions_test.go
@@ -0,0 +1,75 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+package gremlingo
+
+import (
+	"github.com/google/uuid"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestRequestOptions(t *testing.T) {
+	t.Run("Test RequestOptionsBuilder with custom requestID", func(t *testing.T) {
+		requestId := uuid.New()
+		r := new(RequestOptionsBuilder).SetRequestId(requestId).Create()
+		assert.Equal(t, requestId, r.requestID)
+	})
+	t.Run("Test RequestOptionsBuilder with custom evaluationTimeout", func(t *testing.T) {
+		r := new(RequestOptionsBuilder).SetEvaluationTimeout(1234).Create()
+		assert.Equal(t, 1234, r.evaluationTimeout)
+	})
+	t.Run("Test RequestOptionsBuilder with custom batchSize", func(t *testing.T) {
+		r := new(RequestOptionsBuilder).SetBatchSize(123).Create()
+		assert.Equal(t, 123, r.batchSize)
+	})
+	t.Run("Test RequestOptionsBuilder with custom userAgent", func(t *testing.T) {
+		r := new(RequestOptionsBuilder).SetUserAgent("TestUserAgent").Create()
+		assert.Equal(t, "TestUserAgent", r.userAgent)
+	})
+	t.Run("Test RequestOptionsBuilder with custom bindings", func(t *testing.T) {
+		bindings := map[string]interface{}{"x": 2, "y": 5}
+		r := new(RequestOptionsBuilder).SetBindings(bindings).Create()
+		assert.Equal(t, bindings, r.bindings)
+	})
+	t.Run("Test RequestOptionsBuilder AddBinding() with no other bindings", func(t *testing.T) {
+		r := new(RequestOptionsBuilder).AddBinding("x", 2).AddBinding("y", 5).Create()
+		expectedBindings := map[string]interface{}{"x": 2, "y": 5}
+		assert.Equal(t, expectedBindings, r.bindings)
+	})
+	t.Run("Test RequestOptionsBuilder AddBinding() overwriting existing key", func(t *testing.T) {
+		r := new(RequestOptionsBuilder).AddBinding("x", 2).AddBinding("x", 5).Create()
+		expectedBindings := map[string]interface{}{"x": 5}
+		assert.Equal(t, expectedBindings, r.bindings)
+	})
+	t.Run("Test RequestOptionsBuilder AddBinding() with existing bindings", func(t *testing.T) {
+		bindings := map[string]interface{}{"x": 2, "y": 5}
+		r := new(RequestOptionsBuilder).SetBindings(bindings).AddBinding("z", 7).Create()
+		expectedBindings := map[string]interface{}{"x": 2, "y": 5, "z": 7}
+		assert.Equal(t, expectedBindings, r.bindings)
+	})
+	t.Run("Test RequestOptionsBuilder SetBinding(...), SetBinding(nil), AddBinding(...)", func(t *testing.T) {
+		bindings := map[string]interface{}{"x": 2, "y": 5}
+		r := new(RequestOptionsBuilder).SetBindings(bindings).
+			SetBindings(nil).AddBinding("z", 7).Create()
+		expectedBindings := map[string]interface{}{"z": 7}
+		assert.Equal(t, expectedBindings, r.bindings)
+	})
+}
diff --git a/gremlin-go/driver/request_test.go b/gremlin-go/driver/request_test.go
index 0e1d8433e8..c388a1273e 100644
--- a/gremlin-go/driver/request_test.go
+++ b/gremlin-go/driver/request_test.go
@@ -20,7 +20,6 @@ under the License.
 package gremlingo
 
 import (
-	"fmt"
 	"github.com/google/uuid"
 	"testing"
 
@@ -29,22 +28,39 @@ import (
 
 func TestRequest(t *testing.T) {
 	t.Run("Test makeStringRequest() with custom requestID", func(t *testing.T) {
-		requestId := fmt.Sprintf("%v", uuid.New())
-		r := makeStringRequest("g.V()", "g", "", map[string]interface{}{"requestId": requestId})
-		assert.Equal(t, requestId, fmt.Sprintf("%v", r.requestID))
+		requestId := uuid.New()
+		r := makeStringRequest("g.V()", "g", "",
+			new(RequestOptionsBuilder).SetRequestId(requestId).Create())
+		assert.Equal(t, requestId, r.requestID)
 	})
 
 	t.Run("Test makeStringRequest() with no bindings", func(t *testing.T) {
-		r := makeStringRequest("g.V()", "g", "")
+		r := makeStringRequest("g.V()", "g", "", *new(RequestOptions))
 		assert.NotNil(t, r.requestID)
 		assert.NotEqual(t, uuid.Nil, r.requestID)
 	})
 
 	t.Run("Test makeStringRequest() with custom evaluationTimeout", func(t *testing.T) {
-		r := makeStringRequest("g.V()", "g", "", map[string]interface{}{"evaluationTimeout": 1234})
+		r := makeStringRequest("g.V()", "g", "",
+			new(RequestOptionsBuilder).SetEvaluationTimeout(1234).Create())
 		assert.NotNil(t, r.requestID)
 		assert.NotEqual(t, uuid.Nil, r.requestID)
-		bindings := r.args["bindings"].(map[string]interface{})
-		assert.Equal(t, 1234, bindings["evaluationTimeout"])
+		assert.Equal(t, 1234, r.args["evaluationTimeout"])
+	})
+
+	t.Run("Test makeStringRequest() with custom batchSize", func(t *testing.T) {
+		r := makeStringRequest("g.V()", "g", "",
+			new(RequestOptionsBuilder).SetBatchSize(123).Create())
+		assert.NotNil(t, r.requestID)
+		assert.NotEqual(t, uuid.Nil, r.requestID)
+		assert.Equal(t, 123, r.args["batchSize"])
+	})
+
+	t.Run("Test makeStringRequest() with custom userAgent", func(t *testing.T) {
+		r := makeStringRequest("g.V()", "g", "",
+			new(RequestOptionsBuilder).SetUserAgent("TestUserAgent").Create())
+		assert.NotNil(t, r.requestID)
+		assert.NotEqual(t, uuid.Nil, r.requestID)
+		assert.Equal(t, "TestUserAgent", r.args["userAgent"])
 	})
 }