Skip to content

Commit e4002a4

Browse files
committed
Added feature test and docs
1 parent 100a66e commit e4002a4

7 files changed

Lines changed: 81 additions & 6 deletions

File tree

CHANGELOG.asciidoc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ under the License.
2222
2323
image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/images/gremlin-zamfir.png[width=185]
2424
25+
[[release-3-7-7]]
26+
=== TinkerPop 3.7.7 (NOT OFFICIALLY RELEASED YET)
27+
28+
* Fixed conjoin has incorrect null handling.
29+
2530
[[release-3-7-6]]
2631
=== TinkerPop 3.7.6 (Release Date: April 1, 2026)
2732

docs/src/upgrade/release-3.7.x.asciidoc

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,42 @@ image::gremlin-zamfir.png[width=185]
2323
2424
*Gremfir Master of the Pan Flute*
2525
26+
== TinkerPop 3.7.7
27+
28+
*Release Date: NOT OFFICIALLY RELEASED YET*
29+
30+
Please see the link:https://github.com/apache/tinkerpop/blob/3.7.7/CHANGELOG.asciidoc#release-3-7-7[changelog] for a
31+
complete list of all the modifications that are part of this release.
32+
33+
=== Upgrading for Users
34+
35+
==== conjoin() Step Null Handling
36+
37+
The `conjoin()` step previously returned `null` when elements in the incoming list are `null`. This behavior has
38+
been changed so that `conjoin()` now returns an empty string (`""`) in that case.
39+
40+
[source,groovy]
41+
----
42+
// 3.7.6
43+
gremlin> g.inject([null]).conjoin("-")
44+
==>null
45+
gremlin> g.inject([null, null]).conjoin("-")
46+
==>null
47+
48+
// 3.7.7
49+
gremlin> g.inject([null]).conjoin("+")
50+
==>
51+
gremlin> g.inject([null, null]).conjoin("+")
52+
==>
53+
----
54+
55+
Code that checks the result of `conjoin()` for lists that include `null` elements should be updated to check for
56+
an empty string instead.
57+
58+
See: link:https://issues.apache.org/jira/browse/TINKERPOP-3225[TINKERPOP-3225]
59+
60+
61+
2662
== TinkerPop 3.7.6
2763
2864
*Release Date: April 1, 2026*
@@ -122,13 +158,13 @@ opens a session, submits one or more `addV()` operations, commits, and closes th
122158
The benchmark varies the following parameters:
123159
124160
* *Concurrent clients* (`threads`): The number of threads issuing transactions simultaneously. A value of 1 means
125-
transactions are executed sequentially by a single client. Higher values simulate multiple application threads or
126-
service instances issuing transactions concurrently against the same server.
161+
transactions are executed sequentially by a single client. Higher values simulate multiple application threads or
162+
service instances issuing transactions concurrently against the same server.
127163
* *Connection pool size* (`pool`): The number of WebSocket connections maintained in the pool when
128-
`reuseConnectionsForSessions` is enabled. When reuse is disabled, each session creates its own dedicated connection
129-
and this parameter does not apply (shown as `n/a`).
164+
`reuseConnectionsForSessions` is enabled. When reuse is disabled, each session creates its own dedicated connection
165+
and this parameter does not apply (shown as `n/a`).
130166
* *Transaction weight* (`weight`): "light" transactions perform a single `addV()` plus commit. "heavy" transactions
131-
perform ten `addV()` operations plus commit, simulating a more substantial unit of work per transaction.
167+
perform ten `addV()` operations plus commit, simulating a more substantial unit of work per transaction.
132168
133169
Tests were conducted both locally (client and server on the same machine) and remotely (client on the US west coast,
134170
server on the US east coast) to isolate the effect of network latency on connection setup overhead. Each scenario
@@ -1001,7 +1037,7 @@ For 3.7:
10011037
[source,json]
10021038
----
10031039
{"id":1,"label":"person","properties":{"name":[{"id":0,"label":"name","value":"marko","key":"name"}],"age":[{"id":1,"label":"age","value":29,"key":"age"}]}}
1004-
----
1040+
----
10051041
10061042
===== Enabling the previous behavior
10071043

gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,8 @@ private static IDictionary<string, List<Func<GraphTraversalSource, IDictionary<s
633633
{"g_V_out_out_path_byXnameX_conjoinXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Out().Out().Path().By("name").Conjoin("")}},
634634
{"g_injectXa_null_bX_conjoinXxyzX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(p["xx1"]).Conjoin("xyz")}},
635635
{"g_injectX3_threeX_conjoinX_X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(p["xx1"]).Conjoin(";")}},
636+
{"g_injectXnull_a_null_bX_fold_conjoinXplusX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(p["xx1"]).Conjoin("+")}},
637+
{"g_injectXnull_nullX_conjoinXplusX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(p["xx1"]).Conjoin("+")}},
636638
{"g_V_connectedComponent_hasXcomponentX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ConnectedComponent().Has("gremlin.connectedComponentVertexProgram.component")}},
637639
{"g_V_dedup_connectedComponent_hasXcomponentX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Dedup().ConnectedComponent().Has("gremlin.connectedComponentVertexProgram.component")}},
638640
{"g_V_hasLabelXsoftwareX_connectedComponent_project_byXnameX_byXcomponentX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("software").ConnectedComponent().Project<object>("name","component").By("name").By("gremlin.connectedComponentVertexProgram.component")}},

gremlin-go/driver/cucumber/gremlin.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,8 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[
604604
"g_V_out_out_path_byXnameX_conjoinXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Out().Out().Path().By("name").Conjoin("")}},
605605
"g_injectXa_null_bX_conjoinXxyzX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(p["xx1"]).Conjoin("xyz")}},
606606
"g_injectX3_threeX_conjoinX_X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(p["xx1"]).Conjoin(";")}},
607+
"g_injectXnull_a_null_bX_fold_conjoinXplusX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(p["xx1"]).Conjoin("+")}},
608+
"g_injectXnull_nullX_conjoinXplusX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(p["xx1"]).Conjoin("+")}},
607609
"g_V_connectedComponent_hasXcomponentX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().ConnectedComponent().Has("gremlin.connectedComponentVertexProgram.component")}},
608610
"g_V_dedup_connectedComponent_hasXcomponentX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Dedup().ConnectedComponent().Has("gremlin.connectedComponentVertexProgram.component")}},
609611
"g_V_hasLabelXsoftwareX_connectedComponent_project_byXnameX_byXcomponentX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("software").ConnectedComponent().Project("name", "component").By("name").By("gremlin.connectedComponentVertexProgram.component")}},

gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

gremlin-python/src/main/python/tests/feature/gremlin.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,8 @@
606606
'g_V_out_out_path_byXnameX_conjoinXX': [(lambda g:g.V().out().out().path().by('name').conjoin(''))],
607607
'g_injectXa_null_bX_conjoinXxyzX': [(lambda g, xx1=None:g.inject(xx1).conjoin('xyz'))],
608608
'g_injectX3_threeX_conjoinX_X': [(lambda g, xx1=None:g.inject(xx1).conjoin(';'))],
609+
'g_injectXnull_a_null_bX_fold_conjoinXplusX': [(lambda g, xx1=None:g.inject(xx1).conjoin('+'))],
610+
'g_injectXnull_nullX_conjoinXplusX': [(lambda g, xx1=None:g.inject(xx1).conjoin('+'))],
609611
'g_V_connectedComponent_hasXcomponentX': [(lambda g:g.V().connected_component().has('gremlin.connectedComponentVertexProgram.component'))],
610612
'g_V_dedup_connectedComponent_hasXcomponentX': [(lambda g:g.V().dedup().connected_component().has('gremlin.connectedComponentVertexProgram.component'))],
611613
'g_V_hasLabelXsoftwareX_connectedComponent_project_byXnameX_byXcomponentX': [(lambda g:g.V().has_label('software').connected_component().project('name','component').by('name').by('gremlin.connectedComponentVertexProgram.component'))],

gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Conjoin.feature

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,3 +153,29 @@ Feature: Step - conjoin()
153153
Then the result should be unordered
154154
| result |
155155
| 3;three |
156+
157+
@GraphComputerVerificationInjectionNotSupported
158+
Scenario: g_injectXnull_a_null_bX_fold_conjoinXplusX
159+
Given the empty graph
160+
And using the parameter xx1 defined as "l[null,a,null,b]"
161+
And the traversal of
162+
"""
163+
g.inject(xx1).conjoin("+")
164+
"""
165+
When iterated to list
166+
Then the result should be unordered
167+
| result |
168+
| str[a+b] |
169+
170+
@GraphComputerVerificationInjectionNotSupported
171+
Scenario: g_injectXnull_nullX_conjoinXplusX
172+
Given the empty graph
173+
And using the parameter xx1 defined as "l[null,null]"
174+
And the traversal of
175+
"""
176+
g.inject(xx1).conjoin("+")
177+
"""
178+
When iterated to list
179+
Then the result should be unordered
180+
| result |
181+
| str[] |

0 commit comments

Comments
 (0)