Cole-Greer commented on code in PR #3292:
URL: https://github.com/apache/tinkerpop/pull/3292#discussion_r2666715034


##########
gremlin-go/driver/client.go:
##########
@@ -146,9 +151,53 @@ func (client *Client) Submit(traversalString string, 
bindings ...map[string]inte
        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)
-       request := makeBytecodeRequest(bytecode, client.traversalSource)
-       return client.gremlinClient.send(&request)
+// submitGremlinLang submits GremlinLang to the server to execute and returns 
a ResultSet.
+// TODO test and update when connection is set up
+func (client *Client) submitGremlinLang(gremlinLang *GremlinLang) (ResultSet, 
error) {
+       client.logHandler.logf(Debug, submitStartedString, *gremlinLang)
+       // TODO placeholder
+       requestOptionsBuilder := new(RequestOptionsBuilder)
+       if len(gremlinLang.GetParameters()) > 0 {
+               requestOptionsBuilder.SetBindings(gremlinLang.GetParameters())
+       }
+       if len(gremlinLang.optionsStrategies) > 0 {
+               requestOptionsBuilder = 
applyOptionsConfig(requestOptionsBuilder, 
gremlinLang.optionsStrategies[0].configuration)
+       }
+
+       request := makeStringRequest(gremlinLang.GetGremlin(), 
client.traversalSource, requestOptionsBuilder.Create())
+       return client.httpProtocol.send(&request)
 }
+
+func applyOptionsConfig(builder *RequestOptionsBuilder, config 
map[string]interface{}) *RequestOptionsBuilder {
+       builderValue := reflect.ValueOf(builder)
+
+       // Map configuration keys to setter method names
+       setterMap := map[string]string{
+               "requestId":             "SetRequestId",
+               "evaluationTimeout":     "SetEvaluationTimeout",
+               "batchSize":             "SetBatchSize",
+               "userAgent":             "SetUserAgent",
+               "bindings":              "SetBindings",
+               "materializeProperties": "SetMaterializeProperties",
+       }
+
+       for key, value := range config {
+               if methodName, exists := setterMap[key]; exists {
+                       method := builderValue.MethodByName(methodName)
+                       if method.IsValid() {
+                               args := []reflect.Value{reflect.ValueOf(value)}
+                               method.Call(args)
+                       }
+               }
+       }
+
+       return builder
+}
+
+// submitBytecode submits Bytecode to the server to execute and returns a 
ResultSet.
+// TODO remove
+//func (client *Client) submitBytecode(bytecode *Bytecode) (ResultSet, error) {
+//     client.logHandler.logf(Debug, submitStartedBytecode, *bytecode)
+//     request := makeBytecodeRequest(bytecode, client.traversalSource)
+//     return client.httpProtocol.send(&request)
+//}

Review Comment:
   Can this be removed now?



