This is an automated email from the ASF dual-hosted git repository.

xiazcy pushed a commit to branch TINKERPOP-3186
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit 176e8a2764b4289b1db21e663c5db449921167cb
Author: xiazcy <[email protected]>
AuthorDate: Wed Oct 15 18:12:03 2025 -0700

    normalized javascript Element.properties to empty list
---
 .../gremlin-javascript/lib/structure/graph.js      | 27 +++-----
 .../lib/structure/io/type-serializers.js           | 26 +++++++-
 .../test/integration/client-tests.js               | 51 +++++----------
 .../test/integration/traversal-test.js             | 15 ++---
 .../test/unit/graphbinary/AnySerializer-test.js    |  2 +-
 .../gremlin-javascript/test/unit/graphson-test.js  | 74 +++++++++++++++-------
 .../test/unit/structure-types-test.js              | 36 +++++++++++
 .../tests/structure/io/test_graphbinaryV1.py       |  2 +
 8 files changed, 143 insertions(+), 90 deletions(-)

diff --git 
a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/graph.js
 
b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/graph.js
index 02459bc9be..60ac272e89 100644
--- 
a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/graph.js
+++ 
b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/graph.js
@@ -46,9 +46,10 @@ class Graph {
 }
 
 class Element {
-  constructor(id, label) {
+  constructor(id, label, properties = undefined) {
     this.id = id;
     this.label = label;
+    this.properties = properties != null ? properties : [];
   }
 
   /**
@@ -62,9 +63,8 @@ class Element {
 }
 
 class Vertex extends Element {
-  constructor(id, label, properties) {
-    super(id, label);
-    this.properties = properties;
+  constructor(id, label, properties = undefined) {
+    super(id, label, properties);
   }
 
   toString() {
@@ -73,20 +73,10 @@ class Vertex extends Element {
 }
 
 class Edge extends Element {
-  constructor(id, outV, label, inV, properties) {
-    super(id, label);
+  constructor(id, outV, label, inV, properties = undefined) {
+    super(id, label, properties);
     this.outV = outV;
     this.inV = inV;
-    this.properties = {};
-    if (properties) {
-      if (Array.isArray(properties)) {
-        // Handle array of Property objects
-        properties.forEach((prop) => (this.properties[prop.key] = prop.value));
-      } else {
-        // Handle object format as before
-        Object.keys(properties).forEach((k) => (this.properties[k] = 
properties[k].value));
-      }
-    }
   }
 
   toString() {
@@ -98,11 +88,10 @@ class Edge extends Element {
 }
 
 class VertexProperty extends Element {
-  constructor(id, label, value, properties) {
-    super(id, label);
+  constructor(id, label, value, properties = undefined) {
+    super(id, label, properties);
     this.value = value;
     this.key = this.label;
-    this.properties = properties;
   }
 
   toString() {
diff --git 
a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/type-serializers.js
 
b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/type-serializers.js
index 22166a6e70..9157062a0f 100644
--- 
a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/type-serializers.js
+++ 
b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/type-serializers.js
@@ -311,10 +311,30 @@ class TraversalStrategySerializer extends TypeSerializer {
   }
 }
 
+/**
+ * Helper function to deserialize properties into arrays of VertexProperty or 
Property according to graphSONV3.
+ */
+function deserializeProperties(value, reader) {
+  let properties = [];
+  if ('properties' in value) {
+    const props = reader.read(value['properties']);
+    if (props !== null && props !== undefined) {
+      properties = Object.entries(props).flatMap(([key, values]) => {
+        if (Array.isArray(values) && values.length > 0 && values[0] instanceof 
g.VertexProperty) {
+          return values; // Flatten VertexProperty arrays
+        }
+        return values instanceof g.Property ? values : new g.Property(key, 
values); // create Property object when needed
+      });
+    }
+  }
+  return properties;
+}
+
 class VertexSerializer extends TypeSerializer {
   deserialize(obj) {
     const value = obj[valueKey];
-    return new g.Vertex(this.reader.read(value['id']), value['label'], 
this.reader.read(value['properties']));
+    console.log(value);
+    return new g.Vertex(this.reader.read(value['id']), value['label'], 
deserializeProperties(value, this.reader));
   }
 
   /** @param {Vertex} item */
@@ -340,7 +360,7 @@ class VertexPropertySerializer extends TypeSerializer {
       this.reader.read(value['id']),
       value['label'],
       this.reader.read(value['value']),
-      this.reader.read(value['properties']),
+      deserializeProperties(value, this.reader),
     );
   }
 }
@@ -360,7 +380,7 @@ class EdgeSerializer extends TypeSerializer {
       new g.Vertex(this.reader.read(value['outV']), 
this.reader.read(value['outVLabel'])),
       value['label'],
       new g.Vertex(this.reader.read(value['inV']), 
this.reader.read(value['inVLabel'])),
-      this.reader.read(value['properties']),
+      deserializeProperties(value, this.reader),
     );
   }
 
