This is an automated email from the ASF dual-hosted git repository.
xiazcy pushed a commit to branch 3.8-dev
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
The following commit(s) were added to refs/heads/3.8-dev by this push:
new 074d634ac0 [TINKERPOP-3186] - Align Element.properties type for dotnet
(#3257)
074d634ac0 is described below
commit 074d634ac01a01bfe5b3558b573ba4695030c1bf
Author: Yang Xia <[email protected]>
AuthorDate: Thu Oct 30 15:20:33 2025 -0700
[TINKERPOP-3186] - Align Element.properties type for dotnet (#3257)
Normalized Element.properties in .NET to return empty arrays when null
---
CHANGELOG.asciidoc | 1 +
docs/src/upgrade/release-3.8.x.asciidoc | 13 ++++++-----
.../src/Gremlin.Net/Structure/Element.cs | 4 ++--
.../Structure/IO/GraphSON/EdgeDeserializer.cs | 3 ++-
.../Structure/IO/GraphSON/VertexDeserializer.cs | 3 ++-
.../IO/GraphSON/VertexPropertyDeserializer.cs | 2 +-
.../DriverRemoteConnection/GraphTraversalTests.cs | 26 +++++++++-------------
.../Structure/IO/GraphSON/GraphSONReaderTests.cs | 5 +++++
8 files changed, 31 insertions(+), 26 deletions(-)
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index c01b80c945..171b7f760f 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -33,6 +33,7 @@ This release also includes changes from <<release-3-7-XXX,
3.7.XXX>>.
* Removed Vertex/ReferenceVertex from grammar. Use vertex id in traversals now
instead.
* Removed `has(key, traversal)` and `has(T, traversal)` options for `has()`
step.
* Fixed bug where `InlineFilterStrategy` could add an empty `has()`.
+* Normalized dotnet `Element.properties` to lists.
* Normalized python and javascript `Element.properties` to lists.
* Renamed `none()` step to `discard()`.
* Repurposed `none()` step as a list filtering step with the signature
`none(P)`.
diff --git a/docs/src/upgrade/release-3.8.x.asciidoc
b/docs/src/upgrade/release-3.8.x.asciidoc
index 9f254b581d..75ce68d0a1 100644
--- a/docs/src/upgrade/release-3.8.x.asciidoc
+++ b/docs/src/upgrade/release-3.8.x.asciidoc
@@ -625,18 +625,19 @@ See:
link:https://issues.apache.org/jira/browse/TINKERPOP-1463[TINKERPOP-1463]
==== Serialization Changes
-*Properties on Element Serialization in Python & Javascript*
+*Properties on Element Serialization in GLVs*
Element properties handling has been inconsistent across GLVs.
Previously,`gremlin-python` deserialized empty properties
-as None or array depending on the serializer, while `gremlin-javascript`
returned properties as objects or arrays, with
-empty properties as empty lists or undefined depending on the serializer.
+as `None` or array depending on the serializer, while `gremlin-javascript`,
and `gremlin-dotnet` returned properties as
+objects or arrays, with empty properties as empty lists or undefined depending
on the serializer. (Note that
+`gremlin-go` already returns empty slices for null properties so no changes is
needed.)
This inconsistency is now resolved, aligning to how properties are handled in
Gremlin core and in the Java GLV.
-Both GLVs will deserialize element properties into lists of property objects,
returning empty lists instead of null values
+All GLVs will deserialize element properties into lists of property objects,
returning empty lists instead of null values
for missing properties.
-For python, the most notable difference is in graphSON when "tokens" is turned
on for "materializeProperties". The
-properties returned are no longer `None`, but empty lists. Users should update
their code accordingly.
+For python and dotnet, the most notable difference is in graphSON when
"tokens" is turned on for "materializeProperties". The
+properties returned are no longer `None` or `null`, but empty lists. Users
should update their code accordingly.
For javascript, the change is slightly more extensive, as user should no
longer expect javascript objects to be returned.
All properties are returned as lists of Property or VertexProperty objects.
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/Element.cs
b/gremlin-dotnet/src/Gremlin.Net/Structure/Element.cs
index 32935bd6d6..bb2cdf4164 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/Element.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/Element.cs
@@ -41,7 +41,7 @@ namespace Gremlin.Net.Structure
{
Id = id;
Label = label;
- Properties = properties;
+ Properties = properties ?? Array.Empty<dynamic>();
}
/// <summary>
@@ -57,7 +57,7 @@ namespace Gremlin.Net.Structure
/// <summary>
/// Gets the properties of this <see cref="Element" />.
/// </summary>
- public dynamic[]? Properties { get; }
+ public dynamic[] Properties { get; }
/// <inheritdoc />
public bool Equals(Element? other)
diff --git
a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/EdgeDeserializer.cs
b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/EdgeDeserializer.cs
index 4ab5ecdc2d..91e5feaf33 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/EdgeDeserializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/EdgeDeserializer.cs
@@ -21,6 +21,7 @@
#endregion
+using System;
using System.Linq;
using System.Text.Json;
@@ -45,7 +46,7 @@ namespace Gremlin.Net.Structure.IO.GraphSON
? labelProperty.GetString()!
: "edge";
- dynamic[]? properties = null;
+ dynamic[] properties = Array.Empty<dynamic>();
if (graphsonObject.TryGetProperty("properties", out var
propertiesObject)
&& propertiesObject.ValueKind == JsonValueKind.Object)
{
diff --git
a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/VertexDeserializer.cs
b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/VertexDeserializer.cs
index 2412c9a27b..d0321af667 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/VertexDeserializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/VertexDeserializer.cs
@@ -21,6 +21,7 @@
#endregion
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
@@ -36,7 +37,7 @@ namespace Gremlin.Net.Structure.IO.GraphSON
? labelProperty.GetString()!
: Vertex.DefaultLabel;
- dynamic[]? properties = null;
+ dynamic[] properties = Array.Empty<dynamic>();
if (graphsonObject.TryGetProperty("properties", out var
propertiesObject)
&& propertiesObject.ValueKind == JsonValueKind.Object)
{
diff --git
a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/VertexPropertyDeserializer.cs
b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/VertexPropertyDeserializer.cs
index e8e919bee4..0714bc09de 100644
---
a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/VertexPropertyDeserializer.cs
+++
b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/VertexPropertyDeserializer.cs
@@ -37,7 +37,7 @@ namespace Gremlin.Net.Structure.IO.GraphSON
? new Vertex(reader.ToObject(vertexProperty))
: null;
- Property[]? properties = null;
+ Property[] properties = System.Array.Empty<Property>();
if (graphsonObject.TryGetProperty("properties", out var
propertiesObject)
&& propertiesObject.ValueKind == JsonValueKind.Object)
{
diff --git
a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/GraphTraversalTests.cs
b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/GraphTraversalTests.cs
index 4f1799450e..c939ac900f 100644
---
a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/GraphTraversalTests.cs
+++
b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/GraphTraversalTests.cs
@@ -293,7 +293,7 @@ namespace
Gremlin.Net.IntegrationTest.Process.Traversal.DriverRemoteConnection
}
[Fact]
- public void shouldUseMaterializedPropertiesTokenInV()
+ public void ShouldUseMaterializedPropertiesTokenInV()
{
var connection = _connectionFactory.CreateRemoteConnection();
var g = AnonymousTraversalSource.Traversal().With(connection);
@@ -301,13 +301,12 @@ namespace
Gremlin.Net.IntegrationTest.Process.Traversal.DriverRemoteConnection
foreach (var v in vertices)
{
Assert.NotNull(v);
- // GraphSON will deserialize into null and GraphBinary to []
- Assert.True(v.Properties == null || v.Properties.Length == 0);
+ Assert.Empty(v.Properties);
}
}
[Fact]
- public void shouldUseMaterializedPropertiesTokenInE()
+ public void ShouldUseMaterializedPropertiesTokenInE()
{
var connection = _connectionFactory.CreateRemoteConnection();
var g = AnonymousTraversalSource.Traversal().With(connection);
@@ -315,13 +314,12 @@ namespace
Gremlin.Net.IntegrationTest.Process.Traversal.DriverRemoteConnection
foreach (var e in edges)
{
Assert.NotNull(e);
- // GraphSON will deserialize into null and GraphBinary to []
- Assert.True(e.Properties == null || e.Properties.Length == 0);
+ Assert.Empty(e.Properties);
}
}
[Fact]
- public void shouldUseMaterializedPropertiesTokenInVP()
+ public void ShouldUseMaterializedPropertiesTokenInVP()
{
var connection = _connectionFactory.CreateRemoteConnection();
var g = AnonymousTraversalSource.Traversal().With(connection);
@@ -329,13 +327,12 @@ namespace
Gremlin.Net.IntegrationTest.Process.Traversal.DriverRemoteConnection
foreach (var vp in vps)
{
Assert.NotNull(vp);
- // GraphSON will deserialize into null and GraphBinary to []
- Assert.True(vp.Properties == null || vp.Properties.Length ==
0);
+ Assert.Empty(vp.Properties);
}
}
[Fact]
- public void shouldUseMaterializedPropertiesTokenInPath()
+ public void ShouldUseMaterializedPropertiesTokenInPath()
{
var connection = _connectionFactory.CreateRemoteConnection();
var g = AnonymousTraversalSource.Traversal().With(connection);
@@ -352,14 +349,13 @@ namespace
Gremlin.Net.IntegrationTest.Process.Traversal.DriverRemoteConnection
Assert.NotNull(b);
Assert.NotNull(c);
- // GraphSON will deserialize into null and GraphBinary to []
- Assert.True(a.Properties == null || a.Properties.Length == 0);
- Assert.True(b.Properties == null || b.Properties.Length == 0);
- Assert.True(c.Properties == null || c.Properties.Length == 0);
+ Assert.Empty(a.Properties);
+ Assert.Empty(b.Properties);
+ Assert.Empty(c.Properties);
}
[Fact]
- public void shouldMaterializePropertiesAllInPath()
+ public void ShouldMaterializePropertiesAllInPath()
{
var connection = _connectionFactory.CreateRemoteConnection();
var g = AnonymousTraversalSource.Traversal().With(connection);
diff --git
a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONReaderTests.cs
b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONReaderTests.cs
index e903c19b82..a7d314d5be 100644
---
a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONReaderTests.cs
+++
b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONReaderTests.cs
@@ -395,6 +395,7 @@ namespace Gremlin.Net.UnitTest.Structure.IO.GraphSON
Assert.Equal(new Vertex(5L), readPath[0]);
Assert.Equal(new Vertex(5L), readPath["z"]);
Assert.Single(readPath);
+ Assert.Empty(readPath[0]!.Properties);
}
[Theory, MemberData(nameof(Versions))]
@@ -459,6 +460,7 @@ namespace Gremlin.Net.UnitTest.Structure.IO.GraphSON
Assert.Equal("aKey", readVertexProperty.Label);
Assert.True(readVertexProperty.Value);
Assert.NotNull(readVertexProperty.Vertex);
+ Assert.Empty(readVertexProperty.Properties);
}
[Theory, MemberData(nameof(Versions))]
@@ -475,6 +477,7 @@ namespace Gremlin.Net.UnitTest.Structure.IO.GraphSON
Assert.Equal("name", readVertexProperty.Label);
Assert.Equal("marko", readVertexProperty.Value);
Assert.Null(readVertexProperty.Vertex);
+ Assert.Empty(readVertexProperty.Properties);
}
[Theory, MemberData(nameof(Versions))]
@@ -488,6 +491,7 @@ namespace Gremlin.Net.UnitTest.Structure.IO.GraphSON
var deserializedValue = reader.ToObject(jsonElement);
Assert.Equal(new Vertex(45.23f), deserializedValue);
+ Assert.Empty(deserializedValue!.Properties);
}
[Theory, MemberData(nameof(Versions))]
@@ -501,6 +505,7 @@ namespace Gremlin.Net.UnitTest.Structure.IO.GraphSON
Vertex deserializedValue = reader.ToObject(jsonElement)!;
Assert.Equal("person", deserializedValue.Label);
+ Assert.Empty(deserializedValue.Properties);
}
[Theory, MemberData(nameof(Versions))]