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