diff --git 
a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/client-tests.js
 
b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/client-tests.js
index a61701d255..406feab12b 100644
--- 
a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/client-tests.js
+++ 
b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/client-tests.js
@@ -119,17 +119,11 @@ describe('Client', function () {
           assert.strictEqual(result.length, 1);
           const vertex = result.first();
           assert.ok(vertex instanceof graphModule.Vertex);
-          // if/then until TINKERPOP-3186
           let age, name
-          if (vertex.properties instanceof Array) {
-            const ageProps = vertex.properties.filter(p => p.key === 'age');
-            const nameProps = vertex.properties.filter(p => p.key === 'name');
-            age = ageProps[0];
-            name = nameProps[0];
-          } else {
-            age = vertex.properties.age[0]
-            name = vertex.properties.name[0]
-          }
+          const ageProps = vertex.properties.filter(p => p.key === 'age');
+          const nameProps = vertex.properties.filter(p => p.key === 'name');
+          age = ageProps[0];
+          name = nameProps[0];
           assert.ok(age);
           assert.ok(name);
           assert.strictEqual(age.value, 29);
@@ -145,7 +139,7 @@ describe('Client', function () {
           const edge = result.first();
           assert.ok(edge instanceof graphModule.Edge);
           assert.strictEqual(edge.label, 'knows');
-          assert.strictEqual(edge.properties.weight, 0.5);
+          assert.strictEqual(edge.properties[0].value, 0.5);
           assert.ok(edge.inV);
           assert.ok(edge.outV);
         });
@@ -161,18 +155,12 @@ describe('Client', function () {
           assert.strictEqual(prop.key, 'location');
           assert.strictEqual(prop.value, 'centreville');
 
-          // Check meta-properties - TINKERPOP-3186
-          if (prop.properties instanceof Object && !(prop.properties 
instanceof Array)) {
-            assert.strictEqual(prop.properties.startTime, 1990);
-            assert.strictEqual(prop.properties.endTime, 2000);
-          } else {
-            const startTime = prop.properties.find(p => p.key === 'startTime');
-            const endTime = prop.properties.find(p => p.key === 'endTime');
-            assert.ok(startTime);
-            assert.ok(endTime);
-            assert.strictEqual(startTime.value, 1990);
-            assert.strictEqual(endTime.value, 2000);
-          }
+          const startTime = prop.properties.find(p => p.key === 'startTime');
+          const endTime = prop.properties.find(p => p.key === 'endTime');
+          assert.ok(startTime);
+          assert.ok(endTime);
+          assert.strictEqual(startTime.value, 1990);
+          assert.strictEqual(endTime.value, 2000);
         });
     });
 
@@ -355,15 +343,10 @@ function assertVertexProperties(vertex) {
 
   const vertexProperty = locations[0];
   assert.strictEqual(vertexProperty.value, 'centreville');
-  if (vertexProperty.properties instanceof Array) {
-    const start = vertexProperty.properties.find(p => p.key === 'startTime');
-    const end = vertexProperty.properties.find(p => p.key === 'endTime');
-    assert.ok(start);
-    assert.ok(end);
-    assert.strictEqual(start.value, 1990);
-    assert.strictEqual(end.value, 2000);
-  } else {
-    assert.strictEqual(vertexProperty.properties.startTime, 1990);
-    assert.strictEqual(vertexProperty.properties.endTime, 2000);
-  }
+  const start = vertexProperty.properties.find(p => p.key === 'startTime');
+  const end = vertexProperty.properties.find(p => p.key === 'endTime');
+  assert.ok(start);
+  assert.ok(end);
+  assert.strictEqual(start.value, 1990);
+  assert.strictEqual(end.value, 2000);
 }
