Skip to content

Commit 7fe1815

Browse files
author
haiyuwang
committed
Expose serialization functions for alternative transports
1 parent ebdec97 commit 7fe1815

File tree

7 files changed

+108
-27
lines changed

7 files changed

+108
-27
lines changed

gremlin-go/driver/client.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ func (client *Client) Close() {
149149
// SubmitWithOptions submits a Gremlin script to the server with specified RequestOptions and returns a ResultSet.
150150
func (client *Client) SubmitWithOptions(traversalString string, requestOptions RequestOptions) (ResultSet, error) {
151151
client.logHandler.logf(Debug, submitStartedString, traversalString)
152-
request := makeStringRequest(traversalString, client.traversalSource, client.session, requestOptions)
152+
request := MakeStringRequest(traversalString, client.traversalSource, client.session, requestOptions)
153153
result, err := client.connections.write(&request)
154154
if err != nil {
155155
client.logHandler.logf(Error, logErrorGeneric, "Client.Submit()", err.Error())
@@ -171,7 +171,7 @@ func (client *Client) Submit(traversalString string, bindings ...map[string]inte
171171
// submitBytecode submits Bytecode to the server to execute and returns a ResultSet.
172172
func (client *Client) submitBytecode(bytecode *Bytecode) (ResultSet, error) {
173173
client.logHandler.logf(Debug, submitStartedBytecode, *bytecode)
174-
request := makeBytecodeRequest(bytecode, client.traversalSource, client.session)
174+
request := MakeBytecodeRequest(bytecode, client.traversalSource, client.session)
175175
return client.connections.write(&request)
176176
}
177177

gremlin-go/driver/connection_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ func TestConnection(t *testing.T) {
382382
assert.NotNil(t, connection)
383383
assert.Equal(t, established, connection.state)
384384
defer deferredCleanup(t, connection)
385-
request := makeStringRequest("g.V().count()", "g", "", *new(RequestOptions))
385+
request := MakeStringRequest("g.V().count()", "g", "", *new(RequestOptions))
386386
resultSet, err := connection.write(&request)
387387
assert.Nil(t, err)
388388
assert.NotNil(t, resultSet)
@@ -400,7 +400,7 @@ func TestConnection(t *testing.T) {
400400
assert.NotNil(t, connection)
401401
assert.Equal(t, established, connection.state)
402402
defer deferredCleanup(t, connection)
403-
request := makeStringRequest("g.V().count()", "g", "", *new(RequestOptions))
403+
request := MakeStringRequest("g.V().count()", "g", "", *new(RequestOptions))
404404
resultSet, err := connection.write(&request)
405405
assert.Nil(t, err)
406406
assert.NotNil(t, resultSet)
@@ -436,7 +436,7 @@ func TestConnection(t *testing.T) {
436436
err = connection.close()
437437
assert.Nil(t, err)
438438
assert.Equal(t, closed, connection.state)
439-
request := makeStringRequest("g.V().count()", "g", "", *new(RequestOptions))
439+
request := MakeStringRequest("g.V().count()", "g", "", *new(RequestOptions))
440440
resultSet, err := connection.write(&request)
441441
assert.Nil(t, resultSet)
442442
assert.Equal(t, newError(err0102WriteConnectionClosedError), err)
@@ -452,7 +452,7 @@ func TestConnection(t *testing.T) {
452452
assert.Equal(t, established, connection.state)
453453
assert.Nil(t, err)
454454
time.Sleep(120 * time.Second)
455-
request := makeStringRequest("g.V().count()", "g", "", *new(RequestOptions))
455+
request := MakeStringRequest("g.V().count()", "g", "", *new(RequestOptions))
456456
resultSet, err := connection.write(&request)
457457
assert.Nil(t, resultSet)
458458
assert.NotNil(t, err)

gremlin-go/driver/protocol.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ func (protocol *gremlinServerWSProtocol) readLoop(resultSets *synchronizedMap, e
7272
}
7373

7474
// Deserialize message and unpack.
75-
resp, err := protocol.serializer.deserializeMessage(msg)
75+
resp, err := protocol.serializer.DeserializeMessage(msg)
7676
if err != nil {
7777
protocol.logHandler.logf(Error, logErrorGeneric, "gremlinServerWSProtocol.readLoop()", err.Error())
7878
readErrorHandler(resultSets, errorCallback, err, protocol.logHandler)
@@ -149,7 +149,7 @@ func (protocol *gremlinServerWSProtocol) responseHandler(resultSets *synchronize
149149
}
150150

151151
func (protocol *gremlinServerWSProtocol) write(request *request) error {
152-
bytes, err := protocol.serializer.serializeMessage(request)
152+
bytes, err := protocol.serializer.SerializeMessage(request)
153153
if err != nil {
154154
return err
155155
}

gremlin-go/driver/request.go

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,28 @@ const sessionProcessor = "session"
3636
const stringOp = "eval"
3737
const stringProcessor = ""
3838

39-
func makeStringRequest(stringGremlin string, traversalSource string, sessionId string, requestOptions RequestOptions) (req request) {
39+
// MakeStringRequest creates a request from a Gremlin string query for submission to a Gremlin server.
40+
//
41+
// This function is exposed publicly to enable alternative transport protocols (gRPC, HTTP/2, etc.)
42+
// to construct properly formatted requests outside the standard WebSocket client. The returned
43+
// request can then be serialized using SerializeMessage().
44+
//
45+
// Parameters:
46+
// - stringGremlin: The Gremlin query string to execute
47+
// - traversalSource: The name of the traversal source (typically "g")
48+
// - sessionId: Optional session ID for stateful requests (use "" for stateless)
49+
// - requestOptions: Options such as bindings, timeout, batch size, etc.
50+
//
51+
// Returns:
52+
// - request: A request structure ready for serialization
53+
//
54+
// Example for alternative transports:
55+
//
56+
// req := MakeStringRequest("g.V().count()", "g", "", RequestOptions{})
57+
// serializer := newGraphBinarySerializer(nil)
58+
// bytes, _ := serializer.(graphBinarySerializer).SerializeMessage(&req)
59+
// // Send bytes over gRPC, HTTP/2, etc.
60+
func MakeStringRequest(stringGremlin string, traversalSource string, sessionId string, requestOptions RequestOptions) (req request) {
4061
newProcessor := stringProcessor
4162
newArgs := map[string]interface{}{
4263
"gremlin": stringGremlin,
@@ -88,7 +109,28 @@ const bytecodeProcessor = "traversal"
88109
const authOp = "authentication"
89110
const authProcessor = "traversal"
90111

91-
func makeBytecodeRequest(bytecodeGremlin *Bytecode, traversalSource string, sessionId string) (req request) {
112+
// MakeBytecodeRequest creates a request from Gremlin bytecode for submission to a Gremlin server.
113+
//
114+
// This function is exposed publicly to enable alternative transport protocols (gRPC, HTTP/2, etc.)
115+
// to construct properly formatted requests outside the standard WebSocket client. The returned
116+
// request can then be serialized using SerializeMessage().
117+
//
118+
// Parameters:
119+
// - bytecodeGremlin: The Gremlin bytecode to execute
120+
// - traversalSource: The name of the traversal source (typically "g")
121+
// - sessionId: Optional session ID for stateful requests (use "" for stateless)
122+
//
123+
// Returns:
124+
// - request: A request structure ready for serialization
125+
//
126+
// Example for alternative transports:
127+
//
128+
// bytecode := g.V().HasLabel("person").Bytecode
129+
// req := MakeBytecodeRequest(bytecode, "g", "")
130+
// serializer := newGraphBinarySerializer(nil)
131+
// bytes, _ := serializer.(graphBinarySerializer).SerializeMessage(&req)
132+
// // Send bytes over gRPC, HTTP/2, etc.
133+
func MakeBytecodeRequest(bytecodeGremlin *Bytecode, traversalSource string, sessionId string) (req request) {
92134
newProcessor := bytecodeProcessor
93135
newArgs := map[string]interface{}{
94136
"gremlin": *bytecodeGremlin,

gremlin-go/driver/request_test.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,44 +20,45 @@ under the License.
2020
package gremlingo
2121

2222
import (
23-
"github.com/google/uuid"
2423
"testing"
2524

25+
"github.com/google/uuid"
26+
2627
"github.com/stretchr/testify/assert"
2728
)
2829

2930
func TestRequest(t *testing.T) {
3031
t.Run("Test makeStringRequest() with custom requestID", func(t *testing.T) {
3132
requestId := uuid.New()
32-
r := makeStringRequest("g.V()", "g", "",
33+
r := MakeStringRequest("g.V()", "g", "",
3334
new(RequestOptionsBuilder).SetRequestId(requestId).Create())
3435
assert.Equal(t, requestId, r.requestID)
3536
})
3637

3738
t.Run("Test makeStringRequest() with no bindings", func(t *testing.T) {
38-
r := makeStringRequest("g.V()", "g", "", *new(RequestOptions))
39+
r := MakeStringRequest("g.V()", "g", "", *new(RequestOptions))
3940
assert.NotNil(t, r.requestID)
4041
assert.NotEqual(t, uuid.Nil, r.requestID)
4142
})
4243

4344
t.Run("Test makeStringRequest() with custom evaluationTimeout", func(t *testing.T) {
44-
r := makeStringRequest("g.V()", "g", "",
45+
r := MakeStringRequest("g.V()", "g", "",
4546
new(RequestOptionsBuilder).SetEvaluationTimeout(1234).Create())
4647
assert.NotNil(t, r.requestID)
4748
assert.NotEqual(t, uuid.Nil, r.requestID)
4849
assert.Equal(t, 1234, r.args["evaluationTimeout"])
4950
})
5051

5152
t.Run("Test makeStringRequest() with custom batchSize", func(t *testing.T) {
52-
r := makeStringRequest("g.V()", "g", "",
53+
r := MakeStringRequest("g.V()", "g", "",
5354
new(RequestOptionsBuilder).SetBatchSize(123).Create())
5455
assert.NotNil(t, r.requestID)
5556
assert.NotEqual(t, uuid.Nil, r.requestID)
5657
assert.Equal(t, 123, r.args["batchSize"])
5758
})
5859

5960
t.Run("Test makeStringRequest() with custom userAgent", func(t *testing.T) {
60-
r := makeStringRequest("g.V()", "g", "",
61+
r := MakeStringRequest("g.V()", "g", "",
6162
new(RequestOptionsBuilder).SetUserAgent("TestUserAgent").Create())
6263
assert.NotNil(t, r.requestID)
6364
assert.NotEqual(t, uuid.Nil, r.requestID)

gremlin-go/driver/serializer.go

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ const graphBinaryMimeType = "application/vnd.graphbinary-v1.0"
3434

3535
// serializer interface for serializers.
3636
type serializer interface {
37-
serializeMessage(request *request) ([]byte, error)
38-
deserializeMessage(message []byte) (response, error)
37+
SerializeMessage(request *request) ([]byte, error)
38+
DeserializeMessage(message []byte) (response, error)
3939
}
4040

4141
// graphBinarySerializer serializes/deserializes message to/from GraphBinary.
@@ -95,8 +95,28 @@ func convertArgs(request *request, gs graphBinarySerializer) (map[string]interfa
9595
}
9696
}
9797

98-
// serializeMessage serializes a request message into GraphBinary.
99-
func (gs graphBinarySerializer) serializeMessage(request *request) ([]byte, error) {
98+
// SerializeMessage serializes a request message into GraphBinary format.
99+
//
100+
// This method is part of the serializer interface and is used internally by the WebSocket driver.
101+
// It is also exposed publicly to enable alternative transport protocols (gRPC, HTTP/2, etc.) to
102+
// serialize requests created with MakeBytecodeRequest() or MakeStringRequest().
103+
//
104+
// The serialized bytes can be transmitted over any transport protocol that supports binary data.
105+
//
106+
// Parameters:
107+
// - request: The request to serialize (created via MakeBytecodeRequest or MakeStringRequest)
108+
//
109+
// Returns:
110+
// - []byte: The GraphBinary-encoded request ready for transmission
111+
// - error: Any serialization error encountered
112+
//
113+
// Example for alternative transports:
114+
//
115+
// req := MakeBytecodeRequest(bytecode, "g", "")
116+
// serializer := newGraphBinarySerializer(nil)
117+
// bytes, err := serializer.(graphBinarySerializer).SerializeMessage(&req)
118+
// // Send bytes over custom transport
119+
func (gs graphBinarySerializer) SerializeMessage(request *request) ([]byte, error) {
100120
args, err := convertArgs(request, gs)
101121
if err != nil {
102122
return nil, err
@@ -184,8 +204,26 @@ func uuidToBigInt(requestID uuid.UUID) big.Int {
184204
return bigInt
185205
}
186206

187-
// deserializeMessage deserializes a response message.
188-
func (gs graphBinarySerializer) deserializeMessage(message []byte) (response, error) {
207+
// DeserializeMessage deserializes a GraphBinary-encoded response message.
208+
//
209+
// This method is part of the serializer interface and is used internally by the WebSocket driver.
210+
// It is also exposed publicly to enable alternative transport protocols (gRPC, HTTP/2, etc.) to
211+
// deserialize responses received from a Gremlin server.
212+
//
213+
// Parameters:
214+
// - message: The GraphBinary-encoded response bytes
215+
//
216+
// Returns:
217+
// - response: The deserialized response containing results and metadata
218+
// - error: Any deserialization error encountered
219+
//
220+
// Example for alternative transports:
221+
//
222+
// // Receive bytes from custom transport
223+
// serializer := newGraphBinarySerializer(nil)
224+
// resp, err := serializer.(graphBinarySerializer).DeserializeMessage(responseBytes)
225+
// results := resp.responseResult.data
226+
func (gs graphBinarySerializer) DeserializeMessage(message []byte) (response, error) {
189227
var msg response
190228

191229
if message == nil || len(message) == 0 {

gremlin-go/driver/serializer_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ func TestSerializer(t *testing.T) {
4242
args: map[string]interface{}{"gremlin": "g.V().count()", "aliases": map[string]interface{}{"g": "g"}},
4343
}
4444
serializer := newGraphBinarySerializer(newLogHandler(&defaultLogger{}, Error, language.English))
45-
serialized, _ := serializer.serializeMessage(&testRequest)
45+
serialized, _ := serializer.SerializeMessage(&testRequest)
4646
stringified := fmt.Sprintf("%v", serialized)
4747
if stringified != mapDataOrder1 && stringified != mapDataOrder2 {
4848
assert.Fail(t, "Error, expected serialized map data to match one of the provided binary arrays. Can vary based on ordering of keyset, but must map to one of two.")
@@ -52,7 +52,7 @@ func TestSerializer(t *testing.T) {
5252
t.Run("test serialized response message", func(t *testing.T) {
5353
responseByteArray := []byte{129, 0, 251, 37, 42, 74, 117, 221, 71, 191, 183, 78, 86, 53, 0, 12, 132, 100, 0, 0, 0, 200, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 4, 104, 111, 115, 116, 3, 0, 0, 0, 0, 16, 47, 49, 50, 55, 46, 48, 46, 48, 46, 49, 58, 54, 50, 48, 51, 53, 0, 0, 0, 0, 9, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0}
5454
serializer := newGraphBinarySerializer(newLogHandler(&defaultLogger{}, Error, language.English))
55-
response, err := serializer.deserializeMessage(responseByteArray)
55+
response, err := serializer.DeserializeMessage(responseByteArray)
5656
assert.Nil(t, err)
5757
assert.Equal(t, "fb252a4a-75dd-47bf-b74e-5635000c8464", response.responseID.String())
5858
assert.Equal(t, uint16(200), response.responseStatus.code)
@@ -69,7 +69,7 @@ func TestSerializer(t *testing.T) {
6969
}()
7070
responseByteArray := []byte{129, 0, 69, 222, 40, 55, 95, 62, 75, 249, 134, 133, 155, 133, 43, 151, 221, 68, 0, 0, 0, 200, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 4, 104, 111, 115, 116, 3, 0, 0, 0, 0, 18, 47, 49, 48, 46, 50, 52, 52, 46, 48, 46, 51, 51, 58, 53, 49, 52, 55, 48, 0, 0, 0, 0, 9, 0, 0, 0, 0, 1, 33, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 29, 106, 97, 110, 117, 115, 103, 114, 97, 112, 104, 46, 82, 101, 108, 97, 116, 105, 111, 110, 73, 100, 101, 110, 116, 105, 102, 105, 101, 114, 0, 0, 16, 1, 0, 0, 0, 0, 0, 0, 0, 0, 16, 240, 0, 0, 0, 0, 0, 0, 100, 21, 0, 0, 0, 0, 0, 0, 24, 30, 0, 0, 0, 0, 0, 0, 0, 32, 56}
7171
serializer := newGraphBinarySerializer(newLogHandler(&defaultLogger{}, Error, language.English))
72-
response, err := serializer.deserializeMessage(responseByteArray)
72+
response, err := serializer.DeserializeMessage(responseByteArray)
7373
assert.Nil(t, err)
7474
assert.Equal(t, "45de2837-5f3e-4bf9-8685-9b852b97dd44", response.responseID.String())
7575
assert.Equal(t, uint16(200), response.responseStatus.code)
@@ -91,7 +91,7 @@ func TestSerializerFailures(t *testing.T) {
9191
args: map[string]interface{}{"invalidInput": "invalidInput", "aliases": map[string]interface{}{"g": "g"}},
9292
}
9393
serializer := newGraphBinarySerializer(newLogHandler(&defaultLogger{}, Error, language.English))
94-
resp, err := serializer.serializeMessage(&testRequest)
94+
resp, err := serializer.SerializeMessage(&testRequest)
9595
assert.Nil(t, resp)
9696
assert.NotNil(t, err)
9797
assert.True(t, isSameErrorCode(newError(err0704ConvertArgsNoSerializerError), err))
@@ -100,7 +100,7 @@ func TestSerializerFailures(t *testing.T) {
100100
t.Run("test unkownCustomType failure", func(t *testing.T) {
101101
responseByteArray := []byte{129, 0, 69, 222, 40, 55, 95, 62, 75, 249, 134, 133, 155, 133, 43, 151, 221, 68, 0, 0, 0, 200, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 4, 104, 111, 115, 116, 3, 0, 0, 0, 0, 18, 47, 49, 48, 46, 50, 52, 52, 46, 48, 46, 51, 51, 58, 53, 49, 52, 55, 48, 0, 0, 0, 0, 9, 0, 0, 0, 0, 1, 33, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 29, 106, 97, 110, 117, 115, 103, 114, 97, 112, 104, 46, 82, 101, 108, 97, 116, 105, 111, 110, 73, 100, 101, 110, 116, 105, 102, 105, 101, 114, 0, 0, 16, 1, 0, 0, 0, 0, 0, 0, 0, 0, 16, 240, 0, 0, 0, 0, 0, 0, 100, 21, 0, 0, 0, 0, 0, 0, 24, 30, 0, 0, 0, 0, 0, 0, 0, 32, 56}
102102
serializer := newGraphBinarySerializer(newLogHandler(&defaultLogger{}, Error, language.English))
103-
resp, err := serializer.deserializeMessage(responseByteArray)
103+
resp, err := serializer.DeserializeMessage(responseByteArray)
104104
// a partial message will still be returned
105105
assert.NotNil(t, resp)
106106
assert.NotNil(t, err)

0 commit comments

Comments
 (0)