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 2025/01/23 23:34:10 UTC
(tinkerpop) branch go-type-ser created (now 3735d7eb61)
This is an automated email from the ASF dual-hosted git repository.
xiazcy pushed a change to branch go-type-ser
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
at 3735d7eb61 update graph binary serializer to 4.0.0 spec
This branch includes the following new commits:
new 3735d7eb61 update graph binary serializer to 4.0.0 spec
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
(tinkerpop) 01/01: update graph binary serializer to 4.0.0 spec
Posted by xi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
xiazcy pushed a commit to branch go-type-ser
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit 3735d7eb61c8517c0de038217e611214bbebc3d6
Author: Yang Xia <55...@users.noreply.github.com>
AuthorDate: Thu Jan 23 15:33:56 2025 -0800
update graph binary serializer to 4.0.0 spec
---
gremlin-go/driver/graphBinary.go | 630 ++++++++++------------------------
gremlin-go/driver/graphBinary_test.go | 35 +-
gremlin-go/driver/serializer.go | 62 +---
gremlin-go/go.mod | 4 +
gremlin-go/go.sum | 9 +
5 files changed, 231 insertions(+), 509 deletions(-)
diff --git a/gremlin-go/driver/graphBinary.go b/gremlin-go/driver/graphBinary.go
index 39c6d2f029..fb6b2f30dd 100644
--- a/gremlin-go/driver/graphBinary.go
+++ b/gremlin-go/driver/graphBinary.go
@@ -23,6 +23,7 @@ import (
"bytes"
"encoding/binary"
"fmt"
+ "github.com/wk8/go-ordered-map/v2"
"math"
"math/big"
"reflect"
@@ -38,54 +39,33 @@ type dataType uint8
// dataType defined as constants.
const (
- customType dataType = 0x00
- intType dataType = 0x01
- longType dataType = 0x02
- stringType dataType = 0x03
- dateType dataType = 0x04
- timestampType dataType = 0x05
- classType dataType = 0x06
- doubleType dataType = 0x07
- floatType dataType = 0x08
- listType dataType = 0x09
- mapType dataType = 0x0a
- setType dataType = 0x0b
- uuidType dataType = 0x0c
- edgeType dataType = 0x0d
- pathType dataType = 0x0e
- propertyType dataType = 0x0f
- vertexType dataType = 0x11
- vertexPropertyType dataType = 0x12
- barrierType dataType = 0x13
- bindingType dataType = 0x14
- cardinalityType dataType = 0x16
- bytecodeType dataType = 0x15
- columnType dataType = 0x17
- directionType dataType = 0x18
- operatorType dataType = 0x19
- orderType dataType = 0x1a
- pickType dataType = 0x1b
- popType dataType = 0x1c
- lambdaType dataType = 0x1d
- pType dataType = 0x1e
- scopeType dataType = 0x1f
- tType dataType = 0x20
- traverserType dataType = 0x21
- bigDecimalType dataType = 0x22
- bigIntegerType dataType = 0x23
- byteType dataType = 0x24
- byteBuffer dataType = 0x25
- shortType dataType = 0x26
- booleanType dataType = 0x27
- textPType dataType = 0x28
- traversalStrategyType dataType = 0x29
- bulkSetType dataType = 0x2a
- mergeType dataType = 0x2e
- dtType dataType = 0x2f
- metricsType dataType = 0x2c
- traversalMetricsType dataType = 0x2d
- durationType dataType = 0x81
- nullType dataType = 0xFE
+ customType dataType = 0x00
+ intType dataType = 0x01
+ longType dataType = 0x02
+ stringType dataType = 0x03
+ datetimeType dataType = 0x04
+ doubleType dataType = 0x07
+ floatType dataType = 0x08
+ listType dataType = 0x09
+ mapType dataType = 0x0a
+ setType dataType = 0x0b
+ uuidType dataType = 0x0c
+ edgeType dataType = 0x0d
+ pathType dataType = 0x0e
+ propertyType dataType = 0x0f
+ vertexType dataType = 0x11
+ vertexPropertyType dataType = 0x12
+ directionType dataType = 0x18
+ tType dataType = 0x20
+ bigDecimalType dataType = 0x22
+ bigIntegerType dataType = 0x23
+ byteType dataType = 0x24
+ byteBuffer dataType = 0x25
+ shortType dataType = 0x26
+ booleanType dataType = 0x27
+ mergeType dataType = 0x2e
+ durationType dataType = 0x81
+ nullType dataType = 0xFE
)
var nullBytes = []byte{nullType.getCodeByte(), 0x01}
@@ -168,92 +148,45 @@ func mapWriter(value interface{}, buffer *bytes.Buffer, typeSerializer *graphBin
return buffer.Bytes(), nil
}
- v := reflect.ValueOf(value)
- keys := v.MapKeys()
- err := binary.Write(buffer, binary.BigEndian, int32(len(keys)))
- if err != nil {
- return nil, err
- }
- for _, k := range keys {
- convKey := k.Convert(v.Type().Key())
- // serialize k
- _, err := typeSerializer.write(k.Interface(), buffer)
+ if val, ok := value.(*orderedmap.OrderedMap[interface{}, interface{}]); ok {
+ err := binary.Write(buffer, binary.BigEndian, int32(val.Len()))
if err != nil {
return nil, err
}
- // serialize v.MapIndex(c_key)
- val := v.MapIndex(convKey)
- _, err = typeSerializer.write(val.Interface(), buffer)
- if err != nil {
- return nil, err
- }
- }
- return buffer.Bytes(), nil
-}
-
-func instructionWriter(instructions []instruction, buffer *bytes.Buffer, typeSerializer *graphBinaryTypeSerializer) error {
- // Write {steps_length}, i.e number of steps.
- err := binary.Write(buffer, binary.BigEndian, int32(len(instructions)))
- if err != nil {
- return err
- }
-
- // Write {step_0} to {step_n}.
- for _, instruction := range instructions {
- // Write {name} of {step_i}.
- // Note: {name} follows string writing, therefore write string length followed by actual string.
- _, err = typeSerializer.writeValue(instruction.operator, buffer, false)
- if err != nil {
- return err
+ for pair := val.Oldest(); pair != nil; pair = pair.Next() {
+ // serialize k
+ _, err := typeSerializer.write(pair.Key, buffer)
+ if err != nil {
+ return nil, err
+ }
+ // serialize v
+ _, err = typeSerializer.write(pair.Value, buffer)
+ if err != nil {
+ return nil, err
+ }
}
-
- // Write {values_length} of {step_i}.
- err = binary.Write(buffer, binary.BigEndian, int32(len(instruction.arguments)))
+ } else {
+ v := reflect.ValueOf(value)
+ keys := v.MapKeys()
+ err := binary.Write(buffer, binary.BigEndian, int32(len(keys)))
if err != nil {
- return err
+ return nil, err
}
-
- // Write {values_0} to {values_n}.
- for _, argument := range instruction.arguments {
- _, err = typeSerializer.write(argument, buffer)
+ for _, k := range keys {
+ convKey := k.Convert(v.Type().Key())
+ // serialize k
+ _, err := typeSerializer.write(k.Interface(), buffer)
+ if err != nil {
+ return nil, err
+ }
+ // serialize v.MapIndex(c_key)
+ val := v.MapIndex(convKey)
+ _, err = typeSerializer.write(val.Interface(), buffer)
if err != nil {
- return err
+ return nil, err
}
}
}
- return nil
-}
-
-// Format: {steps_length}{step_0}…{step_n}{sources_length}{source_0}…{source_n}
-// Where:
-//
-// {steps_length} is an Int value describing the amount of steps.
-// {step_i} is composed of {name}{values_length}{value_0}…{value_n}, where:
-// {name} is a String. This is also known as the operator.
-// {values_length} is an Int describing the amount values.
-// {value_i} is a fully qualified typed value composed of {type_code}{type_info}{value_flag}{value} describing the step argument.
-func bytecodeWriter(value interface{}, buffer *bytes.Buffer, typeSerializer *graphBinaryTypeSerializer) ([]byte, error) {
- var bc Bytecode
- switch typedVal := value.(type) {
- case *GraphTraversal:
- bc = *typedVal.Bytecode
- case Bytecode:
- bc = typedVal
- case *Bytecode:
- bc = *typedVal
- default:
- return nil, newError(err0402BytecodeWriterError)
- }
-
- // Write {steps_length} and {step_0} through {step_n}, then {sources_length} and {source_0} through {source_n}
- err := instructionWriter(bc.stepInstructions, buffer, typeSerializer)
- if err != nil {
- return nil, err
- }
- err = instructionWriter(bc.sourceInstructions, buffer, typeSerializer)
- if err != nil {
- return nil, err
- }
return buffer.Bytes(), nil
}
@@ -366,16 +299,6 @@ func bigDecimalWriter(value interface{}, buffer *bytes.Buffer, typeSerializer *g
return bigIntWriter(v.UnscaledValue, buffer, typeSerializer)
}
-func classWriter(value interface{}, buffer *bytes.Buffer, typeSerializer *graphBinaryTypeSerializer) ([]byte, error) {
- var v GremlinType
- if reflect.TypeOf(value).Kind() == reflect.Ptr {
- v = *(value.(*GremlinType))
- } else {
- v = value.(GremlinType)
- }
- return stringWriter(v.Fqcn, buffer, typeSerializer)
-}
-
// Format: {Id}{Label}{properties}
func vertexWriter(value interface{}, buffer *bytes.Buffer, typeSerializer *graphBinaryTypeSerializer) ([]byte, error) {
v := value.(*Vertex)
@@ -385,7 +308,7 @@ func vertexWriter(value interface{}, buffer *bytes.Buffer, typeSerializer *graph
}
// Not fully qualified.
- _, err = typeSerializer.writeValue(v.Label, buffer, false)
+ _, err = typeSerializer.writeValue([1]string{v.Label}, buffer, false)
if err != nil {
return nil, err
}
@@ -403,7 +326,7 @@ func edgeWriter(value interface{}, buffer *bytes.Buffer, typeSerializer *graphBi
}
// Not fully qualified
- _, err = typeSerializer.writeValue(e.Label, buffer, false)
+ _, err = typeSerializer.writeValue([1]string{e.Label}, buffer, false)
if err != nil {
return nil, err
}
@@ -465,7 +388,7 @@ func vertexPropertyWriter(value interface{}, buffer *bytes.Buffer, typeSerialize
}
// Not fully qualified.
- _, err = typeSerializer.writeValue(vp.Label, buffer, false)
+ _, err = typeSerializer.writeValue([1]string{vp.Label}, buffer, false)
if err != nil {
return nil, err
}
@@ -502,7 +425,29 @@ func setWriter(value interface{}, buffer *bytes.Buffer, typeSerializer *graphBin
func timeWriter(value interface{}, buffer *bytes.Buffer, _ *graphBinaryTypeSerializer) ([]byte, error) {
t := value.(time.Time)
- err := binary.Write(buffer, binary.BigEndian, t.UnixMilli())
+ err := binary.Write(buffer, binary.BigEndian, int32(t.Year()))
+ if err != nil {
+ return nil, err
+ }
+ err = binary.Write(buffer, binary.BigEndian, byte(t.Month()))
+ if err != nil {
+ return nil, err
+ }
+ err = binary.Write(buffer, binary.BigEndian, byte(t.Day()))
+ if err != nil {
+ return nil, err
+ }
+ // construct time of day in nanoseconds
+ h := t.Hour()
+ m := t.Minute()
+ s := t.Second()
+ ns := (h * 60 * 60 * 1e9) + (m * 60 * 1e9) + (s * 1e9) + t.Nanosecond()
+ err = binary.Write(buffer, binary.BigEndian, int64(ns))
+ if err != nil {
+ return nil, err
+ }
+ _, os := t.Zone()
+ err = binary.Write(buffer, binary.BigEndian, int32(os))
if err != nil {
return nil, err
}
@@ -534,32 +479,6 @@ func enumWriter(value interface{}, buffer *bytes.Buffer, typeSerializer *graphBi
return buffer.Bytes(), err
}
-// Format: {language}{script}{arguments_length}
-func lambdaWriter(value interface{}, buffer *bytes.Buffer, typeSerializer *graphBinaryTypeSerializer) ([]byte, error) {
- lambda := value.(*Lambda)
- if lambda.Language == "" {
- lambda.Language = "gremlin-groovy"
- }
- _, err := typeSerializer.writeValue(lambda.Language, buffer, false)
- if err != nil {
- return nil, err
- }
-
- _, err = typeSerializer.writeValue(lambda.Script, buffer, false)
- if err != nil {
- return nil, err
- }
-
- // It's hard to know how many parameters there are without extensive string parsing.
- // Instead, we can set -1 which means unknown.
- err = binary.Write(buffer, binary.BigEndian, int32(-1))
- if err != nil {
- return nil, err
- }
-
- return buffer.Bytes(), nil
-}
-
// Format: {strategy_class}{configuration}
func traversalStrategyWriter(value interface{}, buffer *bytes.Buffer, typeSerializer *graphBinaryTypeSerializer) ([]byte, error) {
ts := value.(*traversalStrategy)
@@ -572,84 +491,8 @@ func traversalStrategyWriter(value interface{}, buffer *bytes.Buffer, typeSerial
return mapWriter(ts.configuration, buffer, typeSerializer)
}
-func pWriter(value interface{}, buffer *bytes.Buffer, typeSerializer *graphBinaryTypeSerializer) ([]byte, error) {
- var v p
- if reflect.TypeOf(value).Kind() == reflect.Ptr {
- v = *(value.(*p))
- } else {
- v = value.(p)
- }
- _, err := typeSerializer.writeValue(v.operator, buffer, false)
- if err != nil {
- return nil, err
- }
-
- err = binary.Write(buffer, binary.BigEndian, int32(len(v.values)))
- if err != nil {
- return nil, err
- }
-
- for _, pValue := range v.values {
- _, err := typeSerializer.write(pValue, buffer)
- if err != nil {
- return nil, err
- }
- }
- return buffer.Bytes(), err
-}
-
-func textPWriter(value interface{}, buffer *bytes.Buffer, typeSerializer *graphBinaryTypeSerializer) ([]byte, error) {
- var v textP
- if reflect.TypeOf(value).Kind() == reflect.Ptr {
- v = *(value.(*textP))
- } else {
- v = value.(textP)
- }
- _, err := typeSerializer.writeValue(v.operator, buffer, false)
- if err != nil {
- return nil, err
- }
-
- err = binary.Write(buffer, binary.BigEndian, int32(len(v.values)))
- if err != nil {
- return nil, err
- }
-
- for _, pValue := range v.values {
- _, err := typeSerializer.write(pValue, buffer)
- if err != nil {
- return nil, err
- }
- }
- return buffer.Bytes(), err
-}
-
-// Format: {key}{value}
-func bindingWriter(value interface{}, buffer *bytes.Buffer, typeSerializer *graphBinaryTypeSerializer) ([]byte, error) {
- var v Binding
- if reflect.TypeOf(value).Kind() == reflect.Ptr {
- v = *(value.(*Binding))
- } else {
- v = value.(Binding)
- }
-
- // Not fully qualified.
- _, err := typeSerializer.writeValue(v.Key, buffer, false)
- if err != nil {
- return nil, err
- }
-
- _, err = typeSerializer.write(v.Value, buffer)
- if err != nil {
- return nil, err
- }
- return buffer.Bytes(), nil
-}
-
func (serializer *graphBinaryTypeSerializer) getType(val interface{}) (dataType, error) {
switch val.(type) {
- case *Bytecode, Bytecode, *GraphTraversal:
- return bytecodeType, nil
case string:
return stringType, nil
case uint, uint64, *big.Int:
@@ -678,58 +521,26 @@ func (serializer *graphBinaryTypeSerializer) getType(val interface{}) (dataType,
return propertyType, nil
case *VertexProperty:
return vertexPropertyType, nil
- case *Lambda:
- return lambdaType, nil
- case *traversalStrategy:
- return traversalStrategyType, nil
case *Path:
return pathType, nil
case Set:
return setType, nil
case time.Time:
- return dateType, nil
+ return datetimeType, nil
case time.Duration:
return durationType, nil
- case cardinality:
- return cardinalityType, nil
- case column:
- return columnType, nil
case direction:
return directionType, nil
- case operator:
- return operatorType, nil
- case order:
- return orderType, nil
- case pick:
- return pickType, nil
- case pop:
- return popType, nil
case t:
return tType, nil
- case barrier:
- return barrierType, nil
- case scope:
- return scopeType, nil
case merge:
return mergeType, nil
- case dt:
- return dtType, nil
- case p, Predicate:
- return pType, nil
- case textP, TextPredicate:
- return textPType, nil
- case *Binding, Binding:
- return bindingType, nil
case *BigDecimal, BigDecimal:
return bigDecimalType, nil
- case *GremlinType, GremlinType:
- return classType, nil
- case *Metrics, Metrics:
- return metricsType, nil
- case *TraversalMetrics, TraversalMetrics:
- return traversalMetricsType, nil
case *ByteBuffer, ByteBuffer:
return byteBuffer, nil
+ case *orderedmap.OrderedMap[interface{}, interface{}], orderedmap.OrderedMap[interface{}, interface{}]:
+ return mapType, nil
default:
switch reflect.TypeOf(val).Kind() {
case reflect.Map:
@@ -926,8 +737,6 @@ func getDefaultValue(dataType dataType) interface{} {
switch dataType {
case intType, bigIntegerType, longType, shortType, byteType, booleanType, floatType, doubleType:
return 0
- case traverserType, stringType:
- return ""
case uuidType:
return uuid.Nil
case vertexType:
@@ -942,7 +751,7 @@ func getDefaultValue(dataType dataType) interface{} {
return Path{}
case setType:
return SimpleSet{}
- case dateType, timestampType:
+ case datetimeType:
return time.Time{}
case durationType:
return time.Duration(0)
@@ -952,15 +761,28 @@ func getDefaultValue(dataType dataType) interface{} {
}
// Composite
-func readList(data *[]byte, i *int) (interface{}, error) {
+func readList(data *[]byte, i *int, flag byte) (interface{}, error) {
sz := readIntSafe(data, i)
var valList []interface{}
- for j := int32(0); j < sz; j++ {
- val, err := readFullyQualifiedNullable(data, i, true)
- if err != nil {
- return nil, err
+ if flag == 0x02 {
+ for j := int32(0); j < sz; j++ {
+ val, err := readFullyQualifiedNullable(data, i, true)
+ if err != nil {
+ return nil, err
+ }
+ bulk := readIntSafe(data, i)
+ for k := int32(0); k < bulk; k++ {
+ valList = append(valList, val)
+ }
+ }
+ } else {
+ for j := int32(0); j < sz; j++ {
+ val, err := readFullyQualifiedNullable(data, i, true)
+ if err != nil {
+ return nil, err
+ }
+ valList = append(valList, val)
}
- valList = append(valList, val)
}
return valList, nil
}
@@ -975,32 +797,59 @@ func readByteBuffer(data *[]byte, i *int) (interface{}, error) {
return r, nil
}
-func readMap(data *[]byte, i *int) (interface{}, error) {
+func readMap(data *[]byte, i *int, flag byte) (interface{}, error) {
sz := readUint32Safe(data, i)
- var mapData = make(map[interface{}]interface{})
- for j := uint32(0); j < sz; j++ {
- k, err := readFullyQualifiedNullable(data, i, true)
- if err != nil {
- return nil, err
- }
- v, err := readFullyQualifiedNullable(data, i, true)
- if err != nil {
- return nil, err
+ if flag == 0x02 {
+ var mapData = orderedmap.New[interface{}, interface{}]()
+ for j := uint32(0); j < sz; j++ {
+ k, err := readFullyQualifiedNullable(data, i, true)
+ if err != nil {
+ return nil, err
+ }
+ v, err := readFullyQualifiedNullable(data, i, true)
+ if err != nil {
+ return nil, err
+ }
+ if k == nil {
+ mapData.Set(nil, v)
+ } else if reflect.TypeOf(k).Comparable() {
+ mapData.Set(k, v)
+ } else {
+ switch reflect.TypeOf(k).Kind() {
+ case reflect.Map:
+ mapData.Set(&k, v)
+ default:
+ mapData.Set(fmt.Sprint(k), v)
+ }
+ }
}
- if k == nil {
- mapData[nil] = v
- } else if reflect.TypeOf(k).Comparable() {
- mapData[k] = v
- } else {
- switch reflect.TypeOf(k).Kind() {
- case reflect.Map:
- mapData[&k] = v
- default:
- mapData[fmt.Sprint(k)] = v
+ return mapData, nil
+ } else {
+ var mapData = make(map[interface{}]interface{})
+ for j := uint32(0); j < sz; j++ {
+ k, err := readFullyQualifiedNullable(data, i, true)
+ if err != nil {
+ return nil, err
+ }
+ v, err := readFullyQualifiedNullable(data, i, true)
+ if err != nil {
+ return nil, err
+ }
+ if k == nil {
+ mapData[nil] = v
+ } else if reflect.TypeOf(k).Comparable() {
+ mapData[k] = v
+ } else {
+ switch reflect.TypeOf(k).Kind() {
+ case reflect.Map:
+ mapData[&k] = v
+ default:
+ mapData[fmt.Sprint(k)] = v
+ }
}
}
+ return mapData, nil
}
- return mapData, nil
}
func readMapUnqualified(data *[]byte, i *int) (interface{}, error) {
@@ -1028,7 +877,8 @@ func readMapUnqualified(data *[]byte, i *int) (interface{}, error) {
}
func readSet(data *[]byte, i *int) (interface{}, error) {
- list, err := readList(data, i)
+ // TODO placeholder flag
+ list, err := readList(data, i, 0x00)
if err != nil {
return nil, err
}
@@ -1041,7 +891,15 @@ func readUuid(data *[]byte, i *int) (interface{}, error) {
}
func timeReader(data *[]byte, i *int) (interface{}, error) {
- return time.UnixMilli(readLongSafe(data, i)), nil
+ year := readIntSafe(data, i)
+ month := readByteSafe(data, i)
+ day := readByteSafe(data, i)
+ ns := readLongSafe(data, i)
+ offset := readIntSafe(data, i)
+ // only way to pass offset info, timezone display is fixed to UTC as consequence (offset is calculated properly)
+ loc := time.FixedZone("UTC", int(offset))
+ datetime := time.Date(int(year), time.Month(month), int(day), 0, 0, 0, int(ns), loc)
+ return datetime, nil
}
func durationReader(data *[]byte, i *int) (interface{}, error) {
@@ -1063,11 +921,11 @@ func vertexReaderReadingProperties(data *[]byte, i *int, readProperties bool) (i
if err != nil {
return nil, err
}
- label, err := readUnqualified(data, i, stringType, false)
+ label, err := readUnqualified(data, i, listType, false)
if err != nil {
return nil, err
}
- v.Label = label.(string)
+ v.Label = label.([]interface{})[0].(string)
if readProperties {
props, err := readFullyQualifiedNullable(data, i, true)
if err != nil {
@@ -1090,11 +948,11 @@ func edgeReader(data *[]byte, i *int) (interface{}, error) {
if err != nil {
return nil, err
}
- label, err := readUnqualified(data, i, stringType, false)
+ label, err := readUnqualified(data, i, listType, false)
if err != nil {
return nil, err
}
- e.Label = label.(string)
+ e.Label = label.([]interface{})[0].(string)
v, err := vertexReaderReadingProperties(data, i, false)
if err != nil {
return nil, err
@@ -1142,11 +1000,11 @@ func vertexPropertyReader(data *[]byte, i *int) (interface{}, error) {
if err != nil {
return nil, err
}
- label, err := readUnqualified(data, i, stringType, false)
+ label, err := readUnqualified(data, i, listType, false)
if err != nil {
return nil, err
}
- vp.Label = label.(string)
+ vp.Label = label.([]interface{})[0].(string)
vp.Value, err = readFullyQualifiedNullable(data, i, true)
if err != nil {
return nil, err
@@ -1186,35 +1044,6 @@ func pathReader(data *[]byte, i *int) (interface{}, error) {
return path, err
}
-// {bulk int}{fully qualified value}
-func traverserReader(data *[]byte, i *int) (interface{}, error) {
- var err error
- traverser := new(Traverser)
- traverser.bulk = readLongSafe(data, i)
- traverser.value, err = readFullyQualifiedNullable(data, i, true)
- if err != nil {
- return nil, err
- }
- return traverser, nil
-}
-
-// {int32 length}{fully qualified item_0}{int64 repetition_0}...{fully qualified item_n}{int64 repetition_n}
-func bulkSetReader(data *[]byte, i *int) (interface{}, error) {
- sz := int(readIntSafe(data, i))
- var valList []interface{}
- for j := 0; j < sz; j++ {
- val, err := readFullyQualifiedNullable(data, i, true)
- if err != nil {
- return nil, err
- }
- rep := readLongSafe(data, i)
- for k := 0; k < int(rep); k++ {
- valList = append(valList, val)
- }
- }
- return valList, nil
-}
-
// {type code (always string so ignore)}{nil code (always false so ignore)}{int32 size}{string enum}
func enumReader(data *[]byte, i *int) (interface{}, error) {
typeCode := readDataType(data, i)
@@ -1225,113 +1054,6 @@ func enumReader(data *[]byte, i *int) (interface{}, error) {
return readString(data, i)
}
-// {unqualified key}{fully qualified value}
-func bindingReader(data *[]byte, i *int) (interface{}, error) {
- b := new(Binding)
- val, err := readUnqualified(data, i, stringType, false)
- if err != nil {
- return nil, err
- }
- b.Key = val.(string)
-
- b.Value, err = readFullyQualifiedNullable(data, i, true)
- if err != nil {
- return nil, err
- }
- return b, nil
-}
-
-// {id}{name}{duration}{counts}{annotations}{nested_metrics}
-func metricsReader(data *[]byte, i *int) (interface{}, error) {
- metrics := new(Metrics)
- val, err := readUnqualified(data, i, stringType, false)
- if err != nil {
- return nil, err
- }
- metrics.Id = val.(string)
-
- val, err = readUnqualified(data, i, stringType, false)
- if err != nil {
- return nil, err
- }
- metrics.Name = val.(string)
-
- dur, err := readLong(data, i)
- if err != nil {
- return nil, err
- }
- metrics.Duration = dur.(int64)
-
- counts, err := readMap(data, i)
- cmap := counts.(map[interface{}]interface{})
- if err != nil {
- return nil, err
- }
- metrics.Counts = make(map[string]int64, len(cmap))
- for k := range cmap {
- metrics.Counts[k.(string)] = cmap[k].(int64)
- }
-
- annotations, err := readMap(data, i)
- if err != nil {
- return nil, err
- }
- amap := annotations.(map[interface{}]interface{})
- if err != nil {
- return nil, err
- }
- metrics.Annotations = make(map[string]interface{}, len(amap))
- for k := range amap {
- metrics.Annotations[k.(string)] = amap[k]
- }
-
- nested, err := readList(data, i)
- if err != nil {
- return nil, err
- }
- list := nested.([]interface{})
- metrics.NestedMetrics = make([]Metrics, len(list))
- for i, metric := range list {
- metrics.NestedMetrics[i] = metric.(Metrics)
- }
-
- return metrics, nil
-}
-
-// {id}{name}{duration}{counts}{annotations}{nested_metrics}
-func traversalMetricsReader(data *[]byte, i *int) (interface{}, error) {
- m := new(TraversalMetrics)
- dur, err := readLong(data, i)
- if err != nil {
- return nil, err
- }
- m.Duration = dur.(int64)
-
- nested, err := readList(data, i)
- if err != nil {
- return nil, err
- }
- list := nested.([]interface{})
- m.Metrics = make([]Metrics, len(list))
- for i, metric := range list {
- m.Metrics[i] = *metric.(*Metrics)
- }
-
- return m, nil
-}
-
-// Format: A String containing the fqcn.
-func readClass(data *[]byte, i *int) (interface{}, error) {
- gremlinType := new(GremlinType)
- str, err := readString(data, i)
- if err != nil {
- return nil, err
- }
- gremlinType.Fqcn = str.(string)
-
- return gremlinType, nil
-}
-
func readUnqualified(data *[]byte, i *int, dataTyp dataType, nullable bool) (interface{}, error) {
if nullable && readByteSafe(data, i) == valueFlagNull {
return getDefaultValue(dataTyp), nil
@@ -1351,9 +1073,17 @@ func readFullyQualifiedNullable(data *[]byte, i *int, nullable bool) (interface{
}
return nil, nil
} else if nullable {
- if readByteSafe(data, i) == valueFlagNull {
+ flag := readByteSafe(data, i)
+ fmt.Println(flag)
+ if flag == valueFlagNull {
return getDefaultValue(dataTyp), nil
}
+ if dataTyp == listType {
+ return readList(data, i, flag)
+ }
+ if dataTyp == mapType {
+ return readMap(data, i, flag)
+ }
}
deserializer, ok := deserializers[dataTyp]
if !ok {
diff --git a/gremlin-go/driver/graphBinary_test.go b/gremlin-go/driver/graphBinary_test.go
index d8c66d2816..a4d76596ae 100644
--- a/gremlin-go/driver/graphBinary_test.go
+++ b/gremlin-go/driver/graphBinary_test.go
@@ -24,6 +24,7 @@ import (
"encoding/binary"
"fmt"
"github.com/stretchr/testify/assert"
+ "github.com/wk8/go-ordered-map/v2"
"golang.org/x/text/language"
"math/big"
"reflect"
@@ -83,16 +84,6 @@ func TestGraphBinaryV1(t *testing.T) {
assert.Nil(t, err)
assert.Equal(t, str, res)
})
- t.Run("read-write GremlinType", func(t *testing.T) {
- pos := 0
- var buffer bytes.Buffer
- source := &GremlinType{"test fqcn"}
- buf, err := classWriter(source, &buffer, nil)
- assert.Nil(t, err)
- res, err := readClass(&buf, &pos)
- assert.Nil(t, err)
- assert.Equal(t, source, res)
- })
t.Run("read-write bool", func(t *testing.T) {
pos := 0
var buffer bytes.Buffer
@@ -198,7 +189,7 @@ func TestGraphBinaryV1(t *testing.T) {
source := []interface{}{int32(111), "str"}
buf, err := listWriter(source, &buffer, nil)
assert.Nil(t, err)
- res, err := readList(&buf, &pos)
+ res, err := readList(&buf, &pos, 0x00)
assert.Nil(t, err)
assert.Equal(t, source, res)
})
@@ -228,10 +219,23 @@ func TestGraphBinaryV1(t *testing.T) {
source := map[interface{}]interface{}{1: "s1", "s2": 2, nil: nil}
buf, err := mapWriter(source, &buffer, nil)
assert.Nil(t, err)
- res, err := readMap(&buf, &pos)
+ res, err := readMap(&buf, &pos, 0x00)
assert.Nil(t, err)
assert.Equal(t, fmt.Sprintf("%v", source), fmt.Sprintf("%v", res))
})
+ t.Run("read-write ordered map", func(t *testing.T) {
+ pos := 0
+ var buffer bytes.Buffer
+ source := orderedmap.New[interface{}, interface{}]()
+ source.Set(int32(1), "s1")
+ source.Set(int32(2), "s2")
+ source.Set(nil, nil)
+ buf, err := mapWriter(source, &buffer, nil)
+ assert.Nil(t, err)
+ res, err := readMap(&buf, &pos, 0x02)
+ assert.Nil(t, err)
+ assert.Equal(t, source, res)
+ })
t.Run("read incomparable map: a map value as the key", func(t *testing.T) {
// prepare test data
var buf = &bytes.Buffer{}
@@ -255,7 +259,7 @@ func TestGraphBinaryV1(t *testing.T) {
data := buf.Bytes()
i := 0
- result, err := readMap(&data, &i)
+ result, err := readMap(&data, &i, 0x00)
if err != nil {
t.Fatalf("readMap failed: %v", err)
}
@@ -291,7 +295,7 @@ func TestGraphBinaryV1(t *testing.T) {
data := buf.Bytes()
i := 0
- result, err := readMap(&data, &i)
+ result, err := readMap(&data, &i, 0x00)
if err != nil {
t.Fatalf("readMap failed: %v", err)
}
@@ -310,7 +314,8 @@ func TestGraphBinaryV1(t *testing.T) {
assert.Nil(t, err)
res, err := timeReader(&buf, &pos)
assert.Nil(t, err)
- assert.Equal(t, source, res)
+ // ISO format
+ assert.Equal(t, source.Format(time.RFC3339Nano), res.(time.Time).Format(time.RFC3339Nano))
})
})
diff --git a/gremlin-go/driver/serializer.go b/gremlin-go/driver/serializer.go
index 04a7e468b5..30ffef001a 100644
--- a/gremlin-go/driver/serializer.go
+++ b/gremlin-go/driver/serializer.go
@@ -228,7 +228,6 @@ func (gs graphBinarySerializer) deserializeMessage(message []byte) (response, er
func initSerializers() {
serializers = map[dataType]writer{
- bytecodeType: bytecodeWriter,
stringType: stringWriter,
bigDecimalType: bigDecimalWriter,
bigIntegerType: bigIntWriter,
@@ -255,35 +254,20 @@ func initSerializers() {
err := binary.Write(buffer, binary.BigEndian, value)
return buffer.Bytes(), err
},
- vertexType: vertexWriter,
- edgeType: edgeWriter,
- propertyType: propertyWriter,
- vertexPropertyType: vertexPropertyWriter,
- lambdaType: lambdaWriter,
- traversalStrategyType: traversalStrategyWriter,
- pathType: pathWriter,
- setType: setWriter,
- dateType: timeWriter,
- durationType: durationWriter,
- cardinalityType: enumWriter,
- columnType: enumWriter,
- directionType: enumWriter,
- dtType: enumWriter,
- operatorType: enumWriter,
- orderType: enumWriter,
- pickType: enumWriter,
- popType: enumWriter,
- tType: enumWriter,
- barrierType: enumWriter,
- scopeType: enumWriter,
- mergeType: enumWriter,
- pType: pWriter,
- textPType: textPWriter,
- bindingType: bindingWriter,
- mapType: mapWriter,
- listType: listWriter,
- byteBuffer: byteBufferWriter,
- classType: classWriter,
+ vertexType: vertexWriter,
+ edgeType: edgeWriter,
+ propertyType: propertyWriter,
+ vertexPropertyType: vertexPropertyWriter,
+ pathType: pathWriter,
+ setType: setWriter,
+ datetimeType: timeWriter,
+ durationType: durationWriter,
+ directionType: enumWriter,
+ tType: enumWriter,
+ mergeType: enumWriter,
+ mapType: mapWriter,
+ listType: listWriter,
+ byteBuffer: byteBufferWriter,
}
}
@@ -302,34 +286,24 @@ func initDeserializers() {
stringType: readString,
// Composite
- listType: readList,
- mapType: readMap,
+ //listType: readList,
+ //mapType: readMap,
setType: readSet,
uuidType: readUuid,
byteBuffer: readByteBuffer,
- classType: readClass,
// Date Time
- dateType: timeReader,
- timestampType: timeReader,
- durationType: durationReader,
+ datetimeType: timeReader,
+ durationType: durationReader,
// Graph
- traverserType: traverserReader,
vertexType: vertexReader,
edgeType: edgeReader,
propertyType: propertyReader,
vertexPropertyType: vertexPropertyReader,
pathType: pathReader,
- bulkSetType: bulkSetReader,
tType: enumReader,
directionType: enumReader,
- dtType: enumReader,
- bindingType: bindingReader,
-
- // Metrics
- metricsType: metricsReader,
- traversalMetricsType: traversalMetricsReader,
// Customer
customType: customTypeReader,
diff --git a/gremlin-go/go.mod b/gremlin-go/go.mod
index 39cb593de2..0123714f30 100644
--- a/gremlin-go/go.mod
+++ b/gremlin-go/go.mod
@@ -25,11 +25,14 @@ require (
github.com/gorilla/websocket v1.5.3
github.com/nicksnyder/go-i18n/v2 v2.4.1
github.com/stretchr/testify v1.9.0
+ github.com/wk8/go-ordered-map/v2 v2.1.8
golang.org/x/text v0.21.0
gopkg.in/yaml.v3 v3.0.1
)
require (
+ github.com/bahlo/generic-list-go v0.2.0 // indirect
+ github.com/buger/jsonparser v1.1.1 // indirect
github.com/cucumber/gherkin/go/v26 v26.2.0 // indirect
github.com/cucumber/messages/go/v21 v21.0.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
@@ -37,6 +40,7 @@ require (
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
github.com/hashicorp/go-memdb v1.3.4 // indirect
github.com/hashicorp/golang-lru v0.5.4 // indirect
+ github.com/mailru/easyjson v0.7.7 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/objx v0.5.2 // indirect
diff --git a/gremlin-go/go.sum b/gremlin-go/go.sum
index 24bf83a7a5..365be7fe1a 100644
--- a/gremlin-go/go.sum
+++ b/gremlin-go/go.sum
@@ -1,5 +1,9 @@
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
+github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
+github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
+github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
+github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cucumber/gherkin/go/v26 v26.2.0 h1:EgIjePLWiPeslwIWmNQ3XHcypPsWAHoMCz/YEBKP4GI=
github.com/cucumber/gherkin/go/v26 v26.2.0/go.mod h1:t2GAPnB8maCT4lkHL99BDCVNzCh1d7dBhCLt150Nr/0=
@@ -30,11 +34,14 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
+github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
+github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/nicksnyder/go-i18n/v2 v2.4.1 h1:zwzjtX4uYyiaU02K5Ia3zSkpJZrByARkRB4V3YPrr0g=
github.com/nicksnyder/go-i18n/v2 v2.4.1/go.mod h1:++Pl70FR6Cki7hdzZRnEEqdc2dJt+SAGotyFg/SvZMk=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -54,6 +61,8 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=
+github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=