This is an automated email from the ASF dual-hosted git repository. xiazcy pushed a commit to branch go-http-converge-conn-lang in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit 4393a5a3b8a488c9131b0c86b4a1d73159161c48 Author: Yang Xia <[email protected]> AuthorDate: Mon Dec 22 13:44:32 2025 -0800 fix various gremlinlang and serializer bugs in go for http --- .../language/translator/GremlinTranslatorTest.java | 12 +- gremlin-go/driver/client.go | 47 +- gremlin-go/driver/client_test.go | 14 +- gremlin-go/driver/connection_test.go | 161 +---- gremlin-go/driver/cucumber/cucumberSteps_test.go | 3 - gremlin-go/driver/cucumber/cucumberWorld.go | 62 +- gremlin-go/driver/driverRemoteConnection.go | 37 +- gremlin-go/driver/error_codes.go | 1 + gremlin-go/driver/graphBinary.go | 14 +- gremlin-go/driver/graphBinary_test.go | 23 +- gremlin-go/driver/graphTraversal.go | 8 +- gremlin-go/driver/graphTraversalSource.go | 6 +- gremlin-go/driver/gremlinClient.go | 148 ----- gremlin-go/driver/gremlinlang.go | 178 +++-- gremlin-go/driver/gremlinlang_test.go | 45 +- gremlin-go/driver/httpTransporter.go | 7 +- gremlin-go/driver/logger.go | 1 - gremlin-go/driver/serializer.go | 13 +- gremlin-go/driver/strategies.go | 40 +- gremlin-go/driver/translator.go | 365 ----------- gremlin-go/driver/translator_test.go | 717 --------------------- gremlin-go/driver/traversal.go | 52 +- gremlin-go/driver/traversal_test.go | 14 +- gremlin-go/examples/go.mod | 4 +- gremlin-go/examples/go.sum | 2 + gremlin-go/go.mod | 16 +- gremlin-go/go.sum | 33 +- .../python/gremlin_python/process/traversal.py | 2 +- 28 files changed, 410 insertions(+), 1615 deletions(-) diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/translator/GremlinTranslatorTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/translator/GremlinTranslatorTest.java index d89dba51b4..f08355d1a2 100644 --- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/translator/GremlinTranslatorTest.java +++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/translator/GremlinTranslatorTest.java @@ -699,23 +699,13 @@ public class GremlinTranslatorTest { {"g.withStrategies(ReservedKeysVerificationStrategy(throwException: true, keys: [\"age\"])).addV(\"person\").property(\"age\", 29).property(\"name\", \"marko\")", "g.withStrategies(ReservedKeysVerificationStrategy(throwException:true, keys:[\"age\"])).addV(\"person\").property(\"age\", 29).property(\"name\", \"marko\")", "g.withStrategies(ReservedKeysVerificationStrategy(throwException:boolean0, keys:list0)).addV(string0).property(string1, number0).property(string2, string3)", - "g.WithStrategies(new ReservedKeysVerificationStrategy(throwException: true, keys: new List<object> { \"age\" })).AddV(\"person\").Property(\"age\", 29).Property(\"name\", \"marko\")", + "g.WithStrategies(new ReservedKeysVerificationStrategy(throwException: true, keys: new List<object> { \"age\" })).AddV((string) \"person\").Property(\"age\", 29).Property(\"name\", \"marko\")", "g.WithStrategies(gremlingo.ReservedKeysVerificationStrategy(gremlingo.ReservedKeysVerificationStrategyConfig{ThrowException: true, Keys: []string{\"age\"}})).AddV(\"person\").Property(\"age\", 29).Property(\"name\", \"marko\")", "g.withStrategies(new ReservedKeysVerificationStrategy(throwException:true, keys:[\"age\"])).addV(\"person\").property(\"age\", 29).property(\"name\", \"marko\")", "g.withStrategies(ReservedKeysVerificationStrategy.build().throwException(true).keys(new ArrayList<Object>() {{ add(\"age\"); }}).create()).addV(\"person\").property(\"age\", 29).property(\"name\", \"marko\")", "g.withStrategies(new ReservedKeysVerificationStrategy({throwException: true, keys: [\"age\"]})).addV(\"person\").property(\"age\", 29).property(\"name\", \"marko\")", "g.with_strategies(ReservedKeysVerificationStrategy(throw_exception=True, keys=['age'])).add_v('person').property('age', 29).property('name', 'marko')" }, - {"g.withStrategies(OptionsStrategy(myVar: \"myValue\")).V()", - "g.withStrategies(OptionsStrategy(myVar:\"myValue\")).V()", - "g.withStrategies(OptionsStrategy(myVar:string0)).V()", - "g.WithStrategies(new OptionsStrategy(myVar: \"myValue\")).V()", - "g.WithStrategies(gremlingo.OptionsStrategy(map[string]interface{}{\"myVar\": \"myValue\"})).V()", - "g.withStrategies(new OptionsStrategy(myVar:\"myValue\")).V()", - "g.withStrategies(OptionsStrategy.build().myVar(\"myValue\").create()).V()", - "g.withStrategies(new OptionsStrategy({myVar: \"myValue\"})).V()", - "g.with_strategies(OptionsStrategy(my_var='myValue')).V()" - }, {"g.withoutStrategies(ReadOnlyStrategy, PathRetractionStrategy, FilterRankingStrategy)", null, null, diff --git a/gremlin-go/driver/client.go b/gremlin-go/driver/client.go index 12b6c4e9c6..7ce9a8839a 100644 --- a/gremlin-go/driver/client.go +++ b/gremlin-go/driver/client.go @@ -21,6 +21,7 @@ package gremlingo import ( "crypto/tls" + "reflect" "runtime" "time" @@ -134,7 +135,7 @@ func (client *Client) SubmitWithOptions(traversalString string, requestOptions R request := makeStringRequest(traversalString, client.traversalSource, requestOptions) // TODO interceptors (ie. auth) - + rs, err := client.httpProtocol.send(&request) return rs, err } @@ -156,13 +157,47 @@ func (client *Client) submitGremlinLang(gremlinLang *GremlinLang) (ResultSet, er 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) } -// 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.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) +//} diff --git a/gremlin-go/driver/client_test.go b/gremlin-go/driver/client_test.go index 6068f89ecc..9e223dd193 100644 --- a/gremlin-go/driver/client_test.go +++ b/gremlin-go/driver/client_test.go @@ -62,7 +62,7 @@ func TestClient(t *testing.T) { }) assert.NoError(t, err) assert.NotNil(t, client) - resultSet, err := client.Submit("2+2") + resultSet, err := client.Submit("g.inject(2)") assert.NoError(t, err) assert.NotNil(t, resultSet) @@ -104,9 +104,9 @@ func TestClient(t *testing.T) { assert.NotNil(t, client) defer client.Close() - bindings := map[string]interface{}{"x": 2} + bindings := map[string]interface{}{"x": 1} - resultSet, err := client.Submit("x + x", bindings) + resultSet, err := client.Submit("g.V(x).values(\"name\")", bindings) assert.NoError(t, err) assert.NotNil(t, resultSet) @@ -114,7 +114,7 @@ func TestClient(t *testing.T) { assert.NoError(t, err) assert.True(t, ok) - assert.Equal(t, int64(4), result.Data) + assert.Equal(t, "marko", result.Data) }) t.Run("Test client.SubmitWithOptions() with bindings", func(t *testing.T) { @@ -129,9 +129,9 @@ func TestClient(t *testing.T) { assert.NotNil(t, client) defer client.Close() - bindings := map[string]interface{}{"x": 2} + bindings := map[string]interface{}{"x": 1} - resultSet, err := client.SubmitWithOptions("x + x", new(RequestOptionsBuilder).SetBindings(bindings).Create()) + resultSet, err := client.SubmitWithOptions("g.V(x).values(\"name\")", new(RequestOptionsBuilder).SetBindings(bindings).Create()) assert.NoError(t, err) assert.NotNil(t, resultSet) @@ -139,7 +139,7 @@ func TestClient(t *testing.T) { assert.NoError(t, err) assert.True(t, ok) - assert.Equal(t, int64(4), result.Data) + assert.Equal(t, "marko", result.Data) }) t.Run("Test client.submit() with materializeProperties", func(t *testing.T) { diff --git a/gremlin-go/driver/connection_test.go b/gremlin-go/driver/connection_test.go index d24c6158ff..be13a9a8e5 100644 --- a/gremlin-go/driver/connection_test.go +++ b/gremlin-go/driver/connection_test.go @@ -22,7 +22,6 @@ package gremlingo import ( "crypto/tls" "fmt" - "github.com/stretchr/testify/assert" "math/big" "os" "reflect" @@ -30,6 +29,8 @@ import ( "strconv" "sync" "testing" + + "github.com/stretchr/testify/assert" ) const personLabel = "Person" @@ -663,142 +664,28 @@ func TestConnection(t *testing.T) { } }) - t.Run("Test Client.Submit() Simple String Query with Bindings", func(t *testing.T) { - skipTestsIfNotEnabled(t, integrationTestSuiteName, testNoAuthEnable) - - client, err := NewClient(testNoAuthUrl, - func(settings *ClientSettings) { - settings.TlsConfig = testNoAuthTlsConfig - settings.AuthInfo = testNoAuthAuthInfo - }) - assert.Nil(t, err) - assert.NotNil(t, client) - defer client.Close() - - resultSet, err := client.Submit("g.inject(x).math('_+_')", map[string]interface{}{"x": 2}) - assert.Nil(t, err) - assert.NotNil(t, resultSet) - result, ok, err := resultSet.One() - assert.Nil(t, err) - assert.True(t, ok) - assert.NotNil(t, result) - res, err := result.GetInt() - assert.Nil(t, err) - assert.Equal(t, 4, res) - }) - - t.Run("Test Bindings To Server Configured with Modern Graph", func(t *testing.T) { - skipTestsIfNotEnabled(t, integrationTestSuiteName, testNoAuthWithAliasEnable) - remote, err := NewDriverRemoteConnection(testNoAuthWithAliasUrl, - func(settings *DriverRemoteConnectionSettings) { - settings.TlsConfig = testNoAuthWithAliasTlsConfig - settings.AuthInfo = testNoAuthWithAliasAuthInfo - settings.TraversalSource = testServerModernGraphAlias - }) - assert.Nil(t, err) - assert.NotNil(t, remote) - defer remote.Close() - g := Traversal_().With(remote) - - r, err := g.V((&Bindings{}).Of("x", 1)).Out("created").Map(&Lambda{Script: "it.get().value('name').length()", Language: ""}).Sum().ToList() - assert.Nil(t, err) - for _, res := range r { - assert.Equal(t, int32(3), res.GetInterface()) - } - r, err = g.V((&Bindings{}).Of("x", 4)).Out("created").Map(&Lambda{Script: "it.get().value('name').length()", Language: ""}).Sum().ToList() - assert.Nil(t, err) - for _, res := range r { - assert.Equal(t, int32(9), res.GetInterface()) - } - }) - - t.Run("Test DriverRemoteConnection Invalid GraphTraversal", func(t *testing.T) { - skipTestsIfNotEnabled(t, integrationTestSuiteName, testNoAuthEnable) - - // Initialize graph - g := initializeGraph(t, testNoAuthUrl, testNoAuthAuthInfo, testNoAuthTlsConfig) - - // Drop the graph. - dropGraph(t, g) - - // Add vertices and edges to graph. - rs, err := g.AddV("person").Property("id", T__.Unfold().Property().AddV()).ToList() - assert.Nil(t, rs) - assert.True(t, isSameErrorCode(newError(err0502ResponseHandlerError), err)) - - rs, err = g.V().Count().ToList() - assert.NotNil(t, rs) - assert.Nil(t, err) - - // Drop the graph. - dropGraph(t, g) - }) - - t.Run("Test per-request arguments", func(t *testing.T) { - skipTestsIfNotEnabled(t, integrationTestSuiteName, testNoAuthEnable) - - g := getTestGraph(t, testNoAuthUrl, testNoAuthAuthInfo, testNoAuthTlsConfig) - defer g.remoteConnection.Close() - - reqArgsTests := []struct { - msg string - traversal *GraphTraversal - nilErr bool - }{ - { - "Traversal must time out (With)", - g. - With("evaluationTimeout", 10). - Inject(1). - SideEffect(&Lambda{"Thread.sleep(5000)", "gremlin-groovy"}), - false, - }, - { - "Traversal must finish (With)", - g. - With("evaluationTimeout", 10000). - Inject(1). - SideEffect(&Lambda{"Thread.sleep(5000)", "gremlin-groovy"}), - true, - }, - { - "evaluationTimeout is overridden and traversal must time out (With)", - g. - With("evaluationTimeout", 10000).With("evaluationTimeout", 10). - Inject(1). - SideEffect(&Lambda{"Thread.sleep(5000)", "gremlin-groovy"}), - false, - }, - { - "Traversal must time out (OptionsStrategy)", - g. - WithStrategies(OptionsStrategy(map[string]interface{}{"evaluationTimeout": 10})). - Inject(1). - SideEffect(&Lambda{"Thread.sleep(5000)", "gremlin-groovy"}), - false, - }, - { - "Traversal must finish (OptionsStrategy)", - g. - WithStrategies(OptionsStrategy(map[string]interface{}{"evaluationTimeout": 10000})). - Inject(1). - SideEffect(&Lambda{"Thread.sleep(5000)", "gremlin-groovy"}), - true, - }, - } - - gotErrs := make([]<-chan error, len(reqArgsTests)) - - // Run tests in parallel. - for i, tt := range reqArgsTests { - gotErrs[i] = tt.traversal.Iterate() - } - - // Check error promises. - for i, tt := range reqArgsTests { - assert.Equal(t, <-gotErrs[i] == nil, tt.nilErr, tt.msg) - } - }) + // TODO enable after error response is deser properly + //t.Run("Test DriverRemoteConnection Invalid GraphTraversal", func(t *testing.T) { + // skipTestsIfNotEnabled(t, integrationTestSuiteName, testNoAuthEnable) + // + // // Initialize graph + // g := initializeGraph(t, testNoAuthUrl, testNoAuthAuthInfo, testNoAuthTlsConfig) + // + // // Drop the graph. + // dropGraph(t, g) + // + // // Add vertices and edges to graph. + // rs, err := g.AddV("person").Property("id", T__.Unfold().Property().AddV()).ToList() + // assert.Nil(t, rs) + // assert.True(t, isSameErrorCode(newError(err0502ResponseHandlerError), err)) + // + // rs, err = g.V().Count().ToList() + // assert.NotNil(t, rs) + // assert.Nil(t, err) + // + // // Drop the graph. + // dropGraph(t, g) + //}) t.Run("Get all properties when materializeProperties is all", func(t *testing.T) { skipTestsIfNotEnabled(t, integrationTestSuiteName, testNoAuthEnable) diff --git a/gremlin-go/driver/cucumber/cucumberSteps_test.go b/gremlin-go/driver/cucumber/cucumberSteps_test.go index 0942ae1384..f9caa7e187 100644 --- a/gremlin-go/driver/cucumber/cucumberSteps_test.go +++ b/gremlin-go/driver/cucumber/cucumberSteps_test.go @@ -951,11 +951,8 @@ func InitializeScenario(ctx *godog.ScenarioContext) { ctx.Step(`^the result should have a count of (\d+)$`, tg.theResultShouldHaveACountOf) ctx.Step(`^the traversal of$`, tg.theTraversalOf) ctx.Step(`^using the parameter (.+) defined as "(.+)"$`, tg.usingTheParameterDefined) -<<<<<<< HEAD -======= ctx.Step(`^using the parameter (.+) of P\.(.+)\("(.+)"\)$`, tg.usingTheParameterOfP) ctx.Step(`^using the side effect (.+) defined as"(.+)"$`, tg.usingTheSideEffectDefined) ->>>>>>> 3.8-dev ctx.Step(`^the traversal will raise an error$`, tg.theTraversalWillRaiseAnError) ctx.Step(`^the traversal will raise an error with message (\w+) text of "(.+)"$`, tg.theTraversalWillRaiseAnErrorWithMessageContainingTextOf) } diff --git a/gremlin-go/driver/cucumber/cucumberWorld.go b/gremlin-go/driver/cucumber/cucumberWorld.go index 6e6d008af0..ac92ea1db8 100644 --- a/gremlin-go/driver/cucumber/cucumberWorld.go +++ b/gremlin-go/driver/cucumber/cucumberWorld.go @@ -21,11 +21,12 @@ package gremlingo import ( "fmt" - gremlingo "github.com/apache/tinkerpop/gremlin-go/v3/driver" - "github.com/cucumber/godog" "os" "reflect" "strconv" + + gremlingo "github.com/apache/tinkerpop/gremlin-go/v3/driver" + "github.com/cucumber/godog" ) type CucumberWorld struct { @@ -164,8 +165,11 @@ func getVertices(g *gremlingo.GraphTraversalSource) map[string]*gremlingo.Vertex func getEdges(g *gremlingo.GraphTraversalSource) map[string]*gremlingo.Edge { edgeMap := make(map[string]*gremlingo.Edge) - resE, err := g.E().Group().By(gremlingo.T__.Project("o", "l", "i"). - By(gremlingo.T__.OutV().Values("name")).By(gremlingo.T__.Label()).By(gremlingo.T__.InV().Values("name"))). + resE, err := g.E().Group(). + By(gremlingo.T__.Project("o", "l", "i"). + By(gremlingo.T__.OutV().Values("name")). + By(gremlingo.T__.Label()). + By(gremlingo.T__.InV().Values("name"))). By(gremlingo.T__.Tail()).Next() if err != nil { return nil @@ -190,38 +194,44 @@ func getEdgeKey(edgeKeyMap map[interface{}]interface{}) string { } func getVertexProperties(g *gremlingo.GraphTraversalSource) map[string]*gremlingo.VertexProperty { - vertexPropertyMap := make(map[string]*gremlingo.VertexProperty) - res, err := g.V().Properties().Group().By(&gremlingo.Lambda{ - Script: "{ it -> \n" + - " def val = it.value()\n" + - " if (val instanceof Integer)\n" + - " val = 'd[' + val + '].i'\n" + - " else if (val instanceof Float)\n" + - " val = 'd[' + val + '].f'\n" + - " else if (val instanceof Double)\n" + - " val = 'd[' + val + '].d'\n" + - " return it.element().value('name') + '-' + it.key() + '->' + val\n" + - "}", - Language: "", - }).By(gremlingo.T__.Tail()).Next() + vertexPropsMap := make(map[string]*gremlingo.VertexProperty) + res, err := g.V().Properties().Group(). + By(gremlingo.T__.Project("n", "k", "v"). + By(gremlingo.T__.Element().Values("name")). + By(gremlingo.T__.Key()). + By(gremlingo.T__.Value())). + By(gremlingo.T__.Tail()).Next() if res == nil { return nil } if err != nil { return nil } - v := reflect.ValueOf(res.GetInterface()) - if v.Kind() != reflect.Map { - fmt.Printf("Expecting to get a map as a result, got %v instead.", v.Kind()) + valMap := reflect.ValueOf(res.GetInterface()) + if valMap.Kind() != reflect.Map { + fmt.Printf("Expecting to get a map as a result, got %v instead.", valMap.Kind()) return nil } - keys := v.MapKeys() + keys := valMap.MapKeys() for _, k := range keys { - convKey := k.Convert(v.Type().Key()) - val := v.MapIndex(convKey) - vertexPropertyMap[k.Interface().(string)] = val.Interface().(*gremlingo.VertexProperty) + convKey := k.Convert(valMap.Type().Key()) + val := valMap.MapIndex(convKey) + keyMap := reflect.ValueOf(k.Interface()).Elem().Interface().(map[interface{}]interface{}) + vertexPropsMap[getVPKey(keyMap)] = val.Interface().(*gremlingo.VertexProperty) + } + return vertexPropsMap +} + +func getVPKey(vpKeyMap map[interface{}]interface{}) string { + k := vpKeyMap["k"] + v := vpKeyMap["v"] + if k == "weight" { + v = fmt.Sprint("d[", v, "].d") + } else if k == "age" || k == "since" || k == "skill" { + v = fmt.Sprint("d[", v, "].i") } - return vertexPropertyMap + // Format as n-k->v + return fmt.Sprint(vpKeyMap["n"], "-", k, "->", v) } // This function is used to isolate connection problems to each scenario, and used in the Before context hook to prevent diff --git a/gremlin-go/driver/driverRemoteConnection.go b/gremlin-go/driver/driverRemoteConnection.go index d907a7fc34..a61a9e0ac7 100644 --- a/gremlin-go/driver/driverRemoteConnection.go +++ b/gremlin-go/driver/driverRemoteConnection.go @@ -144,22 +144,23 @@ func (driver *DriverRemoteConnection) submitGremlinLang(gremlinLang *GremlinLang return driver.client.submitGremlinLang(gremlinLang) } +// TODO remove // submitBytecode sends a Bytecode traversal to the server. -func (driver *DriverRemoteConnection) submitBytecode(bytecode *Bytecode) (ResultSet, error) { - if driver.isClosed { - return nil, newError(err0203SubmitBytecodeToClosedConnectionError) - } - return driver.client.submitBytecode(bytecode) -} - -func (driver *DriverRemoteConnection) commit() (ResultSet, error) { - bc := &Bytecode{} - bc.AddSource("tx", "commit") - return driver.submitBytecode(bc) -} - -func (driver *DriverRemoteConnection) rollback() (ResultSet, error) { - bc := &Bytecode{} - bc.AddSource("tx", "rollback") - return driver.submitBytecode(bc) -} +//func (driver *DriverRemoteConnection) submitBytecode(bytecode *Bytecode) (ResultSet, error) { +// if driver.isClosed { +// return nil, newError(err0203SubmitBytecodeToClosedConnectionError) +// } +// return driver.client.submitBytecode(bytecode) +//} +// +//func (driver *DriverRemoteConnection) commit() (ResultSet, error) { +// bc := &Bytecode{} +// bc.AddSource("tx", "commit") +// return driver.submitBytecode(bc) +//} +// +//func (driver *DriverRemoteConnection) rollback() (ResultSet, error) { +// bc := &Bytecode{} +// bc.AddSource("tx", "rollback") +// return driver.submitBytecode(bc) +//} diff --git a/gremlin-go/driver/error_codes.go b/gremlin-go/driver/error_codes.go index d1fd98af55..03a4b1cf05 100644 --- a/gremlin-go/driver/error_codes.go +++ b/gremlin-go/driver/error_codes.go @@ -58,6 +58,7 @@ const ( // response handling errors err0501ResponseHandlerResultSetNotCreatedError errorCode = "E0501_PROTOCOL_RESPONSEHANDLER_NO_RESULTSET_ON_DATA_RECEIVE" + err0502ResponseHandlerReadLoopError errorCode = "E0502_PROTOCOL_RESPONSEHANDLER_READ_LOOP_ERROR" err0502ResponseHandlerError errorCode = "E0502_PROTOCOL_RESPONSEHANDLER_ERROR" err0503ResponseHandlerAuthError errorCode = "E0503_PROTOCOL_RESPONSEHANDLER_AUTH_ERROR" diff --git a/gremlin-go/driver/graphBinary.go b/gremlin-go/driver/graphBinary.go index de3c071695..c553b0a2e2 100644 --- a/gremlin-go/driver/graphBinary.go +++ b/gremlin-go/driver/graphBinary.go @@ -320,7 +320,7 @@ func edgeWriter(value interface{}, buffer *bytes.Buffer, typeSerializer *graphBi } // Not fully qualified. - _, err = typeSerializer.writeValue(e.InV.Label, buffer, false) + _, err = typeSerializer.writeValue([1]string{e.InV.Label}, buffer, false) if err != nil { return nil, err } @@ -331,7 +331,7 @@ func edgeWriter(value interface{}, buffer *bytes.Buffer, typeSerializer *graphBi } // Not fully qualified. - _, err = typeSerializer.writeValue(e.OutV.Label, buffer, false) + _, err = typeSerializer.writeValue([1]string{e.OutV.Label}, buffer, false) if err != nil { return nil, err } @@ -405,7 +405,7 @@ func setWriter(value interface{}, buffer *bytes.Buffer, typeSerializer *graphBin return listWriter(slice, buffer, typeSerializer) } -func timeWriter(value interface{}, buffer *bytes.Buffer, _ *graphBinaryTypeSerializer) ([]byte, error) { +func dateTimeWriter(value interface{}, buffer *bytes.Buffer, _ *graphBinaryTypeSerializer) ([]byte, error) { t := value.(time.Time) err := binary.Write(buffer, binary.BigEndian, int32(t.Year())) if err != nil { @@ -758,8 +758,8 @@ func readList(data *[]byte, i *int, flag byte) (interface{}, error) { if err != nil { return nil, err } - bulk := readIntSafe(data, i) - for k := int32(0); k < bulk; k++ { + bulk := readLongSafe(data, i) + for k := int64(0); k < bulk; k++ { valList = append(valList, val) } } @@ -850,7 +850,7 @@ func readUuid(data *[]byte, i *int) (interface{}, error) { return id, nil } -func timeReader(data *[]byte, i *int) (interface{}, error) { +func dateTimeReader(data *[]byte, i *int) (interface{}, error) { year := readIntSafe(data, i) month := readByteSafe(data, i) day := readByteSafe(data, i) @@ -933,7 +933,7 @@ func edgeReader(data *[]byte, i *int) (interface{}, error) { if err != nil { return nil, err } - label, err := readUnqualified(data, i, listType, false) + label, err := readList(data, i, 0) if err != nil { return nil, err } diff --git a/gremlin-go/driver/graphBinary_test.go b/gremlin-go/driver/graphBinary_test.go index f974bef652..eb44538fe1 100644 --- a/gremlin-go/driver/graphBinary_test.go +++ b/gremlin-go/driver/graphBinary_test.go @@ -23,15 +23,16 @@ import ( "bytes" "encoding/binary" "fmt" - "github.com/stretchr/testify/assert" - "golang.org/x/text/language" "math/big" "reflect" "testing" "time" + + "github.com/stretchr/testify/assert" + "golang.org/x/text/language" ) -func TestGraphBinaryV1(t *testing.T) { +func TestGraphBinaryV4(t *testing.T) { t.Run("graphBinaryTypeSerializer tests", func(t *testing.T) { serializer := graphBinaryTypeSerializer{newLogHandler(&defaultLogger{}, Error, language.English)} @@ -296,9 +297,9 @@ func TestGraphBinaryV1(t *testing.T) { pos := 0 var buffer bytes.Buffer source := time.Date(2022, 5, 10, 9, 51, 0, 0, time.Local) - buf, err := timeWriter(source, &buffer, nil) + buf, err := dateTimeWriter(source, &buffer, nil) assert.Nil(t, err) - res, err := timeReader(&buf, &pos) + res, err := dateTimeReader(&buf, &pos) assert.Nil(t, err) // ISO format assert.Equal(t, source.Format(time.RFC3339Nano), res.(time.Time).Format(time.RFC3339Nano)) @@ -307,9 +308,9 @@ func TestGraphBinaryV1(t *testing.T) { pos := 0 var buffer bytes.Buffer source := time.Date(2022, 5, 10, 9, 51, 0, 0, time.Local) - buf, err := offsetDateTimeWriter(source, &buffer, nil) + buf, err := dateTimeWriter(source, &buffer, nil) assert.Nil(t, err) - res, err := offsetDateTimeReader(&buf, &pos) + res, err := dateTimeReader(&buf, &pos) assert.Nil(t, err) // ISO format assert.Equal(t, source.Format(time.RFC3339Nano), res.(time.Time).Format(time.RFC3339Nano)) @@ -318,9 +319,9 @@ func TestGraphBinaryV1(t *testing.T) { pos := 0 var buffer bytes.Buffer source := time.Date(2022, 5, 10, 9, 51, 0, 0, time.UTC) - buf, err := offsetDateTimeWriter(source, &buffer, nil) + buf, err := dateTimeWriter(source, &buffer, nil) assert.Nil(t, err) - res, err := offsetDateTimeReader(&buf, &pos) + res, err := dateTimeReader(&buf, &pos) assert.Nil(t, err) // ISO format assert.Equal(t, source.Format(time.RFC3339Nano), res.(time.Time).Format(time.RFC3339Nano)) @@ -329,9 +330,9 @@ func TestGraphBinaryV1(t *testing.T) { pos := 0 var buffer bytes.Buffer source := time.Date(2022, 5, 10, 9, 51, 34, 123456789, GetTimezoneFromOffset(-36000)) - buf, err := offsetDateTimeWriter(source, &buffer, nil) + buf, err := dateTimeWriter(source, &buffer, nil) assert.Nil(t, err) - res, err := offsetDateTimeReader(&buf, &pos) + res, err := dateTimeReader(&buf, &pos) assert.Nil(t, err) // ISO format assert.Equal(t, source.Format(time.RFC3339Nano), res.(time.Time).Format(time.RFC3339Nano)) diff --git a/gremlin-go/driver/graphTraversal.go b/gremlin-go/driver/graphTraversal.go index abca84b18f..714e8ee447 100644 --- a/gremlin-go/driver/graphTraversal.go +++ b/gremlin-go/driver/graphTraversal.go @@ -116,7 +116,7 @@ func (g *GraphTraversal) As(args ...interface{}) *GraphTraversal { // AsBool adds the asBool step to the GraphTraversal. func (g *GraphTraversal) AsBool(args ...interface{}) *GraphTraversal { - g.Bytecode.AddStep("asBool", args...) + g.GremlinLang.AddStep("asBool", args...) return g } @@ -128,7 +128,7 @@ func (g *GraphTraversal) AsDate(args ...interface{}) *GraphTraversal { // AsNumber adds the asNumber step to the GraphTraversal. func (g *GraphTraversal) AsNumber(args ...interface{}) *GraphTraversal { - g.Bytecode.AddStep("asNumber", args...) + g.GremlinLang.AddStep("asNumber", args...) return g } @@ -947,8 +947,8 @@ func (t *Transaction) Begin() (*GraphTraversalSource, error) { } gts := &GraphTraversalSource{ - graph: t.g.graph, - gremlinLang: t.g.gremlinLang} + graph: t.g.graph, + gremlinLang: t.g.gremlinLang} return gts, nil } diff --git a/gremlin-go/driver/graphTraversalSource.go b/gremlin-go/driver/graphTraversalSource.go index 12ae62b0f7..58ad12a9a6 100644 --- a/gremlin-go/driver/graphTraversalSource.go +++ b/gremlin-go/driver/graphTraversalSource.go @@ -51,9 +51,9 @@ func NewDefaultGraphTraversalSource() *GraphTraversalSource { // GetBytecode gets the traversal Bytecode associated with this graph traversal source. // TODO remove -func (gts *GraphTraversalSource) GetBytecode() *Bytecode { - return nil -} +//func (gts *GraphTraversalSource) GetBytecode() *Bytecode { +// return nil +//} // GetGraphTraversal gets the graph traversal associated with this graph traversal source. func (gts *GraphTraversalSource) GetGraphTraversal() *GraphTraversal { diff --git a/gremlin-go/driver/gremlinClient.go b/gremlin-go/driver/gremlinClient.go deleted file mode 100644 index 5a1369c612..0000000000 --- a/gremlin-go/driver/gremlinClient.go +++ /dev/null @@ -1,148 +0,0 @@ -/* -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 ( - "net/http" -) - -// responsible for serializing and sending requests and then receiving and deserializing responses -type gremlinClient struct { - serializer serializer - logHandler *logHandler - url string - connSettings *connectionSettings - httpClient *http.Client -} - -func newGremlinClient(handler *logHandler, url string, connSettings *connectionSettings) *gremlinClient { - transport := &http.Transport{ - TLSClientConfig: connSettings.tlsConfig, - MaxConnsPerHost: 0, // TODO - IdleConnTimeout: 0, // TODO - DisableCompression: !connSettings.enableCompression, - } - - httpClient := http.Client{ - Transport: transport, - Timeout: connSettings.connectionTimeout, - } - - httpProt := &gremlinClient{ - serializer: newGraphBinarySerializer(handler), - logHandler: handler, - url: url, - connSettings: connSettings, - httpClient: &httpClient, - } - return httpProt -} - -// sends a query request and returns a ResultSet that can be used to obtain query results -func (client *gremlinClient) send(request *request) (ResultSet, error) { - rs := newChannelResultSet() - bytes, err := client.serializer.serializeMessage(request) - if err != nil { - rs.setError(err) - rs.Close() - return rs, err - } - - // one transport per request - transport := newHttpTransporter(client.url, client.connSettings, client.httpClient, client.logHandler) - - // async send request - transport.wg.Add(1) - go func() { - defer transport.wg.Done() - err := transport.write(bytes) - if err != nil { - rs.setError(err) - rs.Close() - } - }() - - // async receive response - transport.wg.Add(1) - go func() { - defer transport.wg.Done() - msg, err := transport.read() - if err != nil { - rs.setError(err) - rs.Close() - } else { - err = client.receive(rs, msg) - } - transport.close() - }() - - return rs, err -} - -// receives a binary response message, deserializes, and adds results to the ResultSet -func (client *gremlinClient) receive(rs ResultSet, msg []byte) error { - resp, err := client.serializer.deserializeMessage(msg) - if err != nil { - client.logHandler.logf(Error, logErrorGeneric, "deserializeMessage()", err.Error()) - rs.Close() - return err - } - - err = client.handleResponse(rs, resp) - if err != nil { - client.logHandler.logf(Error, logErrorGeneric, "handleResponse()", err.Error()) - rs.Close() - return err - } - return nil -} - -// processes a deserialized response and attempts to add results to the ResultSet -func (client *gremlinClient) handleResponse(rs ResultSet, response response) error { - statusCode, data := response.responseStatus.code, response.responseResult.data - if rs == nil { - return newError(err0501ResponseHandlerResultSetNotCreatedError) - } - - if statusCode == http.StatusNoContent { - rs.addResult(&Result{make([]interface{}, 0)}) - rs.Close() - client.logHandler.logf(Debug, readComplete) - } else if statusCode == http.StatusOK { - rs.addResult(&Result{data}) - rs.Close() - client.logHandler.logf(Debug, readComplete) - } else if statusCode == http.StatusUnauthorized || statusCode == http.StatusForbidden { - rs.Close() - err := newError(err0503ResponseHandlerAuthError, response.responseStatus, response.responseResult) - rs.setError(err) - return err - } else { - rs.Close() - err := newError(err0502ResponseHandlerError, response.responseStatus, statusCode) - rs.setError(err) - return err - } - return nil -} - -func (client *gremlinClient) close() { - client.httpClient.CloseIdleConnections() -} diff --git a/gremlin-go/driver/gremlinlang.go b/gremlin-go/driver/gremlinlang.go index 3a67515030..39165d2bc8 100644 --- a/gremlin-go/driver/gremlinlang.go +++ b/gremlin-go/driver/gremlinlang.go @@ -29,6 +29,8 @@ import ( "strings" "sync/atomic" "time" + + "github.com/google/uuid" ) type GremlinLang struct { @@ -46,9 +48,17 @@ func NewGremlinLang(gl *GremlinLang) *GremlinLang { optionsStrategies := make([]*traversalStrategy, 0) paramCount := atomic.Uint64{} if gl != nil { - gremlin = gl.gremlin - parameters = gl.parameters - optionsStrategies = gl.optionsStrategies + 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()) } @@ -63,7 +73,6 @@ func NewGremlinLang(gl *GremlinLang) *GremlinLang { func (gl *GremlinLang) addToGremlin(name string, args ...interface{}) error { flattenedArgs := gl.flattenArguments(args...) if name == "CardinalityValueTraversal" { - gl.gremlin = append(gl.gremlin, "Cardinality.") str0, err := gl.argAsString(flattenedArgs[0]) if err != nil { return err @@ -76,6 +85,7 @@ func (gl *GremlinLang) addToGremlin(name string, args ...interface{}) error { gl.gremlin = append(gl.gremlin, "(") gl.gremlin = append(gl.gremlin, str1) gl.gremlin = append(gl.gremlin, ")") + return nil } gl.gremlin = append(gl.gremlin, ".") @@ -112,9 +122,9 @@ func (gl *GremlinLang) argAsString(arg interface{}) (string, error) { return fmt.Sprintf("\"%s\"", escapeQuotes.Replace(v)), nil case bool: return strconv.FormatBool(v), nil - case uint8: + case int8, uint8: return fmt.Sprintf("%dB", v), nil - case int8, int16: + case int16: return fmt.Sprintf("%dS", v), nil case int32, uint16: return fmt.Sprintf("%d", v), nil @@ -130,7 +140,7 @@ func (gl *GremlinLang) argAsString(arg interface{}) (string, error) { return fmt.Sprintf("%dN", v), nil case float32: if math.IsNaN(float64(v)) { - return "Nan", nil + return "NaN", nil } if math.IsInf(float64(v), 1) { return "Infinity", nil @@ -141,7 +151,7 @@ func (gl *GremlinLang) argAsString(arg interface{}) (string, error) { return fmt.Sprintf("%vF", v), nil case float64: if math.IsNaN(v) { - return "Nan", nil + return "NaN", nil } if math.IsInf(v, 1) { return "Infinity", nil @@ -151,14 +161,19 @@ func (gl *GremlinLang) argAsString(arg interface{}) (string, error) { } return fmt.Sprintf("%vD", v), nil case *SimpleSet: - return gl.translateSlice(v.ToSlice()) - case *BigDecimal, BigDecimal: - return fmt.Sprintf("%vM", v), nil + 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: + 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 @@ -223,6 +238,8 @@ func (gl *GremlinLang) argAsString(arg interface{}) (string, error) { gl.parameters[key] = v.Value() } return key, nil + case uuid.UUID: + return fmt.Sprintf("UUID(\"%v\")", v.String()), nil default: switch reflect.TypeOf(arg).Kind() { case reflect.Map: @@ -269,8 +286,16 @@ func (gl *GremlinLang) translateMap(arg interface{}) (string, error) { } func (gl *GremlinLang) translateSlice(arg interface{}) (string, error) { + return gl.translateCollection(arg, "[", "]") +} + +func (gl *GremlinLang) translateSet(arg interface{}) (string, error) { + return gl.translateCollection(arg, "{", "}") +} + +func (gl *GremlinLang) translateCollection(arg interface{}, open, close string) (string, error) { sb := strings.Builder{} - sb.WriteString("[") + sb.WriteString(open) list := reflect.ValueOf(arg) for i := 0; i < list.Len(); i++ { @@ -283,82 +308,84 @@ func (gl *GremlinLang) translateSlice(arg interface{}) (string, error) { } sb.WriteString(vString) } - sb.WriteString("]") + sb.WriteString(close) return sb.String(), nil } func (gl *GremlinLang) translateTextPredicate(v *textP) (string, error) { - if v.operator == "" || len(v.values) == 0 { + if v.operator == "" && len(v.values) == 0 { return "", nil } - instructionString := "" - instructionString += v.operator - instructionString += "(" - if len(v.values) == 1 { - argString, err := gl.argAsString(v.values[0]) - if err != nil { - return "", err - } - instructionString += argString - } else if len(v.values) > 1 { - for index, arg := range v.values { - argString, err := gl.argAsString(arg) - if err != nil { - return "", err - } + if v.operator == "or" || v.operator == "and" { + return gl.translateConnPOp(v.operator, v.values, gl.getPredicateString) + } + return gl.translatePValue(v.operator, v.values) +} - instructionString += argString - if index < len(v.values)-1 && argString != "" { - instructionString += "," - } - } +func (gl *GremlinLang) translatePredicate(v *p) (string, error) { + if v.operator == "" && len(v.values) == 0 { + return "", nil } - instructionString += ")" + if v.operator == "or" || v.operator == "and" { + return gl.translateConnPOp(v.operator, v.values, gl.getPredicateString) + } + return gl.translatePValue(v.operator, v.values) +} - return instructionString, nil +func (gl *GremlinLang) translateConnPOp(operator string, values []interface{}, translator func(interface{}) (string, error)) (string, error) { + arg1, err := translator(values[0]) + if err != nil { + return "", err + } + arg2, err := translator(values[1]) + if err != nil { + return "", err + } + return arg1 + "." + operator + "(" + arg2 + ")", nil } -func (gl *GremlinLang) translatePredicate(v *p) (string, error) { +func (gl *GremlinLang) getPredicateString(v interface{}) (string, error) { + if val, ok := v.(textP); ok { + return gl.translateTextPredicate(&val) + } + if val, ok := v.(*textP); ok { + return gl.translateTextPredicate(val) + } + if val, ok := v.(p); ok { + return gl.translatePredicate(&val) + } + return gl.translatePredicate(v.(*p)) +} - if v.operator == "" || len(v.values) == 0 { - return "", nil +func (gl *GremlinLang) translatePValue(operator string, values []interface{}) (string, error) { + sb := strings.Builder{} + sb.WriteString(operator + "(") + + if len(values) > 1 && operator != "between" && operator != "inside" { + sb.WriteString("[") } - instructionString := "" - instructionString += v.operator - instructionString += "(" - if len(v.values) == 1 { - argString, err := gl.argAsString(v.values[0]) + for i, arg := range values { + argString, err := gl.argAsString(arg) if err != nil { return "", err } - instructionString += argString - } else if len(v.values) > 1 { - if v.operator != "between" && v.operator != "inside" { - instructionString += "[" - } - for index, arg := range v.values { - argString, err := gl.argAsString(arg) - if err != nil { - return "", err - } - - instructionString += argString - if index < len(v.values)-1 && argString != "" { - instructionString += "," - } - } - if v.operator != "between" && v.operator != "inside" { - instructionString += "]" + sb.WriteString(argString) + if i < len(values)-1 && argString != "" { + sb.WriteString(",") } } - instructionString += ")" + if len(values) > 1 && operator != "between" && operator != "inside" { + sb.WriteString("]") + } + sb.WriteString(")") - return instructionString, nil + return sb.String(), nil } + func (gl *GremlinLang) asParameter(arg interface{}) string { paramName := fmt.Sprintf("_%d", gl.paramCount.Load()) gl.paramCount.Add(1) @@ -394,11 +421,15 @@ func (gl *GremlinLang) Reset() { } func (gl *GremlinLang) AddSource(name string, arguments ...interface{}) { - if name == "withStrategies" && len(arguments) != 0 { + if (name == "withStrategies" || name == "withoutStrategies") && len(arguments) != 0 { args := gl.buildStrategyArgs(arguments...) // possible to have empty strategies list to send if len(args) != 0 { - gl.gremlin = append(gl.gremlin, ".withStrategies(") + if name == "withoutStrategies" { + gl.gremlin = append(gl.gremlin, ".withoutStrategies(") + } else { + gl.gremlin = append(gl.gremlin, ".withStrategies(") + } gl.gremlin = append(gl.gremlin, args) gl.gremlin = append(gl.gremlin, ")") } @@ -476,8 +507,13 @@ func (gl *GremlinLang) flattenArguments(arguments ...interface{}) []interface{} arg, ok := argument.([]interface{}) if ok { for _, nestedArg := range arg { - converted, _ := gl.convertArgument(nestedArg) - flatArgs = append(flatArgs, converted) + _, isUUID := nestedArg.(uuid.UUID) + if isUUID { + flatArgs = append(flatArgs, nestedArg) + } else { + converted, _ := gl.convertArgument(nestedArg) + flatArgs = append(flatArgs, converted) + } } } else { converted, _ := gl.convertArgument(argument) @@ -510,6 +546,10 @@ func (gl *GremlinLang) convertArgument(arg interface{}) (interface{}, error) { } return newMap, nil case reflect.Array, reflect.Slice: + _, isUUID := arg.(uuid.UUID) + if isUUID { + return arg, nil + } argList := reflect.ValueOf(arg) newList := make([]interface{}, argList.Len()) for i := 0; i < argList.Len(); i++ { diff --git a/gremlin-go/driver/gremlinlang_test.go b/gremlin-go/driver/gremlinlang_test.go index 450bb729ff..d462e9f77b 100644 --- a/gremlin-go/driver/gremlinlang_test.go +++ b/gremlin-go/driver/gremlinlang_test.go @@ -20,9 +20,12 @@ under the License. package gremlingo import ( + "math" "regexp" "testing" "time" + + "github.com/google/uuid" ) func Test_GremlinLang(t *testing.T) { @@ -234,12 +237,6 @@ func Test_GremlinLang(t *testing.T) { }, equals: "g.withSack(0).V(\"3\",\"5\").sack(Operator.sum).by(\"runways\").sack()", }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V("3").Values("runways").Store("x").V("4").Values("runways").Store("x").By(T__.Constant(1)).V("6").Store("x").By(T__.Constant(1)).Select("x").Unfold().Sum() - }, - equals: "g.V(\"3\").values(\"runways\").store(\"x\").V(\"4\").values(\"runways\").store(\"x\").by(__.constant(1)).V(\"6\").store(\"x\").by(__.constant(1)).select(\"x\").unfold().sum()", - }, { assert: func(g *GraphTraversalSource) *GraphTraversal { return g.Inject(3, 4, 5) @@ -641,6 +638,42 @@ func Test_GremlinLang(t *testing.T) { }, equals: "g.V().has(\"p1\",null)", }, + { + assert: func(g *GraphTraversalSource) *GraphTraversal { + return g.V().HasLabel("person").Values("age").Is(P.Between(26, 30).Or(P.Gt(34))) + }, + equals: "g.V().hasLabel(\"person\").values(\"age\").is(between(26,30).or(gt(34)))", + }, + { + assert: func(g *GraphTraversalSource) *GraphTraversal { + return g.Inject(1).AsNumber(GType.Double) + }, + equals: "g.inject(1).asNumber(GType.DOUBLE)", + }, + { + assert: func(g *GraphTraversalSource) *GraphTraversal { + return g.Inject(uuid.MustParse("f47af10b-58cc-4372-a567-0f02b2f3d479")) + }, + equals: "g.inject(UUID(\"f47af10b-58cc-4372-a567-0f02b2f3d479\"))", + }, + { + assert: func(g *GraphTraversalSource) *GraphTraversal { + return g.V().Filter(T__.Has("name", TextP.StartingWith("m").Or(TextP.StartingWith("p")))) + }, + equals: "g.V().filter(__.has(\"name\",startingWith(\"m\").or(startingWith(\"p\"))))", + }, + { + assert: func(g *GraphTraversalSource) *GraphTraversal { + return g.V().Has("person", "age", P.Within()) + }, + equals: "g.V().has(\"person\",\"age\",within([]))", + }, + { + assert: func(g *GraphTraversalSource) *GraphTraversal { + return g.Inject(math.NaN()).Is(P.Eq(math.NaN())) + }, + equals: "g.inject(NaN).is(eq(NaN))", + }, } var testsToRun []test diff --git a/gremlin-go/driver/httpTransporter.go b/gremlin-go/driver/httpTransporter.go index f11cc104e1..465b80d96e 100644 --- a/gremlin-go/driver/httpTransporter.go +++ b/gremlin-go/driver/httpTransporter.go @@ -22,12 +22,10 @@ package gremlingo import ( "bytes" "compress/zlib" - "encoding/hex" "errors" "fmt" "io" "net/http" - "os" "sync" ) @@ -101,8 +99,9 @@ func (transporter *HttpTransporter) Write(data []byte) error { return err } - str := hex.EncodeToString(all) - _, _ = fmt.Fprintf(os.Stdout, "Received response data : %s\n", str) + // TODO for debug, remove later, and check response handling + //str := hex.EncodeToString(all) + //_, _ = fmt.Fprintf(os.Stdout, "Received response data : %s\n", str) fmt.Println("Sending response to responseChannel") transporter.responseChannel <- all diff --git a/gremlin-go/driver/logger.go b/gremlin-go/driver/logger.go index eef29f9b07..f1f8c6986a 100644 --- a/gremlin-go/driver/logger.go +++ b/gremlin-go/driver/logger.go @@ -107,7 +107,6 @@ const ( creatingRequest errorKey = "CREATING_REQUEST" readComplete errorKey = "READ_COMPLETE" submitStartedString errorKey = "SUBMIT_STARTED_STRING" - submitStartedBytecode errorKey = "SUBMIT_STARTED_BYTECODE" failedToCloseInErrorCallback errorKey = "FAILED_TO_CLOSE_IN_ERROR_CALLBACK" failedToWriteMessage errorKey = "FAILED_TO_WRITE_MESSAGE" failedToSetWriteDeadline errorKey = "FAILED_TO_SET_WRITE_DEADLINE" diff --git a/gremlin-go/driver/serializer.go b/gremlin-go/driver/serializer.go index 5ef970a68f..1e1c7b2bf3 100644 --- a/gremlin-go/driver/serializer.go +++ b/gremlin-go/driver/serializer.go @@ -22,8 +22,6 @@ package gremlingo import ( "bytes" "encoding/binary" - "fmt" - "os" "sync" ) @@ -111,13 +109,16 @@ func (gs graphBinarySerializer) deserializeMessage(message []byte) (response, er if err != nil { return msg, err } - _, _ = fmt.Fprintf(os.Stdout, "Deserializing data : %v\n", n) + // TODO for debug, remove later + //_, _ = fmt.Fprintf(os.Stdout, "Deserializing data : %v\n", n) if n == EndOfStream() { break } results = append(results, n) } - _, _ = fmt.Fprintf(os.Stdout, "Deserialized results : %s\n", results) + + // TODO for debug, remove later + //_, _ = fmt.Fprintf(os.Stdout, "Deserialized results : %s\n", results) msg.responseResult.data = results code := readUint32Safe(&message, &i) msg.responseStatus.code = code @@ -173,7 +174,7 @@ func initSerializers() { propertyType: propertyWriter, vertexPropertyType: vertexPropertyWriter, pathType: pathWriter, - datetimeType: timeWriter, + datetimeType: dateTimeWriter, durationType: durationWriter, directionType: enumWriter, gTypeType: enumWriter, @@ -209,7 +210,7 @@ func initDeserializers() { byteBuffer: readByteBuffer, // Date Time - datetimeType: timeReader, + datetimeType: dateTimeReader, durationType: durationReader, // Graph diff --git a/gremlin-go/driver/strategies.go b/gremlin-go/driver/strategies.go index 939f7ea741..c0d8b3b578 100644 --- a/gremlin-go/driver/strategies.go +++ b/gremlin-go/driver/strategies.go @@ -74,7 +74,7 @@ func OptionsStrategy(options ...map[string]interface{}) TraversalStrategy { if len(options) > 0 { optsMap = options[0] } - return &traversalStrategy{name: "OptionsStrategy", configuration: options} + return &traversalStrategy{name: "OptionsStrategy", configuration: optsMap} } // PartitionStrategy partitions the Vertices, Edges and Vertex properties of a Graph into String named @@ -210,21 +210,37 @@ type MatchAlgorithmStrategyConfig struct { } func ReferenceElementStrategy(options ...map[string]interface{}) TraversalStrategy { - return &traversalStrategy{name: "ReferenceElementStrategy", configuration: options[0]} + config := make(map[string]interface{}) + if len(options) > 0 { + config = options[0] + } + return &traversalStrategy{name: "ReferenceElementStrategy", configuration: config} } func ComputerFinalizationStrategy(options ...map[string]interface{}) TraversalStrategy { - return &traversalStrategy{name: "ComputerFinalizationStrategy", configuration: options[0]} + config := make(map[string]interface{}) + if len(options) > 0 { + config = options[0] + } + return &traversalStrategy{name: "ComputerFinalizationStrategy", configuration: config} } func ProfileStrategy(options ...map[string]interface{}) TraversalStrategy { - return &traversalStrategy{name: "ProfileStrategy", configuration: options[0]} + config := make(map[string]interface{}) + if len(options) > 0 { + config = options[0] + } + return &traversalStrategy{name: "ProfileStrategy", configuration: config} } // Verification strategies func ComputerVerificationStrategy(options ...map[string]interface{}) TraversalStrategy { - return &traversalStrategy{name: "ComputerVerificationStrategy", configuration: options[0]} + config := make(map[string]interface{}) + if len(options) > 0 { + config = options[0] + } + return &traversalStrategy{name: "ComputerVerificationStrategy", configuration: config} } // EdgeLabelVerificationStrategy does not allow Edge traversal steps to have no label specified. @@ -290,14 +306,6 @@ func VertexProgramRestrictionStrategy() TraversalStrategy { return &traversalStrategy{name: "VertexProgramRestrictionStrategy"} } -func StandardVerificationStrategy() TraversalStrategy { - return &traversalStrategy{name: "StandardVerificationStrategy"} -} - -func VertexProgramRestrictionStrategy() TraversalStrategy { - return &traversalStrategy{name: "VertexProgramRestrictionStrategy"} -} - // Optimization strategies // AdjacentToIncidentStrategy looks for Vertex- and value-emitting steps followed by a CountGlobalStep and replaces @@ -387,7 +395,11 @@ func MatchPredicateStrategy() TraversalStrategy { } func MessagePassingReductionStrategy(options ...map[string]interface{}) TraversalStrategy { - return &traversalStrategy{name: "MessagePassingReductionStrategy", configuration: options[0]} + config := make(map[string]interface{}) + if len(options) > 0 { + config = options[0] + } + return &traversalStrategy{name: "MessagePassingReductionStrategy", configuration: config} } // OrderLimitStrategy is an OLAP strategy that folds a RangeGlobalStep into a preceding diff --git a/gremlin-go/driver/translator.go b/gremlin-go/driver/translator.go deleted file mode 100644 index 10629a51c3..0000000000 --- a/gremlin-go/driver/translator.go +++ /dev/null @@ -1,365 +0,0 @@ -/* -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" - "reflect" - "strings" - "time" -) - -type Translator interface { - Translate(bytecode *Bytecode) (string, error) -} - -type translator struct { - source string -} - -func NewTranslator(source string) Translator { - return &translator{source} -} - -func (t *translator) Translate(bytecode *Bytecode) (string, error) { - return t.translate(bytecode, true) -} - -func (t *translator) translate(bytecode *Bytecode, initial bool) (string, error) { - translated := "" - - if initial { - translated += t.source - appendDot(&translated) - } - - for _, instruction := range bytecode.sourceInstructions { - if len(instruction.arguments) == 0 { - continue - } - - appendDot(&translated) - - translatedInstruction, err := t.translateInstruction(instruction) - if err != nil { - return "", err - } - translated += translatedInstruction - } - - appendDot(&translated) - - for _, instruction := range bytecode.stepInstructions { - - appendDot(&translated) - - translatedInstruction, err := t.translateInstruction(instruction) - if err != nil { - return "", err - } - translated += translatedInstruction - } - - return translated, nil -} - -func (t *translator) translateInstruction(instruction instruction) (string, error) { - instructionString := fmt.Sprintf("%v(", instruction.operator) - - for index, arg := range instruction.arguments { - if index > 0 { - instructionString += "," - } - - if instruction.operator == "with" { - switch v := arg.(type) { - case int32, string: - translatedArg, err := t.translateWithOptions(v) - if err != nil { - return "", err - } - instructionString += translatedArg - continue - } - } - - argString, err := t.toString(arg) - if err != nil { - return "", err - } - instructionString += argString - - } - - instructionString += ")" - - return instructionString, nil -} - -func (t *translator) translateWithOptions(arg interface{}) (string, error) { - if groovyWithOptions[arg] != "" { - return groovyWithOptions[arg], nil - } - - return t.toString(arg) -} - -func (t *translator) translateMap(arg interface{}, isClassParamsMap bool) (string, error) { - instructionString := "" - iter := reflect.ValueOf(arg).MapRange() - - index := 0 - for iter.Next() { - if index == 0 && !isClassParamsMap { - instructionString += "{" - } - - k := iter.Key().Interface() - kString, err := t.toString(k) - if err != nil { - return "", err - } - if isClassParamsMap { - kString = strings.Replace(kString, "'", "", -1) - } - v := iter.Value().Interface() - vString, err := t.toString(v) - if err != nil { - return "", err - } - instructionString += fmt.Sprintf("%v:%v", kString, vString) - - if index < reflect.ValueOf(arg).Len()-1 { - instructionString += "," - } - - if index == reflect.ValueOf(arg).Len()-1 && !isClassParamsMap { - instructionString += "}" - } - index++ - - } - - return instructionString, nil -} - -func (t *translator) translateSlice(arg interface{}) (string, error) { - instructionString := "[" - oldSlice := reflect.ValueOf(arg) - if oldSlice.Len() == 0 { - return "", nil - } - - for i := 0; i < oldSlice.Len(); i++ { - if i > 0 { - instructionString += "," - } - instructionStepString, err := t.toString(oldSlice.Index(i).Interface()) - if err != nil { - return "", err - } - instructionString += fmt.Sprintf("%v", instructionStepString) - } - instructionString += "]" - - return instructionString, nil -} - -func (t *translator) translateTextPredicate(v *textP) (string, error) { - if v.operator == "" || len(v.values) == 0 { - return "", nil - } - - instructionString := "" - instructionString += v.operator - instructionString += "(" - if len(v.values) == 1 { - argString, err := t.toString(v.values[0]) - if err != nil { - return "", err - } - instructionString += argString - } else if len(v.values) > 1 { - for index, arg := range v.values { - argString, err := t.toString(arg) - if err != nil { - return "", err - } - - instructionString += argString - if index < len(v.values)-1 && argString != "" { - instructionString += "," - } - } - } - - instructionString += ")" - - return instructionString, nil -} - -func (t *translator) translatePredicate(v *p) (string, error) { - - if v.operator == "" || len(v.values) == 0 { - return "", nil - } - - instructionString := "" - instructionString += v.operator - instructionString += "(" - if len(v.values) == 1 { - argString, err := t.toString(v.values[0]) - if err != nil { - return "", err - } - instructionString += argString - } else if len(v.values) > 1 { - if v.operator != "between" && v.operator != "inside" { - instructionString += "[" - } - for index, arg := range v.values { - argString, err := t.toString(arg) - if err != nil { - return "", err - } - - instructionString += argString - if index < len(v.values)-1 && argString != "" { - instructionString += "," - } - } - if v.operator != "between" && v.operator != "inside" { - instructionString += "]" - } - } - - instructionString += ")" - - return instructionString, nil -} - -func (t *translator) translateTraversalStrategy(v *traversalStrategy) (string, error) { - - instructionString := "" - className := getGroovyClassName(v.name) - instructionString += fmt.Sprintf("new %v(", className) - instructionConfigurationString, err := t.translateMap(interface{}(v.configuration), true) - if err != nil { - return "", err - } - instructionString += instructionConfigurationString - instructionString += ")" - - return instructionString, nil - -} - -func (t *translator) toString(arg interface{}) (string, error) { - if arg == nil { - return "null", nil - } - reflectedArg := reflect.TypeOf(arg) - switch reflectedArg.Kind() { - - case reflect.Map: - return t.translateMap(arg, false) - case reflect.Slice: - return t.translateSlice(arg) - default: - switch v := arg.(type) { - case withOptions: - { - return groovyWithOptions[v], nil - } - case AnonymousTraversal: - case *AnonymousTraversal: - return t.toString(arg) - case *Binding: - return v.String(), nil - case GraphTraversal: - case *GraphTraversal: - return t.translate(v.Bytecode, false) - case traversalStrategy: - case *traversalStrategy: - return t.translateTraversalStrategy(v) - case *Bytecode: - return t.translate(v, false) - case textP: - case *textP: - return t.translateTextPredicate(v) - case p: - case *p: - return t.translatePredicate(v) - default: - { - switch v := arg.(type) { - case time.Time: - { - return timeToGroovyTime(v), nil - } - case string: - { - return fmt.Sprintf("'%v'", v), nil - } - default: - { - return fmt.Sprintf("%v", v), nil - } - } - } - } - } - - return "", nil - -} - -func appendDot(s *string) { - if len(*s) == 0 { - return - } - - if (*s)[len(*s)-1] != '.' { - *s += "." - } -} - -func getGroovyClassName(classPath string) string { - classPathArray := strings.Split(classPath, ".") - return classPathArray[len(classPathArray)-1] -} - -func timeToGroovyTime(t time.Time) string { - return fmt.Sprintf("new Date(%v,%v,%v,%v,%v,%v)", t.Year()-1900, int(t.Month()), t.Day(), t.Hour(), t.Minute(), t.Second()) - -} - -var groovyWithOptions map[any]string = map[any]string{ - WithOptions.Tokens: "WithOptions.tokens", - WithOptions.None: "WithOptions.none", - WithOptions.Ids: "WithOptions.ids", - WithOptions.Labels: "WithOptions.labels", - WithOptions.Keys: "WithOptions.keys", - WithOptions.Values: "WithOptions.values", - WithOptions.All: "WithOptions.all", - WithOptions.Indexer: "WithOptions.indexer", - WithOptions.List: "WithOptions.list", - WithOptions.Map: "WithOptions.map", -} diff --git a/gremlin-go/driver/translator_test.go b/gremlin-go/driver/translator_test.go deleted file mode 100644 index 8daa5ce312..0000000000 --- a/gremlin-go/driver/translator_test.go +++ /dev/null @@ -1,717 +0,0 @@ -/* -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 ( - "regexp" - "testing" - "time" -) - -func Test_translator_Translate(t *testing.T) { - type test struct { - name string - assert func(g *GraphTraversalSource) *GraphTraversal - equals string - only bool - skip bool - wantErr bool - containsRandomClassParams bool - } - tests := []test{ - { - assert: func(g *GraphTraversalSource) *GraphTraversal { return g.V() }, - equals: "g.V()", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { return g.V("1", "2", "3", "4") }, - equals: "g.V('1','2','3','4')", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { return g.V("3").ValueMap(true) }, - equals: "g.V('3').valueMap(true)", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { return g.V().Constant(5) }, - equals: "g.V().constant(5)", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { return g.V().Constant(1.5) }, - equals: "g.V().constant(1.5)", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { return g.V().Constant("Hello") }, - equals: "g.V().constant('Hello')", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { return g.V().HasLabel("airport").Limit(5) }, - equals: "g.V().hasLabel('airport').limit(5)", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { return g.V().HasLabel(P.Within("a", "b", "c")) }, - equals: "g.V().hasLabel(within(['a','b','c']))", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V().HasLabel("airport", "continent").Out().Limit(5) - }, - equals: "g.V().hasLabel('airport','continent').out().limit(5)", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V().HasLabel("airport").Out().Values("code").Limit(5) - }, - equals: "g.V().hasLabel('airport').out().values('code').limit(5)", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V("3").As("a").Out("route").Limit(10).Where(P.Eq("a")).By("region") - }, - equals: "g.V('3').as('a').out('route').limit(10).where(eq('a')).by('region')", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V("3").Repeat(T__.Out("route").SimplePath()).Times(2).Path().By("code") - }, - equals: "g.V('3').repeat(out('route').simplePath()).times(2).path().by('code')", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V().HasLabel("airport").Out().Has("region", "US-TX").Values("code").Limit(5) - }, - equals: "g.V().hasLabel('airport').out().has('region','US-TX').values('code').limit(5)", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V().HasLabel("airport").Union(T__.Values("city"), T__.Values("region")).Limit(5) - }, - equals: "g.V().hasLabel('airport').union(values('city'),values('region')).limit(5)", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { return g.V("3").As("a").Out("route", "routes") }, - equals: "g.V('3').as('a').out('route','routes')", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { return g.V().Where(T__.Values("runways").Is(5)) }, - equals: "g.V().where(values('runways').is(5))", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V("3").Repeat(T__.Out().SimplePath()).Until(T__.Has("code", "AGR")).Path().By("code").Limit(5) - }, - equals: "g.V('3').repeat(out().simplePath()).until(has('code','AGR')).path().by('code').limit(5)", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { return g.V().HasLabel("airport").Order().By(T__.Id()) }, - equals: "g.V().hasLabel('airport').order().by(id())", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { return g.V().HasLabel("airport").Order().By(T.Id) }, - equals: "g.V().hasLabel('airport').order().by(id)", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V().HasLabel("airport").Order().By(T__.Id(), Order.Desc) - }, - equals: "g.V().hasLabel('airport').order().by(id(),desc)", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V().HasLabel("airport").Order().By("code", Order.Desc) - }, - equals: "g.V().hasLabel('airport').order().by('code',desc)", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V("1", "2", "3").Local(T__.Out().Out().Dedup().Fold()) - }, - equals: "g.V('1','2','3').local(out().out().dedup().fold())", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V("3").Out().Path().Count(Scope.Local) - }, - equals: "g.V('3').out().path().count(local)", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.E().Count() - }, - equals: "g.E().count()", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V("5").OutE("route").InV().Path().Limit(10) - }, - equals: "g.V('5').outE('route').inV().path().limit(10)", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V("5").PropertyMap().Select(Column.Keys) - }, - equals: "g.V('5').propertyMap().select(keys)", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V("5").PropertyMap().Select(Column.Values) - }, - equals: "g.V('5').propertyMap().select(values)", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V("3").Values("runways").Math("_ + 1") - }, - equals: "g.V('3').values('runways').math('_ + 1')", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V("3").Emit().Repeat(T__.Out().SimplePath()).Times(3).Limit(5).Path() - }, - equals: "g.V('3').emit().repeat(out().simplePath()).times(3).limit(5).path()", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V().Match(T__.As("a").Has("code", "LHR").As("b")).Select("b").By("code") - }, - equals: "g.V().match(as('a').has('code','LHR').as('b')).select('b').by('code')", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V().Has("test-using-keyword-as-property", "repeat") - }, - equals: "g.V().has('test-using-keyword-as-property','repeat')", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V("1").AddE("test").To(T__.V("4")) - }, - equals: "g.V('1').addE('test').to(V('4'))", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V().Values("runways").Max() - }, - equals: "g.V().values('runways').max()", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V().Values("runways").Min() - }, - equals: "g.V().values('runways').min()", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V().Values("runways").Sum() - }, - equals: "g.V().values('runways').sum()", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V().Values("runways").Mean() - }, - equals: "g.V().values('runways').mean()", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.WithSack(0).V("3", "5").Sack(Operator.Sum).By("runways").Sack() - }, - equals: "g.withSack(0).V('3','5').sack(sum).by('runways').sack()", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.Inject(3, 4, 5) - }, - equals: "g.inject(3,4,5)", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.Inject([]interface{}{3, 4, 5}) - }, - equals: "g.inject([3,4,5])", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.Inject(3, 4, 5).Count() - }, - equals: "g.inject(3,4,5).count()", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V().Has("runways", P.Gt(5)).Count() - }, - equals: "g.V().has('runways',gt(5)).count()", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V().Has("runways", P.Lte(5.3)).Count() - }, - equals: "g.V().has('runways',lte(5.3)).count()", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V().Has("code", P.Within(123, 124)) - }, - equals: "g.V().has('code',within([123,124]))", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V().Has("code", P.Within(123, "abc")) - }, - equals: "g.V().has('code',within([123,'abc']))", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V().Has("code", P.Within("abc", 123)) - }, - equals: "g.V().has('code',within(['abc',123]))", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V().Has("code", P.Within("abc", "xyz")) - }, - equals: "g.V().has('code',within(['abc','xyz']))", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V("1", "2").Has("region", P.Within("US-TX", "US-GA")) - }, - equals: "g.V('1','2').has('region',within(['US-TX','US-GA']))", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V().And(T__.Has("runways", P.Gt(5)), T__.Has("region", "US-TX")) - }, - equals: "g.V().and(has('runways',gt(5)),has('region','US-TX'))", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V().Union(T__.Has("runways", P.Gt(5)), T__.Has("region", "US-TX")) - }, - equals: "g.V().union(has('runways',gt(5)),has('region','US-TX'))", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V("3").Choose(T__.Values("runways").Is(3), T__.Constant("three"), T__.Constant("not three")) - }, - equals: "g.V('3').choose(values('runways').is(3),constant('three'),constant('not three'))", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V("3").Choose(T__.Values("runways")).Option(1, T__.Constant("three")).Option(2, T__.Constant("not three")) - }, - equals: "g.V('3').choose(values('runways')).option(1,constant('three')).option(2,constant('not three'))", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V("3").Choose(T__.Values("runways")).Option(1.5, T__.Constant("one and a half")).Option(2, T__.Constant("not three")) - }, - equals: "g.V('3').choose(values('runways')).option(1.5,constant('one and a half')).option(2,constant('not three'))", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V("3").Repeat(T__.Out().SimplePath()).Until(T__.Loops().Is(1)).Count() - }, - equals: "g.V('3').repeat(out().simplePath()).until(loops().is(1)).count()", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V().HasLabel("airport").Limit(20).Group().By("region").By("code").Order(Scope.Local).By(Column.Keys) - }, - equals: "g.V().hasLabel('airport').limit(20).group().by('region').by('code').order(local).by(keys)", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V("1").As("a").V("2").As("a").Select(Pop.All, "a") - }, - equals: "g.V('1').as('a').V('2').as('a').select(all,'a')", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.AddV("test").Property(Cardinality.Set, "p1", 10) - }, - equals: "g.addV('test').property(set,'p1',10)", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.AddV("test").Property(Cardinality.List, "p1", 10) - }, - equals: "g.addV('test').property(list,'p1',10)", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.AddV("test").Property(Cardinality.Single, "p1", 10) - }, - equals: "g.addV('test').property(single,'p1',10)", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V().Limit(5).Order().By(T__.Label()) - }, - equals: "g.V().limit(5).order().by(label())", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V().Range(1, 5) - }, - equals: "g.V().range(1,5)", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.AddV("test").Property("p1", 123) - }, - equals: "g.addV('test').property('p1',123)", - }, - { - 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)))", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.AddE("route").From(T__.V("1")).To(T__.V("2")) - }, - equals: "g.addE('route').from(V('1')).to(V('2'))", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.WithSideEffect("a", []interface{}{1, 2}).V("3").Select("a") - }, - equals: "g.withSideEffect('a',[1,2]).V('3').select('a')", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.WithSideEffect("a", 1).V("3").Select("a") - }, - equals: "g.withSideEffect('a',1).V('3').select('a')", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.WithSideEffect("a", "abc").V("3").Select("a") - }, - equals: "g.withSideEffect('a','abc').V('3').select('a')", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V().Has("airport", "region", "US-NM").Limit(3).Values("elev").Fold().Index() - }, - equals: "g.V().has('airport','region','US-NM').limit(3).values('elev').fold().index()", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V("3").Repeat(T__.TimeLimit(1000).Out().SimplePath()).Until(T__.Has("code", "AGR")).Path() - }, - equals: "g.V('3').repeat(timeLimit(1000).out().simplePath()).until(has('code','AGR')).path()", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V().HasLabel("airport").Where(T__.Values("elev").Is(P.Gt(14000))) - }, - equals: "g.V().hasLabel('airport').where(values('elev').is(gt(14000)))", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V().HasLabel("airport").Where(T__.Out().Count().Is(P.Gt(250))).Values("code") - }, - equals: "g.V().hasLabel('airport').where(out().count().is(gt(250))).values('code')", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V().HasLabel("airport").Filter(T__.Out().Count().Is(P.Gt(250))).Values("code") - }, - equals: "g.V().hasLabel('airport').filter(out().count().is(gt(250))).values('code')", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.WithSack(0). - V("3"). - Repeat(T__.OutE("route").Sack(Operator.Sum).By("dist").InV()). - Until(T__.Has("code", "AGR").Or().Loops().Is(4)). - Has("code", "AGR"). - 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)", - }, - { - 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')", - }, - { - 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')", - }, - { - 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())", - }, - { - 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()", - }, - { - 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))", - }, - { - 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)]))", - }, - { - 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)))", - }, - { - 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)))", - }, - { - 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)))", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V().Has("runways", P.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))", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return 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())", - }, - { - 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)", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V("44").ValueMap().With(WithOptions.All) - }, - equals: "g.V('44').valueMap().with(WithOptions.all)", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V("44").ValueMap().With(WithOptions.Indexer) - }, - equals: "g.V('44').valueMap().with(WithOptions.indexer)", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V("44").ValueMap().With(WithOptions.Tokens) - }, - equals: "g.V('44').valueMap().with(WithOptions.tokens)", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.WithStrategies(ReadOnlyStrategy()).AddV("test") - }, - equals: "g.withStrategies(new ReadOnlyStrategy()).addV('test')", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.WithStrategies(SubgraphStrategy(SubgraphStrategyConfig{Vertices: T__.Has("region", "US-TX"), Edges: T__.HasLabel("route")})).V().Count() - }, - containsRandomClassParams: true, - equals: "g.withStrategies(new SubgraphStrategy(vertices:has('region','US-TX'),edges:hasLabel('route'))).V().count()", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.WithStrategies(SubgraphStrategy(SubgraphStrategyConfig{VertexProperties: T__.HasNot("runways")})).V().Count() - }, - equals: "g.withStrategies(new SubgraphStrategy(vertexProperties:hasNot('runways'))).V().count()", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.WithStrategies(SubgraphStrategy(SubgraphStrategyConfig{Vertices: T__.Has("region", "US-TX"), VertexProperties: T__.HasNot("runways")})).V().Count() - }, - containsRandomClassParams: true, - equals: "g.withStrategies(new SubgraphStrategy(vertices:has('region','US-TX'),vertexProperties:hasNot('runways'))).V().count()", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.WithStrategies(ReadOnlyStrategy(), SubgraphStrategy(SubgraphStrategyConfig{Vertices: T__.Has("region", "US-TX"), Edges: T__.HasLabel("route")})).V().Count() - }, - containsRandomClassParams: true, - equals: "g.withStrategies(new ReadOnlyStrategy(),new SubgraphStrategy(vertices:has('region','US-TX'),edges:hasLabel('route'))).V().count()", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.WithStrategies(ReadOnlyStrategy(), SubgraphStrategy(SubgraphStrategyConfig{Vertices: T__.Has("region", "US-TX")})).V().Count() - }, - equals: "g.withStrategies(new ReadOnlyStrategy(),new SubgraphStrategy(vertices:has('region','US-TX'))).V().count()", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.WithStrategies(OptionsStrategy(map[string]interface{}{"evaluationTimeout": 500})).V().Count() - }, - equals: "g.withStrategies(new OptionsStrategy(evaluationTimeout:500)).V().count()", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.WithStrategies(PartitionStrategy(PartitionStrategyConfig{PartitionKey: "partition", WritePartition: "a", ReadPartitions: NewSimpleSet("a")})).AddV("test") - }, - containsRandomClassParams: true, - equals: "g.withStrategies(new PartitionStrategy(includeMetaProperties:false,partitionKey:'partition',writePartition:'a',readPartitions:['a'])).addV('test')", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.WithStrategies(VertexProgramStrategy(VertexProgramStrategyConfig{})).V().ShortestPath().With("~tinkerpop.shortestPath.target", T__.Has("name", "peter")) - }, - equals: "g.withStrategies(new VertexProgramStrategy()).V().shortestPath().with('~tinkerpop.shortestPath.target',has('name','peter'))", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V().Has("p1", TextP.StartingWith("foo")) - }, - equals: "g.V().has('p1',startingWith('foo'))", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V().Has("p1", TextP.EndingWith("foo")) - }, - equals: "g.V().has('p1',endingWith('foo'))", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V().Has("p1", TextP.Containing("foo")) - }, - equals: "g.V().has('p1',containing('foo'))", - }, - { - assert: func(g *GraphTraversalSource) *GraphTraversal { - return g.V().Has("p1", nil) - }, - equals: "g.V().has('p1',null)", - }, - } - - var testsToRun []test - - onlyTests := make([]test, 0) - for _, tt := range tests { - if tt.only { - onlyTests = append(onlyTests, tt) - } - } - - if len(onlyTests) > 0 { - testsToRun = onlyTests - } else { - testsToRun = tests - } - - for _, tt := range testsToRun { - if tt.skip { - continue - } - - testName := tt.name - if testName == "" { - testName = tt.equals - } - - t.Run(testName, func(t *testing.T) { - tr := &translator{ - source: "g", - } - g := NewGraphTraversalSource(nil, nil) - bytecode := tt.assert(g).Bytecode - got, err := tr.Translate(bytecode) - if (err != nil) != tt.wantErr { - t.Errorf("translator.Translate() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !tt.containsRandomClassParams && got != tt.equals { - t.Errorf("translator.Translate() = %v, equals %v", got, tt.equals) - } - - if tt.containsRandomClassParams { - equalsParams := getParams(tt.equals) - gotParams := getParams(got) - - if len(equalsParams) != len(gotParams) { - t.Errorf("translator.Translate() = %v, equals %v", got, tt.equals) - } - - for _, equalsParam := range equalsParams { - found := false - for _, gotParam := range gotParams { - if equalsParam == gotParam { - found = true - break - } - } - if !found { - t.Errorf("translator.Translate() = %v, equals %v", got, tt.equals) - } - } - } - }) - } -} - -func getParams(result string) []string { - pattern := `(\w+:.*?)` - re := regexp.MustCompile(pattern) - matches := re.FindAllStringSubmatch(result, -1) - - params := make([]string, 0) - for _, match := range matches { - if len(match) > 0 { - params = append(params, match[0]) - } - } - - return params -} diff --git a/gremlin-go/driver/traversal.go b/gremlin-go/driver/traversal.go index a1948e6aa6..b76862849d 100644 --- a/gremlin-go/driver/traversal.go +++ b/gremlin-go/driver/traversal.go @@ -33,7 +33,7 @@ type Traverser struct { // Traversal is the primary way in which graphs are processed. type Traversal struct { graph *Graph - Bytecode *Bytecode + Bytecode *Bytecode //TODO remove GremlinLang *GremlinLang remote *DriverRemoteConnection results ResultSet @@ -162,33 +162,33 @@ var Cardinality = cardinalities{ } type cv struct { - Bytecode *Bytecode + GremlinLang *GremlinLang } type CardValue interface { - Single(val interface{}) Bytecode - Set(val interface{}) Bytecode - List(val interface{}) Bytecode + Single(val interface{}) GremlinLang + Set(val interface{}) GremlinLang + List(val interface{}) GremlinLang } var CardinalityValue CardValue = &cv{} -func (*cv) Single(val interface{}) Bytecode { - bc := Bytecode{} - bc.AddSource("CardinalityValueTraversal", Cardinality.Single, val) - return bc +func (*cv) Single(val interface{}) GremlinLang { + gl := GremlinLang{} + gl.AddSource("CardinalityValueTraversal", Cardinality.Single, val) + return gl } -func (*cv) Set(val interface{}) Bytecode { - bc := Bytecode{} - bc.AddSource("CardinalityValueTraversal", Cardinality.Set, val) - return bc +func (*cv) Set(val interface{}) GremlinLang { + gl := GremlinLang{} + gl.AddSource("CardinalityValueTraversal", Cardinality.Set, val) + return gl } -func (*cv) List(val interface{}) Bytecode { - bc := Bytecode{} - bc.AddSource("CardinalityValueTraversal", Cardinality.List, val) - return bc +func (*cv) List(val interface{}) GremlinLang { + gl := GremlinLang{} + gl.AddSource("CardinalityValueTraversal", Cardinality.List, val) + return gl } type column string @@ -518,7 +518,7 @@ func newP(operator string, args ...interface{}) Predicate { return &p{operator: operator, values: values} } -func newPWithP(operator string, pp p, args ...interface{}) Predicate { +func newPWithP(operator string, pp *p, args ...interface{}) Predicate { values := make([]interface{}, 1) values[0] = pp values = append(values, args...) @@ -606,12 +606,12 @@ func (*p) Without(args ...interface{}) Predicate { // And Predicate returns a Predicate composed of two predicates (logical AND of them). func (pp *p) And(args ...interface{}) Predicate { - return newPWithP("and", *pp, args...) + return newPWithP("and", pp, args...) } // Or Predicate returns a Predicate composed of two predicates (logical OR of them). func (pp *p) Or(args ...interface{}) Predicate { - return newPWithP("or", *pp, args...) + return newPWithP("or", pp, args...) } type TextPredicate interface { @@ -784,6 +784,18 @@ type BigDecimal struct { UnscaledValue *big.Int } +func (bd *BigDecimal) Value() *big.Float { + // Create the divisor: 10^scale + divisor := new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(bd.Scale)), nil) + + // Convert unscaled value and divisor to big.Float + unscaled := new(big.Float).SetInt(bd.UnscaledValue) + div := new(big.Float).SetInt(divisor) + + // Divide: unscaledValue / 10^scale + return new(big.Float).Quo(unscaled, div) +} + // ParseBigDecimal creates a BigDecimal from a string value. func ParseBigDecimal(strValue string) *BigDecimal { val := &BigDecimal{} diff --git a/gremlin-go/driver/traversal_test.go b/gremlin-go/driver/traversal_test.go index 97520bf76c..dff1876726 100644 --- a/gremlin-go/driver/traversal_test.go +++ b/gremlin-go/driver/traversal_test.go @@ -36,16 +36,16 @@ func TestTraversal(t *testing.T) { clone := original.Clone().Out("knows") cloneClone := clone.Clone().Out("created") - assert.Equal(t, 2, len(original.Bytecode.stepInstructions)) - assert.Equal(t, 3, len(clone.Bytecode.stepInstructions)) - assert.Equal(t, 4, len(cloneClone.Bytecode.stepInstructions)) + assert.Equal(t, "g.V().out(\"created\")", original.GremlinLang.GetGremlin()) + assert.Equal(t, "g.V().out(\"created\").out(\"knows\")", clone.GremlinLang.GetGremlin()) + assert.Equal(t, "g.V().out(\"created\").out(\"knows\").out(\"created\")", cloneClone.GremlinLang.GetGremlin()) original.Has("person", "name", "marko") clone.V().Out() - assert.Equal(t, 3, len(original.Bytecode.stepInstructions)) - assert.Equal(t, 5, len(clone.Bytecode.stepInstructions)) - assert.Equal(t, 4, len(cloneClone.Bytecode.stepInstructions)) + assert.Equal(t, "g.V().out(\"created\").has(\"person\",\"name\",\"marko\")", original.GremlinLang.GetGremlin()) + assert.Equal(t, "g.V().out(\"created\").out(\"knows\").V().out()", clone.GremlinLang.GetGremlin()) + assert.Equal(t, "g.V().out(\"created\").out(\"knows\").out(\"created\")", cloneClone.GremlinLang.GetGremlin()) }) t.Run("Test Iterate with empty removeConnection", func(t *testing.T) { @@ -524,7 +524,7 @@ func TestTraversal(t *testing.T) { }) t.Run("Test should extract ID from Vertex", func(t *testing.T) { - g := cloneGraphTraversalSource(&Graph{}, NewBytecode(nil), nil) + g := cloneGraphTraversalSource(&Graph{}, NewGremlinLang(nil), nil) // Test basic V() step with mixed ID types vStart := g.V(1, &Vertex{Element: Element{Id: 2}}) diff --git a/gremlin-go/examples/go.mod b/gremlin-go/examples/go.mod index 20da81ee7d..6dd55e1afc 100644 --- a/gremlin-go/examples/go.mod +++ b/gremlin-go/examples/go.mod @@ -26,6 +26,6 @@ replace github.com/apache/tinkerpop/gremlin-go/v3 => ../ require ( github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect - github.com/nicksnyder/go-i18n/v2 v2.5.0 // indirect - golang.org/x/text v0.21.0 // indirect + github.com/nicksnyder/go-i18n/v2 v2.6.0 // indirect + golang.org/x/text v0.32.0 // indirect ) diff --git a/gremlin-go/examples/go.sum b/gremlin-go/examples/go.sum index b3d1c347c8..4d66940fd6 100644 --- a/gremlin-go/examples/go.sum +++ b/gremlin-go/examples/go.sum @@ -8,6 +8,7 @@ github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aN github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/nicksnyder/go-i18n/v2 v2.5.0 h1:3wH1gpaekcgGuwzWdSu7JwJhH9Tk87k1ezt0i1p2/Is= github.com/nicksnyder/go-i18n/v2 v2.5.0/go.mod h1:DrhgsSDZxoAfvVrBVLXoxZn/pN5TXqaDbq7ju94viiQ= +github.com/nicksnyder/go-i18n/v2 v2.6.0/go.mod h1:88sRqr0C6OPyJn0/KRNaEz1uWorjxIKP7rUUcvycecE= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= @@ -16,5 +17,6 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/gremlin-go/go.mod b/gremlin-go/go.mod index 8b0e656723..c36ea3718d 100644 --- a/gremlin-go/go.mod +++ b/gremlin-go/go.mod @@ -20,22 +20,22 @@ module github.com/apache/tinkerpop/gremlin-go/v3 go 1.25 require ( - github.com/cucumber/godog v0.15.0 + github.com/cucumber/godog v0.15.1 github.com/google/uuid v1.6.0 - github.com/nicksnyder/go-i18n/v2 v2.5.0 - github.com/stretchr/testify v1.9.0 - golang.org/x/text v0.21.0 + github.com/nicksnyder/go-i18n/v2 v2.6.0 + github.com/stretchr/testify v1.11.1 + golang.org/x/text v0.32.0 ) require ( 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 - github.com/gofrs/uuid v4.3.1+incompatible // indirect + github.com/gofrs/uuid v4.4.0+incompatible // indirect 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/hashicorp/go-memdb v1.3.5 // indirect + github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/pflag v1.0.10 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/gremlin-go/go.sum b/gremlin-go/go.sum index 87eb5eae01..59675a75c5 100644 --- a/gremlin-go/go.sum +++ b/gremlin-go/go.sum @@ -1,10 +1,10 @@ -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/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= +github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= 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= -github.com/cucumber/godog v0.15.0 h1:51AL8lBXF3f0cyA5CV4TnJFCTHpgiy+1x1Hb3TtZUmo= -github.com/cucumber/godog v0.15.0/go.mod h1:FX3rzIDybWABU4kuIXLZ/qtqEe1Ac5RdXmqvACJOces= +github.com/cucumber/godog v0.15.1 h1:rb/6oHDdvVZKS66hrhpjFQFHjthFSrQBCOI1LwshNTI= +github.com/cucumber/godog v0.15.1/go.mod h1:qju+SQDewOljHuq9NSM66s0xEhogx0q30flfxL4WUk8= github.com/cucumber/messages/go/v21 v21.0.1 h1:wzA0LxwjlWQYZd32VTlAVDTkW6inOFmSM+RuOwHZiMI= github.com/cucumber/messages/go/v21 v21.0.1/go.mod h1:zheH/2HS9JLVFukdrsPWoPdmUtmYQAQPLk7w5vWsk5s= github.com/cucumber/messages/go/v22 v22.0.0/go.mod h1:aZipXTKc0JnjCsXrJnuZpWhtay93k7Rn3Dee7iyPJjs= @@ -12,35 +12,40 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gofrs/uuid v4.3.1+incompatible h1:0/KbAdpx3UXAx1kEOWHJeOkpbgRFGHVgv+CFIY7dBJI= github.com/gofrs/uuid v4.3.1+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= +github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-immutable-radix v1.3.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-memdb v1.3.4 h1:XSL3NR682X/cVk2IeV0d70N4DZ9ljI885xAEU8IoK3c= github.com/hashicorp/go-memdb v1.3.4/go.mod h1:uBTr1oQbtuMgd1SSGoR8YV27eT3sBHbYiNm53bMpgSg= +github.com/hashicorp/go-memdb v1.3.5 h1:b3taDMxCBCBVgyRrS1AZVHO14ubMYZB++QpNhBg+Nyo= +github.com/hashicorp/go-memdb v1.3.5/go.mod h1:8IVKKBkVe+fxFgdFOYxzQQNjz+sWCyHCdIC/+5+Vy1Y= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -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/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= +github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= 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/nicksnyder/go-i18n/v2 v2.5.0 h1:3wH1gpaekcgGuwzWdSu7JwJhH9Tk87k1ezt0i1p2/Is= -github.com/nicksnyder/go-i18n/v2 v2.5.0/go.mod h1:DrhgsSDZxoAfvVrBVLXoxZn/pN5TXqaDbq7ju94viiQ= +github.com/nicksnyder/go-i18n/v2 v2.6.0 h1:C/m2NNWNiTB6SK4Ao8df5EWm3JETSTIGNXBpMJTxzxQ= +github.com/nicksnyder/go-i18n/v2 v2.6.0/go.mod h1:88sRqr0C6OPyJn0/KRNaEz1uWorjxIKP7rUUcvycecE= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -48,10 +53,10 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 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= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/gremlin-python/src/main/python/gremlin_python/process/traversal.py b/gremlin-python/src/main/python/gremlin_python/process/traversal.py index ba40b8d992..a90678098e 100644 --- a/gremlin-python/src/main/python/gremlin_python/process/traversal.py +++ b/gremlin-python/src/main/python/gremlin_python/process/traversal.py @@ -522,7 +522,7 @@ class TextP(P): def startingWith(*args): warnings.warn( "gremlin_python.process.TextP.startingWith will be replaced by " - "gremlin_python.process.TextP.startingWith.", + "gremlin_python.process.TextP.starting_with.", DeprecationWarning) return TextP("startingWith", *args)