##########
gremlin-go/driver/graphTraversalSource.go:
##########
@@ -39,97 +39,91 @@ type GraphTraversalSource struct {
 // Graph and DriverRemoteConnection can be set to nil as valid default values.
 func NewGraphTraversalSource(graph *Graph, remoteConnection 
*DriverRemoteConnection,
        traversalStrategies ...TraversalStrategy) *GraphTraversalSource {
-       convertedArgs := convertStrategyVarargs(traversalStrategies)
-       bc := NewBytecode(nil)
-       bc.AddSource("withStrategies", convertedArgs...)
-       return &GraphTraversalSource{graph: graph, bytecode: bc, 
remoteConnection: remoteConnection}
+       // TODO: revisit when updating strategies
+       gl := NewGremlinLang(nil)
+       return &GraphTraversalSource{graph: graph, gremlinLang: gl, 
remoteConnection: remoteConnection}
 }
 
 // NewDefaultGraphTraversalSource creates a new graph GraphTraversalSource 
without a graph, strategy, or existing traversal.
 func NewDefaultGraphTraversalSource() *GraphTraversalSource {
-       return &GraphTraversalSource{graph: nil, bytecode: NewBytecode(nil), 
remoteConnection: nil}
+       return &GraphTraversalSource{graph: nil, gremlinLang: 
NewGremlinLang(nil), remoteConnection: nil}
 }
 
 // GetBytecode gets the traversal Bytecode associated with this graph 
traversal source.
-func (gts *GraphTraversalSource) GetBytecode() *Bytecode {
-       return gts.bytecode
-}
+// TODO remove
+//func (gts *GraphTraversalSource) GetBytecode() *Bytecode {

Review Comment:
   Is this going to be replaced with a new GetGremlinLang() method?



##########
gremlin-go/driver/gremlinlang.go:
##########
@@ -0,0 +1,578 @@
+/*
+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 (
+       "fmt"
+       "go/token"
+       "math"
+       "math/big"
+       "reflect"
+       "strconv"
+       "strings"
+       "sync/atomic"
+       "time"
+
+       "github.com/google/uuid"
+)
+
+type GremlinLang struct {
+       emptyArray        []interface{}
+       gremlin           []string
+       parameters        map[string]interface{}
+       optionsStrategies []*traversalStrategy
+       paramCount        *atomic.Uint64
+}
+
+// NewGremlinLang creates a new GremlinLang to be used in traversals.
+func NewGremlinLang(gl *GremlinLang) *GremlinLang {
+       gremlin := make([]string, 0)
+       parameters := make(map[string]interface{})
+       optionsStrategies := make([]*traversalStrategy, 0)
+       paramCount := atomic.Uint64{}
+       if gl != nil {
+               gremlin = make([]string, len(gl.gremlin))
+               copy(gremlin, gl.gremlin)
+
+               parameters = make(map[string]interface{})
+               for k, v := range gl.parameters {
+                       parameters[k] = v
+               }
+
+               optionsStrategies = make([]*traversalStrategy, 
len(gl.optionsStrategies))
+               copy(optionsStrategies, gl.optionsStrategies)
+
+               paramCount.Store(gl.paramCount.Load())
+       }
+
+       return &GremlinLang{
+               gremlin:           gremlin,
+               parameters:        parameters,
+               optionsStrategies: optionsStrategies,
+               paramCount:        &paramCount,
+       }
+}
+
+func (gl *GremlinLang) addToGremlin(name string, args ...interface{}) error {
+       flattenedArgs := gl.flattenArguments(args...)
+       if name == "CardinalityValueTraversal" {
+               str0, err := gl.argAsString(flattenedArgs[0])
+               if err != nil {
+                       return err
+               }
+               str1, err := gl.argAsString(flattenedArgs[1])
+               if err != nil {
+                       return err
+               }
+               gl.gremlin = append(gl.gremlin, str0)
+               gl.gremlin = append(gl.gremlin, "(")
+               gl.gremlin = append(gl.gremlin, str1)
+               gl.gremlin = append(gl.gremlin, ")")
+               return nil
+       }
+
+       gl.gremlin = append(gl.gremlin, ".")
+       gl.gremlin = append(gl.gremlin, name)
+       gl.gremlin = append(gl.gremlin, "(")
+
+       for i := 0; i < len(flattenedArgs); i++ {
+               if i > 0 {
+                       gl.gremlin = append(gl.gremlin, ",")
+               }
+               convertArg, err := gl.convertArgument(flattenedArgs[i]) 
//.Index(i).Interface())
+               if err != nil {
+                       return err
+               }
+               argStr, err := gl.argAsString(convertArg)
+               if err != nil {
+                       return err
+               }
+               gl.gremlin = append(gl.gremlin, argStr)
+       }
+       gl.gremlin = append(gl.gremlin, ")")
+       return nil
+}
+
+func (gl *GremlinLang) argAsString(arg interface{}) (string, error) {
+       if arg == nil {
+               return "null", nil
+       }
+       // we are concerned with both single and double quotes and %q in fmt 
only escapes double quotes
+       escapeQuotes := strings.NewReplacer(`'`, `\'`, `"`, `\"`)
+
+       switch v := arg.(type) {
+       case string:
+               return fmt.Sprintf("\"%s\"", escapeQuotes.Replace(v)), nil
+       case bool:
+               return strconv.FormatBool(v), nil
+       case int8, uint8:
+               return fmt.Sprintf("%dB", v), nil
+       case int16:
+               return fmt.Sprintf("%dS", v), nil
+       case int32, uint16:
+               return fmt.Sprintf("%d", v), nil
+       case int:
+               if v <= math.MaxInt32 && v >= math.MinInt32 {
+                       return fmt.Sprintf("%d", v), nil
+               } else {
+                       return fmt.Sprintf("%dL", v), nil
+               }
+       case int64, uint32:
+               return fmt.Sprintf("%dL", v), nil
+       case uint, uint64, *big.Int:
+               return fmt.Sprintf("%dN", v), nil
+       case float32:
+               if math.IsNaN(float64(v)) {
+                       return "NaN", nil
+               }
+               if math.IsInf(float64(v), 1) {
+                       return "Infinity", nil
+               }
+               if math.IsInf(float64(v), -1) {
+                       return "-Infinity", nil
+               }
+               return fmt.Sprintf("%vF", v), nil
+       case float64:
+               if math.IsNaN(v) {
+                       return "NaN", nil
+               }
+               if math.IsInf(v, 1) {
+                       return "Infinity", nil
+               }
+               if math.IsInf(v, -1) {
+                       return "-Infinity", nil
+               }
+               return fmt.Sprintf("%vD", v), nil
+       case *SimpleSet:
+               return gl.translateSet(v.ToSlice())
+       case BigDecimal:
+               return fmt.Sprintf("%vM", v.Value()), nil
+       case *BigDecimal:
+               return fmt.Sprintf("%vM", v.Value()), nil
+       case time.Time:
+               return fmt.Sprintf("datetime(\"%v\")", v.Format(time.RFC3339)), 
nil
+       case cardinality, column, direction, operator, order, pick, pop, 
barrier, scope, t, merge, gType:
+               name := reflect.ValueOf(v).Type().Name()

Review Comment:
   It's unfortunate that we need to use reflection here. Definitely out of 
scope for this PR but we might want to revisit the design of our "pseudo-enums" 
and see if there's anything better.



##########
gremlin-go/driver/gremlinlang.go:
##########
@@ -0,0 +1,578 @@
+/*
+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 (
+       "fmt"
+       "go/token"
+       "math"
+       "math/big"
+       "reflect"
+       "strconv"
+       "strings"
+       "sync/atomic"
+       "time"
+
+       "github.com/google/uuid"
+)
+
+type GremlinLang struct {
+       emptyArray        []interface{}
+       gremlin           []string
+       parameters        map[string]interface{}
+       optionsStrategies []*traversalStrategy
+       paramCount        *atomic.Uint64
+}
+
+// NewGremlinLang creates a new GremlinLang to be used in traversals.
+func NewGremlinLang(gl *GremlinLang) *GremlinLang {
+       gremlin := make([]string, 0)
+       parameters := make(map[string]interface{})
+       optionsStrategies := make([]*traversalStrategy, 0)
+       paramCount := atomic.Uint64{}
+       if gl != nil {
+               gremlin = make([]string, len(gl.gremlin))
+               copy(gremlin, gl.gremlin)
+
+               parameters = make(map[string]interface{})
+               for k, v := range gl.parameters {
+                       parameters[k] = v
+               }
+
+               optionsStrategies = make([]*traversalStrategy, 
len(gl.optionsStrategies))
+               copy(optionsStrategies, gl.optionsStrategies)
+
+               paramCount.Store(gl.paramCount.Load())
+       }
+
+       return &GremlinLang{
+               gremlin:           gremlin,
+               parameters:        parameters,
+               optionsStrategies: optionsStrategies,
+               paramCount:        &paramCount,
+       }
+}
+
+func (gl *GremlinLang) addToGremlin(name string, args ...interface{}) error {
+       flattenedArgs := gl.flattenArguments(args...)
+       if name == "CardinalityValueTraversal" {
+               str0, err := gl.argAsString(flattenedArgs[0])
+               if err != nil {
+                       return err
+               }
+               str1, err := gl.argAsString(flattenedArgs[1])
+               if err != nil {
+                       return err
+               }
+               gl.gremlin = append(gl.gremlin, str0)
+               gl.gremlin = append(gl.gremlin, "(")
+               gl.gremlin = append(gl.gremlin, str1)
+               gl.gremlin = append(gl.gremlin, ")")
+               return nil
+       }
+
+       gl.gremlin = append(gl.gremlin, ".")
+       gl.gremlin = append(gl.gremlin, name)
+       gl.gremlin = append(gl.gremlin, "(")
+
+       for i := 0; i < len(flattenedArgs); i++ {
+               if i > 0 {
+                       gl.gremlin = append(gl.gremlin, ",")
+               }
+               convertArg, err := gl.convertArgument(flattenedArgs[i]) 
//.Index(i).Interface())
+               if err != nil {
+                       return err
+               }
+               argStr, err := gl.argAsString(convertArg)
+               if err != nil {
+                       return err
+               }
+               gl.gremlin = append(gl.gremlin, argStr)
+       }
+       gl.gremlin = append(gl.gremlin, ")")
+       return nil
+}
+
+func (gl *GremlinLang) argAsString(arg interface{}) (string, error) {
+       if arg == nil {
+               return "null", nil
+       }
+       // we are concerned with both single and double quotes and %q in fmt 
only escapes double quotes
+       escapeQuotes := strings.NewReplacer(`'`, `\'`, `"`, `\"`)
+
+       switch v := arg.(type) {
+       case string:
+               return fmt.Sprintf("\"%s\"", escapeQuotes.Replace(v)), nil
+       case bool:
+               return strconv.FormatBool(v), nil
+       case int8, uint8:
+               return fmt.Sprintf("%dB", v), nil
+       case int16:
+               return fmt.Sprintf("%dS", v), nil
+       case int32, uint16:
+               return fmt.Sprintf("%d", v), nil
+       case int:
+               if v <= math.MaxInt32 && v >= math.MinInt32 {
+                       return fmt.Sprintf("%d", v), nil
+               } else {
+                       return fmt.Sprintf("%dL", v), nil
+               }
+       case int64, uint32:
+               return fmt.Sprintf("%dL", v), nil
+       case uint, uint64, *big.Int:
+               return fmt.Sprintf("%dN", v), nil
+       case float32:
+               if math.IsNaN(float64(v)) {
+                       return "NaN", nil
+               }
+               if math.IsInf(float64(v), 1) {
+                       return "Infinity", nil
+               }
+               if math.IsInf(float64(v), -1) {
+                       return "-Infinity", nil
+               }

Review Comment:
   This is definitely out of scope for this PR, but its occurring to me that we 
are losing the float 32 type for infinities and NaNs. Seems like a minor gap in 
the grammar which we may want to address.



##########
gremlin-go/driver/traversal.go:
##########
@@ -782,6 +783,18 @@ type BigDecimal struct {
        UnscaledValue *big.Int
 }
 
+func (bd *BigDecimal) Value() *big.Float {

Review Comment:
   It would be nice if we could get rid of our BigDecimal type and allow users 
to directly use the native big.Float type



##########
gremlin-go/driver/gremlinlang_test.go:
##########
@@ -448,191 +451,228 @@ func Test_translator_Translate(t *testing.T) {
                                        
Local(T__.Union(T__.Path().By("code").By("dist"), T__.Sack()).Fold()).
                                        Limit(10)
                        },
-                       equals: 
"g.withSack(0).V('3').repeat(outE('route').sack(sum).by('dist').inV()).until(has('code','AGR').or().loops().is(4)).has('code','AGR').local(union(path().by('code').by('dist'),sack()).fold()).limit(10)",
+                       equals: 
"g.withSack(0).V(\"3\").repeat(__.outE(\"route\").sack(Operator.sum).by(\"dist\").inV()).until(__.has(\"code\",\"AGR\").or().loops().is(4)).has(\"code\",\"AGR\").local(__.union(__.path().by(\"code\").by(\"dist\"),__.sack()).fold()).limit(10)",
                },
                {
                        assert: func(g *GraphTraversalSource) *GraphTraversal {
                                return 
g.AddV().As("a").AddV().As("b").AddE("knows").From("a").To("b")
                        },
-                       equals: 
"g.addV().as('a').addV().as('b').addE('knows').from('a').to('b')",
+                       equals: 
"g.addV().as(\"a\").addV().as(\"b\").addE(\"knows\").from(\"a\").to(\"b\")",
                },
                {
                        assert: func(g *GraphTraversalSource) *GraphTraversal {
                                return 
g.AddV("Person").As("a").AddV("Person").As("b").AddE("knows").From("a").To("b")
                        },
-                       equals: 
"g.addV('Person').as('a').addV('Person').as('b').addE('knows').from('a').to('b')",
+                       equals: 
"g.addV(\"Person\").as(\"a\").addV(\"Person\").as(\"b\").addE(\"knows\").from(\"a\").to(\"b\")",
                },
                {
                        assert: func(g *GraphTraversalSource) *GraphTraversal {
                                return g.V("3").Project("Out", 
"In").By(T__.Out().Count()).By(T__.In().Count())
                        },
-                       equals: 
"g.V('3').project('Out','In').by(out().count()).by(in().count())",
+                       equals: 
"g.V(\"3\").project(\"Out\",\"In\").by(__.out().count()).by(__.in().count())",
                },
                {
                        assert: func(g *GraphTraversalSource) *GraphTraversal {
                                return 
g.V("44").Out().Aggregate("a").Out().Where(P.Within("a")).Path()
                        },
-                       equals: 
"g.V('44').out().aggregate('a').out().where(within('a')).path()",
+                       equals: 
"g.V(\"44\").out().aggregate(\"a\").out().where(within(\"a\")).path()",
                },
                {
                        assert: func(g *GraphTraversalSource) *GraphTraversal {
                                return g.V().Has("date", time.Date(2021, 2, 22, 
0, 0, 0, 0, time.UTC))
                        },
-                       equals: "g.V().has('date',new Date(121,2,22,0,0,0))",
+                       equals: 
"g.V().has(\"date\",datetime(\"2021-02-22T00:00:00Z\"))",
                },
                {
                        assert: func(g *GraphTraversalSource) *GraphTraversal {
                                return g.V().Has("date", 
P.Within(time.Date(2021, 2, 22, 0, 0, 0, 0, time.UTC), time.Date(2021, 1, 1, 0, 
0, 0, 0, time.UTC)))
                        },
-                       equals: "g.V().has('date',within([new 
Date(121,2,22,0,0,0),new Date(121,1,1,0,0,0)]))",
+                       equals: 
"g.V().has(\"date\",within([datetime(\"2021-02-22T00:00:00Z\"),datetime(\"2021-01-01T00:00:00Z\")]))",
                },
                {
                        assert: func(g *GraphTraversalSource) *GraphTraversal {
                                return g.V().Has("date", 
P.Between(time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC), time.Date(2021, 2, 22, 
0, 0, 0, 0, time.UTC)))
                        },
-                       equals: "g.V().has('date',between(new 
Date(121,1,1,0,0,0),new Date(121,2,22,0,0,0)))",
+                       equals: 
"g.V().has(\"date\",between(datetime(\"2021-01-01T00:00:00Z\"),datetime(\"2021-02-22T00:00:00Z\")))",
                },
                {
                        assert: func(g *GraphTraversalSource) *GraphTraversal {
                                return g.V().Has("date", 
P.Inside(time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC), time.Date(2021, 2, 22, 0, 
0, 0, 0, time.UTC)))
                        },
-                       equals: "g.V().has('date',inside(new 
Date(121,1,1,0,0,0),new Date(121,2,22,0,0,0)))",
+                       equals: 
"g.V().has(\"date\",inside(datetime(\"2021-01-01T00:00:00Z\"),datetime(\"2021-02-22T00:00:00Z\")))",
                },
                {
                        assert: func(g *GraphTraversalSource) *GraphTraversal {
                                return g.V().Has("date", P.Gt(time.Date(2021, 
1, 1, 9, 30, 0, 0, time.UTC)))
                        },
-                       equals: "g.V().has('date',gt(new 
Date(121,1,1,9,30,0)))",
+                       equals: 
"g.V().has(\"date\",gt(datetime(\"2021-01-01T09:30:00Z\")))",
                },
                {
                        assert: func(g *GraphTraversalSource) *GraphTraversal {
                                return g.V().Has("runways", P.Between(3, 5))
                        },
-                       equals: "g.V().has('runways',between(3,5))",
+                       equals: "g.V().has(\"runways\",between(3,5))",
                },
                {
                        assert: func(g *GraphTraversalSource) *GraphTraversal {
                                return g.V().Has("runways", P.Inside(3, 5))
                        },
-                       equals: "g.V().has('runways',inside(3,5))",
+                       equals: "g.V().has(\"runways\",inside(3,5))",
                },
                {
                        assert: func(g *GraphTraversalSource) *GraphTraversal {
                                return g.V("44").OutE().ElementMap()
                        },
-                       equals: "g.V('44').outE().elementMap()",
+                       equals: "g.V(\"44\").outE().elementMap()",
                },
                {
                        assert: func(g *GraphTraversalSource) *GraphTraversal {
                                return g.V("44").ValueMap().By(T__.Unfold())
                        },
-                       equals: "g.V('44').valueMap().by(unfold())",
+                       equals: "g.V(\"44\").valueMap().by(__.unfold())",
                },
                {
                        assert: func(g *GraphTraversalSource) *GraphTraversal {
                                return 
g.V("44").ValueMap().With(WithOptions.Tokens, WithOptions.Labels)
                        },
-                       equals: 
"g.V('44').valueMap().with(WithOptions.tokens,WithOptions.labels)",
+                       equals: 
"g.V(\"44\").valueMap().with(\"~tinkerpop.valueMap.tokens\",2)",

Review Comment:
   The WithOptions in this and following cases don't look right, the grammar 
should parse the enums directly.
   
   ```suggestion
                        equals: 
"g.V(\"44\").valueMap().with(WithOptions.tokens,WithOptions.labels)",
   ```



##########
gremlin-go/driver/gremlinlang.go:
##########
@@ -0,0 +1,578 @@
+/*
+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 (
+       "fmt"
+       "go/token"
+       "math"
+       "math/big"
+       "reflect"
+       "strconv"
+       "strings"
+       "sync/atomic"
+       "time"
+
+       "github.com/google/uuid"
+)
+
+type GremlinLang struct {
+       emptyArray        []interface{}
+       gremlin           []string
+       parameters        map[string]interface{}
+       optionsStrategies []*traversalStrategy
+       paramCount        *atomic.Uint64
+}
+
+// NewGremlinLang creates a new GremlinLang to be used in traversals.
+func NewGremlinLang(gl *GremlinLang) *GremlinLang {
+       gremlin := make([]string, 0)
+       parameters := make(map[string]interface{})
+       optionsStrategies := make([]*traversalStrategy, 0)
+       paramCount := atomic.Uint64{}
+       if gl != nil {
+               gremlin = make([]string, len(gl.gremlin))
+               copy(gremlin, gl.gremlin)
+
+               parameters = make(map[string]interface{})
+               for k, v := range gl.parameters {
+                       parameters[k] = v
+               }
+
+               optionsStrategies = make([]*traversalStrategy, 
len(gl.optionsStrategies))
+               copy(optionsStrategies, gl.optionsStrategies)
+
+               paramCount.Store(gl.paramCount.Load())
+       }
+
+       return &GremlinLang{
+               gremlin:           gremlin,
+               parameters:        parameters,
+               optionsStrategies: optionsStrategies,
+               paramCount:        &paramCount,
+       }
+}
+
+func (gl *GremlinLang) addToGremlin(name string, args ...interface{}) error {
+       flattenedArgs := gl.flattenArguments(args...)
+       if name == "CardinalityValueTraversal" {
+               str0, err := gl.argAsString(flattenedArgs[0])
+               if err != nil {
+                       return err
+               }
+               str1, err := gl.argAsString(flattenedArgs[1])
+               if err != nil {
+                       return err
+               }
+               gl.gremlin = append(gl.gremlin, str0)
+               gl.gremlin = append(gl.gremlin, "(")
+               gl.gremlin = append(gl.gremlin, str1)
+               gl.gremlin = append(gl.gremlin, ")")
+               return nil
+       }
+
+       gl.gremlin = append(gl.gremlin, ".")
+       gl.gremlin = append(gl.gremlin, name)
+       gl.gremlin = append(gl.gremlin, "(")
+
+       for i := 0; i < len(flattenedArgs); i++ {
+               if i > 0 {
+                       gl.gremlin = append(gl.gremlin, ",")
+               }
+               convertArg, err := gl.convertArgument(flattenedArgs[i]) 
//.Index(i).Interface())
+               if err != nil {
+                       return err
+               }
+               argStr, err := gl.argAsString(convertArg)
+               if err != nil {
+                       return err
+               }
+               gl.gremlin = append(gl.gremlin, argStr)
+       }
+       gl.gremlin = append(gl.gremlin, ")")
+       return nil
+}
+
+func (gl *GremlinLang) argAsString(arg interface{}) (string, error) {
+       if arg == nil {
+               return "null", nil
+       }
+       // we are concerned with both single and double quotes and %q in fmt 
only escapes double quotes
+       escapeQuotes := strings.NewReplacer(`'`, `\'`, `"`, `\"`)
+
+       switch v := arg.(type) {
+       case string:
+               return fmt.Sprintf("\"%s\"", escapeQuotes.Replace(v)), nil
+       case bool:
+               return strconv.FormatBool(v), nil
+       case int8, uint8:
+               return fmt.Sprintf("%dB", v), nil
+       case int16:
+               return fmt.Sprintf("%dS", v), nil
+       case int32, uint16:
+               return fmt.Sprintf("%d", v), nil
+       case int:
+               if v <= math.MaxInt32 && v >= math.MinInt32 {
+                       return fmt.Sprintf("%d", v), nil
+               } else {
+                       return fmt.Sprintf("%dL", v), nil
+               }
+       case int64, uint32:
+               return fmt.Sprintf("%dL", v), nil
+       case uint, uint64, *big.Int:
+               return fmt.Sprintf("%dN", v), nil
+       case float32:
+               if math.IsNaN(float64(v)) {
+                       return "NaN", nil
+               }
+               if math.IsInf(float64(v), 1) {
+                       return "Infinity", nil
+               }
+               if math.IsInf(float64(v), -1) {
+                       return "-Infinity", nil
+               }
+               return fmt.Sprintf("%vF", v), nil
+       case float64:
+               if math.IsNaN(v) {
+                       return "NaN", nil
+               }
+               if math.IsInf(v, 1) {
+                       return "Infinity", nil
+               }
+               if math.IsInf(v, -1) {
+                       return "-Infinity", nil
+               }
+               return fmt.Sprintf("%vD", v), nil
+       case *SimpleSet:
+               return gl.translateSet(v.ToSlice())
+       case BigDecimal:
+               return fmt.Sprintf("%vM", v.Value()), nil
+       case *BigDecimal:
+               return fmt.Sprintf("%vM", v.Value()), nil
+       case time.Time:
+               return fmt.Sprintf("datetime(\"%v\")", v.Format(time.RFC3339)), 
nil
+       case cardinality, column, direction, operator, order, pick, pop, 
barrier, scope, t, merge, gType:
+               name := reflect.ValueOf(v).Type().Name()
+               return fmt.Sprintf("%s.%s", strings.ToUpper(name[:1])+name[1:], 
v), nil
+       case dt:
+               name := reflect.ValueOf(v).Type().Name()
+               return fmt.Sprintf("%s.%s", strings.ToUpper(name), v), nil
+       case *Vertex:
+               id, _ := gl.argAsString(v.Id)
+               return fmt.Sprintf("new ReferenceVertex(%s,\"%s\")", 
escapeQuotes.Replace(id), escapeQuotes.Replace(v.Label)), nil

Review Comment:
   Are there tests for this? ReferenceVertex should not be present in the 
grammar.



##########
gremlin-go/driver/connection_test.go:
##########
@@ -272,6 +274,55 @@ func TestConnection(t *testing.T) {
        testBasicAuthAuthInfo := getBasicAuthInfo()
        testBasicAuthTlsConfig := &tls.Config{InsecureSkipVerify: true}
 
+       // this test is used to test the ws->http POC changes via manual 
execution with a local TP 4.0 gremlin server running on 8182

Review Comment:
   What's the plan for this test? It looks like it's mostly setup for manual 
debugging. Is the intention to keep it or will it be cleaned up or removed at a 
later date?



##########
gremlin-go/driver/gremlinlang.go:
##########
@@ -0,0 +1,578 @@
+/*
+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 (
+       "fmt"
+       "go/token"
+       "math"
+       "math/big"
+       "reflect"
+       "strconv"
+       "strings"
+       "sync/atomic"
+       "time"
+
+       "github.com/google/uuid"
+)
+
+type GremlinLang struct {
+       emptyArray        []interface{}
+       gremlin           []string
+       parameters        map[string]interface{}
+       optionsStrategies []*traversalStrategy
+       paramCount        *atomic.Uint64
+}
+
+// NewGremlinLang creates a new GremlinLang to be used in traversals.
+func NewGremlinLang(gl *GremlinLang) *GremlinLang {
+       gremlin := make([]string, 0)
+       parameters := make(map[string]interface{})
+       optionsStrategies := make([]*traversalStrategy, 0)
+       paramCount := atomic.Uint64{}
+       if gl != nil {
+               gremlin = make([]string, len(gl.gremlin))
+               copy(gremlin, gl.gremlin)
+
+               parameters = make(map[string]interface{})
+               for k, v := range gl.parameters {
+                       parameters[k] = v
+               }
+
+               optionsStrategies = make([]*traversalStrategy, 
len(gl.optionsStrategies))
+               copy(optionsStrategies, gl.optionsStrategies)
+
+               paramCount.Store(gl.paramCount.Load())
+       }
+
+       return &GremlinLang{
+               gremlin:           gremlin,
+               parameters:        parameters,
+               optionsStrategies: optionsStrategies,
+               paramCount:        &paramCount,
+       }
+}
+
+func (gl *GremlinLang) addToGremlin(name string, args ...interface{}) error {
+       flattenedArgs := gl.flattenArguments(args...)
+       if name == "CardinalityValueTraversal" {
+               str0, err := gl.argAsString(flattenedArgs[0])
+               if err != nil {
+                       return err
+               }
+               str1, err := gl.argAsString(flattenedArgs[1])
+               if err != nil {
+                       return err
+               }
+               gl.gremlin = append(gl.gremlin, str0)
+               gl.gremlin = append(gl.gremlin, "(")
+               gl.gremlin = append(gl.gremlin, str1)
+               gl.gremlin = append(gl.gremlin, ")")
+               return nil
+       }
+
+       gl.gremlin = append(gl.gremlin, ".")
+       gl.gremlin = append(gl.gremlin, name)
+       gl.gremlin = append(gl.gremlin, "(")
+
+       for i := 0; i < len(flattenedArgs); i++ {
+               if i > 0 {
+                       gl.gremlin = append(gl.gremlin, ",")
+               }
+               convertArg, err := gl.convertArgument(flattenedArgs[i]) 
//.Index(i).Interface())
+               if err != nil {
+                       return err
+               }
+               argStr, err := gl.argAsString(convertArg)
+               if err != nil {
+                       return err
+               }
+               gl.gremlin = append(gl.gremlin, argStr)
+       }
+       gl.gremlin = append(gl.gremlin, ")")
+       return nil
+}
+
+func (gl *GremlinLang) argAsString(arg interface{}) (string, error) {
+       if arg == nil {
+               return "null", nil
+       }
+       // we are concerned with both single and double quotes and %q in fmt 
only escapes double quotes
+       escapeQuotes := strings.NewReplacer(`'`, `\'`, `"`, `\"`)
+
+       switch v := arg.(type) {
+       case string:
+               return fmt.Sprintf("\"%s\"", escapeQuotes.Replace(v)), nil
+       case bool:
+               return strconv.FormatBool(v), nil
+       case int8, uint8:
+               return fmt.Sprintf("%dB", v), nil
+       case int16:
+               return fmt.Sprintf("%dS", v), nil
+       case int32, uint16:
+               return fmt.Sprintf("%d", v), nil
+       case int:
+               if v <= math.MaxInt32 && v >= math.MinInt32 {
+                       return fmt.Sprintf("%d", v), nil
+               } else {
+                       return fmt.Sprintf("%dL", v), nil
+               }
+       case int64, uint32:
+               return fmt.Sprintf("%dL", v), nil
+       case uint, uint64, *big.Int:

Review Comment:
   Nit: we may want to give `uint` some "range-based" type resolution logic 
similar to `int` instead of directly promoting to BigInteger



##########
gremlin-go/driver/gValue.go:
##########
@@ -0,0 +1,61 @@
+/*
+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 (
+       "fmt"
+       "strings"
+)
+
+// GValue is a variable or literal value that is used in a Traversal. It is 
composed of a key-value pair where the key
+// is the name given to the variable and the value is the object that the 
variable resolved to.
+type GValue interface {

Review Comment:
   I'm not sure it's necessary to have an interface for `GValue` with accessor 
methods. I think we could get away with capitalizing the `gValue` struct type 
and allowing users to directly interact with it. I wouldn't expect there is 
much need for multiple implementations of the interface.



##########
gremlin-go/driver/driverRemoteConnection.go:
##########
@@ -135,22 +135,32 @@ func (driver *DriverRemoteConnection) 
Submit(traversalString string) (ResultSet,
        return driver.SubmitWithOptions(traversalString, *new(RequestOptions))
 }
 
-// submitBytecode sends a Bytecode traversal to the server.
-func (driver *DriverRemoteConnection) submitBytecode(bytecode *Bytecode) 
(ResultSet, error) {
+// submitGremlinLang sends a GremlinLang traversal to the server.
+// TODO test and update when connection is set up
+func (driver *DriverRemoteConnection) submitGremlinLang(gremlinLang 
*GremlinLang) (ResultSet, error) {
        if driver.isClosed {
-               return nil, 
newError(err0203SubmitBytecodeToClosedConnectionError)
+               return nil, 
newError(err0203SubmitGremlinLangToClosedConnectionError)
        }
-       return driver.client.submitBytecode(bytecode)
-}
-
-func (driver *DriverRemoteConnection) commit() (ResultSet, error) {
-       bc := &Bytecode{}
-       bc.AddSource("tx", "commit")
-       return driver.submitBytecode(bc)
+       return driver.client.submitGremlinLang(gremlinLang)
 }
 
-func (driver *DriverRemoteConnection) rollback() (ResultSet, error) {
-       bc := &Bytecode{}
-       bc.AddSource("tx", "rollback")
-       return driver.submitBytecode(bc)
-}
+// TODO remove
+// submitBytecode sends a Bytecode traversal to the server.

Review Comment:
   Can this be removed now?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to