\ No newline at end of file
diff --git 
a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/traversal-test.js
 
b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/traversal-test.js
index 89b4c85232..60cd93bbfa 100644
--- 
a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/traversal-test.js
+++ 
b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/traversal-test.js
@@ -137,7 +137,7 @@ describe('Traversal', function () {
         assert.ok(list);
         assert.strictEqual(list.length, 6);
         list.forEach(v => assert.ok(v instanceof Vertex));
-        list.forEach(v => assert.ok(v.properties === undefined || 
v.properties.length === 0));
+        list.forEach(v => assert.strictEqual(v.properties.length, 0));
       });
     });
     it('should skip edge properties when tokens is set', function () {
@@ -156,7 +156,7 @@ describe('Traversal', function () {
         assert.ok(list);
         assert.strictEqual(list.length, 12);
         list.forEach(vp => assert.ok(vp instanceof VertexProperty));
-        list.forEach(vp => assert.ok(vp.properties === undefined || 
vp.properties.length === 0));
+        list.forEach(vp => assert.strictEqual(vp.properties.length, 0));
       });
     });
     it('should skip path element properties when tokens is set', function () {
@@ -171,9 +171,9 @@ describe('Traversal', function () {
         assert.ok(a instanceof Vertex);
         assert.ok(b instanceof Edge);
         assert.ok(c instanceof Vertex);
-        assert.ok(a.properties === undefined || a.properties.length === 0);
+        assert.strictEqual(a.properties.length, 0);
         assert.strictEqual(Object.keys(b.properties).length, 0);
-        assert.ok(c.properties === undefined || c.properties.length === 0);
+        assert.strictEqual(c.properties.length, 0);
       });
     });
     it('should materialize path element properties when all is set', function 
() {
@@ -207,12 +207,7 @@ describe('Traversal', function () {
         assert.strictEqual(aAgeProps.length, 1);
         assert.strictEqual(aAgeProps[0].value, 29);
         assert.ok(b.properties);
-        let bWeight;
-        if (b.properties instanceof Array) {
-          bWeight = b.properties.filter(p => p.key === 'weight');
-        } else {
-          bWeight = b.properties['weight'];
-        }
+        const bWeight = b.properties[0].value
         assert.ok(bWeight !== undefined);
         assert.strictEqual(bWeight, 0.4);
         assert.ok(c.properties);
diff --git 
a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/graphbinary/AnySerializer-test.js
 
b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/graphbinary/AnySerializer-test.js
index d723c85cd9..deb7f5ccf1 100644
--- 
a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/graphbinary/AnySerializer-test.js
+++ 
b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/graphbinary/AnySerializer-test.js
@@ -267,7 +267,7 @@ describe('GraphBinary.AnySerializer', () => {
           0x00,0x00,0x00,0x05, ...from('Label'),
           0x01,0x00, 0x00,0x00,0x00,0x2A,
           0xFE,0x01,
-          0xFE,0x01,
+          0x09,0x00, 0x00,0x00,0x00,0x00,
         ]
       },
 
diff --git 
a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/graphson-test.js
 
b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/graphson-test.js
index 913102b098..8de0173ea6 100644
--- 
a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/graphson-test.js
+++ 
b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/graphson-test.js
@@ -92,21 +92,23 @@ describe('GraphSONReader', function () {
   });
   it('should parse vertices from GraphSON', function () {
     const obj = {
-      "@type":"g:Vertex", 
"@value":{"id":{"@type":"g:Int32","@value":1},"label":"person",
-        
"properties":{"name":[{"id":{"@type":"g:Int64","@value":0},"value":"marko"}],
-          
"age":[{"id":{"@type":"g:Int64","@value":1},"value":{"@type":"g:Int32","@value":29}}]}}};
+      
"@type":"g:Vertex","@value":{"id":{"@type":"g:Int32","@value":1},"label":"person",
+        
"properties":{"name":[{"@type":"g:VertexProperty","@value":{"id":{"@type":"g:Int64","@value":0},
+              "value":"marko","label":"name"}}],"age":[{
+            
"@type":"g:VertexProperty","@value":{"id":{"@type":"g:Int64","@value":1},
+              "value":{"@type":"g:Int32","@value":29},"label":"age"}}]}}}
     const reader = new GraphSONReader(obj);
     const result = reader.read(obj);
     assert.ok(result instanceof graph.Vertex);
     assert.strictEqual(result.label, 'person');
     assert.strictEqual(typeof result.id, 'number');
     assert.ok(result.properties);
-    assert.ok(result.properties['name']);
-    assert.strictEqual(result.properties['name'].length, 1);
-    assert.strictEqual(result.properties['name'][0].value, 'marko');
-    assert.ok(result.properties['age']);
-    assert.strictEqual(result.properties['age'].length, 1);
-    assert.strictEqual(result.properties['age'][0].value, 29);
+    assert.ok(result.properties[0]);
+    assert.strictEqual(result.properties[0].key, 'name');
+    assert.strictEqual(result.properties[0].value, 'marko');
+    assert.ok(result.properties[1]);
+    assert.strictEqual(result.properties[1].key, 'age');
+    assert.strictEqual(result.properties[1].value, 29);
   });
   it('should parse paths from GraphSON', function () {
     const obj = 
{"@type":"g:Path","@value":{"labels":[["a"],["b","c"],[]],"objects":[
@@ -136,19 +138,19 @@ describe('GraphSONReader', function () {
     assert.strictEqual(a.label, 'person');
     assert.strictEqual(bc.label, 'software');
     assert.ok(a.properties);
-    assert.ok(a.properties['name']);
-    assert.strictEqual(a.properties['name'].length, 1);
-    assert.strictEqual(a.properties['name'][0].value, 'marko');
-    assert.ok(a.properties['age']);
-    assert.strictEqual(a.properties['age'].length, 1);
-    assert.strictEqual(a.properties['age'][0].value, 29);
+    assert.ok(a.properties[0]);
+    assert.strictEqual(a.properties[0].key, 'name');
+    assert.strictEqual(a.properties[0].value, 'marko');
+    assert.ok(a.properties[1]);
+    assert.strictEqual(a.properties[1].key, 'age');
+    assert.strictEqual(a.properties[1].value, 29);
     assert.ok(bc.properties);
-    assert.ok(bc.properties['name']);
-    assert.strictEqual(bc.properties['name'].length, 1);
-    assert.strictEqual(bc.properties['name'][0].value, 'lop');
-    assert.ok(bc.properties['lang']);
-    assert.strictEqual(bc.properties['lang'].length, 1);
-    assert.strictEqual(bc.properties['lang'][0].value, 'java');
+    assert.ok(bc.properties[0]);
+    assert.strictEqual(bc.properties[0].key, 'name');
+    assert.strictEqual(bc.properties[0].value, 'lop');
+    assert.ok(bc.properties[1]);
+    assert.strictEqual(bc.properties[1].key, 'lang');
+    assert.strictEqual(bc.properties[1].value, 'java');
   });
   it('should parse paths from GraphSON3 without properties', function () {
     const obj = {
@@ -203,8 +205,34 @@ describe('GraphSONReader', function () {
     assert.ok(bc instanceof graph.Vertex);
     assert.strictEqual(a.label, 'person');
     assert.strictEqual(bc.label, 'software');
-    assert.ok(a.properties === undefined);
-    assert.ok(bc.properties === undefined);
+    assert.deepStrictEqual(a.properties, []);
+    assert.deepStrictEqual(bc.properties, []);
+  });
+
+  it('should deserialize vertices without properties to empty array', 
function() {
+    const obj = {"@type":"g:Vertex", 
"@value":{"id":{"@type":"g:Int32","@value":2},"label":"person"}};
+    const reader = new GraphSONReader();
+    const vertex = reader.read(obj);
+    assert.strictEqual(vertex.constructor.name, 'Vertex');
+    assert.strictEqual(vertex.label, 'person');
+    assert.strictEqual(vertex.id, 2);
+    assert.deepStrictEqual(vertex.properties, []);
+  });
+
+  it('should deserialize edges without properties to empty array', function() {
+    const obj = {"@type":"g:Edge", 
"@value":{"id":{"@type":"g:Int64","@value":18},"label":"knows","inV":"a","outV":"b","inVLabel":"xLab"}};
+    const reader = new GraphSONReader();
+    const edge = reader.read(obj);
+    assert.strictEqual(edge.constructor.name, 'Edge');
+    assert.deepStrictEqual(edge.properties, []);
+  });
+
+  it('should deserialize vertex properties without meta-properties to empty 
array', function() {
+    const obj = {"@type":"g:VertexProperty", 
"@value":{"id":"anId","label":"aKey","value":true,"vertex":{"@type":"g:Int32","@value":9}}};
+    const reader = new GraphSONReader();
+    const vp = reader.read(obj);
+    assert.strictEqual(vp.constructor.name, 'VertexProperty');
+    assert.deepStrictEqual(vp.properties, []);
   });
 });
 describe('GraphSONWriter', function () {
diff --git 
a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/structure-types-test.js
 
b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/structure-types-test.js
index 29bebfad92..552e891ef1 100644
--- 
a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/structure-types-test.js
+++ 
b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/structure-types-test.js
@@ -32,6 +32,18 @@ describe('Edge', () => {
       assert.strictEqual(element.toString(), `e[123][?-label1->?]`);
     });
   });
+
+  describe('properties', () => {
+    it('should default to empty array when not provided', () => {
+      const edge = new Edge('123', new Vertex(1), 'knows', new Vertex(2));
+      assert.deepStrictEqual(edge.properties, []);
+    });
+
+    it('should default to empty array when null', () => {
+      const edge = new Edge('123', new Vertex(1), 'knows', new Vertex(2), 
null);
+      assert.deepStrictEqual(edge.properties, []);
+    });
+  });
 });
 
 describe('Vertex', () => {
@@ -41,6 +53,18 @@ describe('Vertex', () => {
       assert.strictEqual(element.toString(), `v[-200]`);
     });
   });
+
+  describe('properties', () => {
+    it('should default to empty array when not provided', () => {
+      const vertex = new Vertex(1, 'person');
+      assert.deepStrictEqual(vertex.properties, []);
+    });
+
+    it('should default to empty array when null', () => {
+      const vertex = new Vertex(1, 'person', null);
+      assert.deepStrictEqual(vertex.properties, []);
+    });
+  });
 });
 
 describe('VertexProperty', () => {
@@ -56,6 +80,18 @@ describe('VertexProperty', () => {
       });
     });
   });
+
+  describe('properties', () => {
+    it('should default to empty array when not provided', () => {
+      const vp = new VertexProperty(24, 'name', 'marko');
+      assert.deepStrictEqual(vp.properties, []);
+    });
+
+    it('should default to empty array when null', () => {
+      const vp = new VertexProperty(24, 'name', 'marko', null);
+      assert.deepStrictEqual(vp.properties, []);
+    });
+  });
 });
 
 describe('Property', () => {
diff --git 
a/gremlin-python/src/main/python/tests/structure/io/test_graphbinaryV1.py 
b/gremlin-python/src/main/python/tests/structure/io/test_graphbinaryV1.py
index 102be4997a..75c0d693e4 100644
--- a/gremlin-python/src/main/python/tests/structure/io/test_graphbinaryV1.py
+++ b/gremlin-python/src/main/python/tests/structure/io/test_graphbinaryV1.py
@@ -191,6 +191,8 @@ class TestGraphBinaryWriter(object):
 
     def test_vertexproperty(self):
         x = VertexProperty(123, "name", "stephen", None)
+        print('\n')
+        print(self.graphbinary_writer.write_object(x))
         output = 
self.graphbinary_reader.read_object(self.graphbinary_writer.write_object(x))
         assert x == output
         

Reply via email to