Element data in VertexProperty and Property are now minimilistic and only what is necessay to attach the Property/VertexProperty. Added more test cases accordingly.
Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/77257188 Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/77257188 Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/77257188 Branch: refs/heads/TINKERPOP-1520 Commit: 7725718826a61bffb5a5b50dba9adc8d9971716e Parents: 996cb23 Author: Marko A. Rodriguez <okramma...@gmail.com> Authored: Thu Nov 17 12:16:58 2016 -0700 Committer: Marko A. Rodriguez <okramma...@gmail.com> Committed: Tue Nov 22 11:20:01 2016 -0700 ---------------------------------------------------------------------- CHANGELOG.asciidoc | 4 +- .../io/graphson/GraphSONSerializersV2d0.java | 82 ++++++++++++-------- .../gremlin_python/structure/io/graphson.py | 29 +++++-- .../jython/tests/structure/io/test_graphson.py | 69 +++++++++++----- 4 files changed, 124 insertions(+), 60 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/77257188/CHANGELOG.asciidoc ---------------------------------------------------------------------- diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index 1280f79..27ccabc 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -56,11 +56,11 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima TinkerPop 3.2.4 (Release Date: NOT OFFICIALLY RELEASED YET) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -* Added support for `VertexProperty.element()` and `Property.element()` in GraphSON to enable attachment. +* Added "attachment requisite" `VertexProperty.element()` and `Property.element()` data in GraphSON serialization. * Added `Vertex`, `Edge`, `VertexProperty`, and `Property` serializers to Gremlin-Python and exposed tests that use graph object arguments. * `Bytecode.getSourceInstructions()` and `Bytecode.getStepInstructions()` now returns `List<Instruction>` instead of `Iterable<Instruction>`. * Added various `TraversalStrategy` registrations with `GryoMapper`. -* Fixed a naming mistake in Gremlin-Python: `IdentityRemoveStrategy` is now called `IdentityRemovalStrategy`. +* Fixed a naming mistake in Gremlin-Python: `IdentityRemoveStrategy` is now called `IdentityRemovalStrategy`. (*breaking*) * Added `TranslationStrategy` test infrastructure that verifies `Bytecode` generated from a translation is equal to the original `Bytecode`. * Converted Spark process suite tests to "integration" tests. * Fixed a bug in `InlineFilterStrategy` having to do with folding `HasContainers` into `VertexStep`. http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/77257188/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializersV2d0.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializersV2d0.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializersV2d0.java index 11d77a4..ad1fd0e 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializersV2d0.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializersV2d0.java @@ -35,7 +35,6 @@ import org.apache.tinkerpop.gremlin.structure.Vertex; import org.apache.tinkerpop.gremlin.structure.VertexProperty; import org.apache.tinkerpop.gremlin.structure.util.Comparators; import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedEdge; -import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedFactory; import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedProperty; import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex; import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertexProperty; @@ -179,8 +178,28 @@ class GraphSONSerializersV2d0 { jsonGenerator.writeStartObject(); jsonGenerator.writeStringField(GraphSONTokens.KEY, property.key()); jsonGenerator.writeObjectField(GraphSONTokens.VALUE, property.value()); - if (null != property.element()) - jsonGenerator.writeObjectField(GraphSONTokens.ELEMENT, DetachedFactory.detach(property.element(), false)); + if (property.element() instanceof VertexProperty) { + VertexProperty vertexProperty = (VertexProperty) property.element(); + jsonGenerator.writeObjectFieldStart(GraphSONTokens.ELEMENT); + jsonGenerator.writeStringField(GraphSONTokens.VALUETYPE, "g:VertexProperty"); + jsonGenerator.writeObjectFieldStart(GraphSONTokens.VALUEPROP); + jsonGenerator.writeObjectField(GraphSONTokens.ID, vertexProperty.id()); + jsonGenerator.writeStringField(GraphSONTokens.LABEL, vertexProperty.label()); + jsonGenerator.writeObjectField(GraphSONTokens.VERTEX, vertexProperty.element().id()); + jsonGenerator.writeEndObject(); + jsonGenerator.writeEndObject(); + } else if (property.element() instanceof Edge) { + Edge edge = (Edge) property.element(); + jsonGenerator.writeObjectFieldStart(GraphSONTokens.ELEMENT); + jsonGenerator.writeStringField(GraphSONTokens.VALUETYPE, "g:Edge"); + jsonGenerator.writeObjectFieldStart(GraphSONTokens.VALUEPROP); + jsonGenerator.writeObjectField(GraphSONTokens.ID, edge.id()); + jsonGenerator.writeStringField(GraphSONTokens.LABEL, edge.label()); + jsonGenerator.writeObjectField(GraphSONTokens.OUT, edge.outVertex().id()); + jsonGenerator.writeObjectField(GraphSONTokens.IN, edge.inVertex().id()); + jsonGenerator.writeEndObject(); + jsonGenerator.writeEndObject(); + } jsonGenerator.writeEndObject(); } } @@ -204,8 +223,8 @@ class GraphSONSerializersV2d0 { jsonGenerator.writeObjectField(GraphSONTokens.ID, vertexProperty.id()); jsonGenerator.writeObjectField(GraphSONTokens.VALUE, vertexProperty.value()); if (null != vertexProperty.element()) - jsonGenerator.writeObjectField(GraphSONTokens.VERTEX, DetachedFactory.detach(vertexProperty.element(), false)); - if (includeLabel) + jsonGenerator.writeObjectField(GraphSONTokens.VERTEX, vertexProperty.element().id()); + if (this.includeLabel) jsonGenerator.writeStringField(GraphSONTokens.LABEL, vertexProperty.label()); tryWriteMetaProperties(vertexProperty, jsonGenerator, normalize); @@ -434,7 +453,7 @@ class GraphSONSerializersV2d0 { public Vertex createObject(final Map<String, Object> vertexData) { return new DetachedVertex( vertexData.get(GraphSONTokens.ID), - vertexData.getOrDefault(GraphSONTokens.LABEL, Vertex.DEFAULT_LABEL).toString(), + (String) vertexData.getOrDefault(GraphSONTokens.LABEL, Vertex.DEFAULT_LABEL), (Map<String, Object>) vertexData.getOrDefault(GraphSONTokens.PROPERTIES, Collections.emptyMap()) ); } @@ -450,10 +469,10 @@ class GraphSONSerializersV2d0 { public Edge createObject(final Map<String, Object> edgeData) { return new DetachedEdge( edgeData.get(GraphSONTokens.ID), - edgeData.getOrDefault(GraphSONTokens.LABEL, Edge.DEFAULT_LABEL).toString(), - (Map) edgeData.getOrDefault(GraphSONTokens.PROPERTIES, Collections.emptyMap()), - Pair.with(edgeData.get(GraphSONTokens.OUT), edgeData.getOrDefault(GraphSONTokens.OUT_LABEL, Vertex.DEFAULT_LABEL).toString()), - Pair.with(edgeData.get(GraphSONTokens.IN), edgeData.getOrDefault(GraphSONTokens.IN_LABEL, Vertex.DEFAULT_LABEL).toString()) + (String) edgeData.getOrDefault(GraphSONTokens.LABEL, Edge.DEFAULT_LABEL), + (Map<String, Object>) edgeData.getOrDefault(GraphSONTokens.PROPERTIES, Collections.emptyMap()), + Pair.with(edgeData.get(GraphSONTokens.OUT), (String) edgeData.getOrDefault(GraphSONTokens.OUT_LABEL, Vertex.DEFAULT_LABEL)), + Pair.with(edgeData.get(GraphSONTokens.IN), (String) edgeData.getOrDefault(GraphSONTokens.IN_LABEL, Vertex.DEFAULT_LABEL)) ); } } @@ -472,19 +491,17 @@ class GraphSONSerializersV2d0 { } private Element getElement(final Object element) { - if (element instanceof Element) - return (Element) element; - else if (element instanceof Map) { - final Map<String, Object> map = (Map<String, Object>) element; - if (map.containsKey(GraphSONTokens.IN_LABEL)) - return new EdgeJacksonDeserializer().createObject(map); - else if (map.containsKey(GraphSONTokens.VALUE)) - return new VertexPropertyJacksonDeserializer().createObject(map); - else - return new VertexJacksonDeserializer().createObject(map); - } else - throw new IllegalArgumentException("Unknown element structure: " + element); - + if (element instanceof Edge) + return (Edge) element; + if (element instanceof Map) { + final String type = (String) ((Map<String, Object>) element).get(GraphSONTokens.VALUETYPE); + final Map<String, Object> elementMap = (Map<String, Object>) ((Map) element).get(GraphSONTokens.VALUEPROP); + if ("g:VertexProperty".equals(type)) + return new VertexPropertyJacksonDeserializer().createObject(elementMap); + else if ("g:Edge".equals(type)) + return new EdgeJacksonDeserializer().createObject(elementMap); + } + throw new IllegalArgumentException("Unknown element structure: " + element); } } @@ -497,17 +514,18 @@ class GraphSONSerializersV2d0 { @Override public VertexProperty createObject(final Map<String, Object> propData) { return propData.containsKey(GraphSONTokens.VERTEX) ? - new DetachedVertexProperty(propData.get(GraphSONTokens.ID), (String) propData.get(GraphSONTokens.LABEL), propData.get(GraphSONTokens.VALUE), (Map) propData.getOrDefault(GraphSONTokens.PROPERTIES, Collections.emptyMap()), getVertex(propData.get(GraphSONTokens.VERTEX))) : - new DetachedVertexProperty(propData.get(GraphSONTokens.ID), (String) propData.get(GraphSONTokens.LABEL), propData.get(GraphSONTokens.VALUE), (Map) propData.getOrDefault(GraphSONTokens.PROPERTIES, Collections.emptyMap())); + new DetachedVertexProperty<>( + propData.get(GraphSONTokens.ID), + (String) propData.get(GraphSONTokens.LABEL), + propData.get(GraphSONTokens.VALUE), (Map<String, Object>) propData.getOrDefault(GraphSONTokens.PROPERTIES, Collections.emptyMap()), + new DetachedVertex(propData.get(GraphSONTokens.VERTEX), Vertex.DEFAULT_LABEL, Collections.emptyMap())) : + new DetachedVertexProperty<>( + propData.get(GraphSONTokens.ID), + (String) propData.get(GraphSONTokens.LABEL), + propData.get(GraphSONTokens.VALUE), + (Map<String, Object>) propData.getOrDefault(GraphSONTokens.PROPERTIES, Collections.emptyMap())); } - - private Vertex getVertex(final Object vertex) { - if (vertex instanceof Vertex) - return (Vertex) vertex; - else - return new VertexJacksonDeserializer().createObject((Map<String, Object>) vertex); - } } static class PathJacksonDeserializer extends AbstractObjectDeserializer<Path> { http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/77257188/gremlin-python/src/main/jython/gremlin_python/structure/io/graphson.py ---------------------------------------------------------------------- diff --git a/gremlin-python/src/main/jython/gremlin_python/structure/io/graphson.py b/gremlin-python/src/main/jython/gremlin_python/structure/io/graphson.py index 85dc726..663ff5d 100644 --- a/gremlin-python/src/main/jython/gremlin_python/structure/io/graphson.py +++ b/gremlin-python/src/main/jython/gremlin_python/structure/io/graphson.py @@ -183,9 +183,11 @@ class EdgeSerializer(_GraphSONTypeIO): @classmethod def dictify(cls, edge, writer): return GraphSONUtil.typedValue("Edge", {"id": writer.toDict(edge.id), - "outV": writer.toDict(edge.outV), + "outV": writer.toDict(edge.outV.id), + "outVLabel": writer.toDict(edge.outV.label), "label": writer.toDict(edge.label), - "inV": writer.toDict(edge.inV)}) + "inV": writer.toDict(edge.inV.id), + "inVLabel": writer.toDict(edge.inV.label)}) class VertexPropertySerializer(_GraphSONTypeIO): @@ -197,7 +199,7 @@ class VertexPropertySerializer(_GraphSONTypeIO): return GraphSONUtil.typedValue("VertexProperty", {"id": writer.toDict(vertex_property.id), "label": writer.toDict(vertex_property.label), "value": writer.toDict(vertex_property.value), - "vertex": writer.toDict(vertex_property.vertex)}) + "vertex": writer.toDict(vertex_property.vertex.id)}) class PropertySerializer(_GraphSONTypeIO): @@ -206,9 +208,18 @@ class PropertySerializer(_GraphSONTypeIO): @classmethod def dictify(cls, property, writer): + elementDict = writer.toDict(property.element) + if elementDict is not None: + valueDict = elementDict["@value"] + if "outVLabel" in valueDict: + del valueDict["outVLabel"] + if "inVLabel" in valueDict: + del valueDict["inVLabel"] + if "properties" in valueDict: + del valueDict["properties"] return GraphSONUtil.typedValue("Property", {"key": writer.toDict(property.key), "value": writer.toDict(property.value), - "element": writer.toDict(property.element)}) + "element": writer.toDict(elementDict)}) class TraversalStrategySerializer(_GraphSONTypeIO): @@ -341,9 +352,9 @@ class EdgeDeserializer(_GraphSONTypeIO): @classmethod def objectify(cls, d, reader): return Edge(reader.toObject(d["id"]), - Vertex(reader.toObject(d["outV"]), ""), + Vertex(reader.toObject(d["outV"]), d.get("outVLabel", "vertex")), d.get("label", "edge"), - Vertex(reader.toObject(d["inV"]), "")) + Vertex(reader.toObject(d["inV"]), d.get("inVLabel", "vertex"))) class VertexPropertyDeserializer(_GraphSONTypeIO): @@ -351,10 +362,11 @@ class VertexPropertyDeserializer(_GraphSONTypeIO): @classmethod def objectify(cls, d, reader): + vertex = Vertex(reader.toObject(d.get("vertex"))) if "vertex" in d else None return VertexProperty(reader.toObject(d["id"]), d["label"], reader.toObject(d["value"]), - reader.toObject(d["vertex"])) + vertex) class PropertyDeserializer(_GraphSONTypeIO): @@ -362,7 +374,8 @@ class PropertyDeserializer(_GraphSONTypeIO): @classmethod def objectify(cls, d, reader): - return Property(d["key"], reader.toObject(d["value"]), reader.toObject(d["element"])) + element = reader.toObject(d["element"]) if "element" in d else None + return Property(d["key"], reader.toObject(d["value"]), element) class PathDeserializer(_GraphSONTypeIO): http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/77257188/gremlin-python/src/main/jython/tests/structure/io/test_graphson.py ---------------------------------------------------------------------- diff --git a/gremlin-python/src/main/jython/tests/structure/io/test_graphson.py b/gremlin-python/src/main/jython/tests/structure/io/test_graphson.py index 5fc797e..1e8c4cd 100644 --- a/gremlin-python/src/main/jython/tests/structure/io/test_graphson.py +++ b/gremlin-python/src/main/jython/tests/structure/io/test_graphson.py @@ -69,13 +69,46 @@ class TestGraphSONReader(TestCase): assert 31.2 == x def test_graph(self): - vertex = self.graphson_reader.readObject( - """{"@type":"g:Vertex", "@value":{"id":{"@type":"g:Int32","@value":1},"label":"person","outE":{"created":[{"id":{"@type":"g:Int32","@value":9},"inV":{"@type":"g:Int32","@value":3},"properties":{"weight":{"@type":"g:Double","@value":0.4}}}],"knows":[{"id":{"@type":"g:Int32","@value":7},"inV":{"@type":"g:Int32","@value":2},"properties":{"weight":{"@type":"g:Double","@value":0.5}}},{"id":{"@type":"g:Int32","@value":8},"inV":{"@type":"g:Int32","@value":4},"properties":{"weight":{"@type":"g:Double","@value":1.0}}}]},"properties":{"name":[{"id":{"@type":"g:Int64","@value":0},"value":"marko"}],"age":[{"id":{"@type":"g:Int64","@value":1},"value":{"@type":"g:Int32","@value":29}}]}}}""") + vertex = self.graphson_reader.readObject(""" + {"@type":"g:Vertex", "@value":{"id":{"@type":"g:Int32","@value":1},"label":"person","outE":{"created":[{"id":{"@type":"g:Int32","@value":9},"inV":{"@type":"g:Int32","@value":3},"properties":{"weight":{"@type":"g:Double","@value":0.4}}}],"knows":[{"id":{"@type":"g:Int32","@value":7},"inV":{"@type":"g:Int32","@value":2},"properties":{"weight":{"@type":"g:Double","@value":0.5}}},{"id":{"@type":"g:Int32","@value":8},"inV":{"@type":"g:Int32","@value":4},"properties":{"weight":{"@type":"g:Double","@value":1.0}}}]},"properties":{"name":[{"id":{"@type":"g:Int64","@value":0},"value":"marko"}],"age":[{"id":{"@type":"g:Int64","@value":1},"value":{"@type":"g:Int32","@value":29}}]}}}""") assert isinstance(vertex, Vertex) assert "person" == vertex.label assert 1 == vertex.id assert isinstance(vertex.id, int) assert vertex == Vertex(1) + ## + vertex = self.graphson_reader.readObject(""" + {"@type":"g:Vertex", "@value":{"id":{"@type":"g:Float","@value":45.23}}}""") + assert isinstance(vertex, Vertex) + assert 45.23 == vertex.id + assert isinstance(vertex.id, FloatType) + assert "vertex" == vertex.label + assert vertex == Vertex(45.23) + ## + vertex_property = self.graphson_reader.readObject(""" + {"@type":"g:VertexProperty", "@value":{"id":"anId","label":"aKey","value":true,"vertex":{"@type":"g:Int32","@value":9}}}""") + assert isinstance(vertex_property, VertexProperty) + assert "anId" == vertex_property.id + assert "aKey" == vertex_property.label + assert vertex_property.value + assert vertex_property.vertex == Vertex(9) + ## + vertex_property = self.graphson_reader.readObject(""" + {"@type":"g:VertexProperty", "@value":{"id":{"@type":"g:Int32","@value":1},"label":"name","value":"marko"}}""") + assert isinstance(vertex_property, VertexProperty) + assert 1 == vertex_property.id + assert "name" == vertex_property.label + assert "marko" == vertex_property.value + assert vertex_property.vertex is None + ## + edge = self.graphson_reader.readObject(""" + {"@type":"g:Edge", "@value":{"id":{"@type":"g:Int64","@value":17},"label":"knows","inV":"x","outV":"y","inVLabel":"xLab"}}""") + # print edge + assert isinstance(edge, Edge) + assert 17 == edge.id + assert "knows" == edge.label + assert edge.inV == Vertex("x", "xLabel") + assert edge.outV == Vertex("y", "vertex") def test_path(self): path = self.graphson_reader.readObject( @@ -156,25 +189,25 @@ class TestGraphSONWriter(TestCase): "@value": {"id": {"@type": "g:Int64", "@value": 12}, "label": "person"}} == json.loads( self.graphson_writer.writeObject(Vertex(12l, "person"))) assert {"@type": "g:Edge", "@value": {"id": {"@type": "g:Int32", "@value": 7}, - "outV": {"@type": "g:Vertex", - "@value": {"id": { - "@type": "g:Int32", - "@value": 0}, "label": "vertex"}}, + "outV": {"@type": "g:Int32", "@value": 0}, + "outVLabel": "person", "label": "knows", - "inV": {"@type": "g:Vertex", "@value": { - "id": {"@type": "g:Int32", "@value": 1}, - "label": "vertex"}}}} == json.loads( - self.graphson_writer.writeObject(Edge(7, Vertex(0), "knows", Vertex(1)))) + "inV": {"@type": "g:Int32", "@value": 1}, + "inVLabel": "dog"}} == json.loads( + self.graphson_writer.writeObject(Edge(7, Vertex(0, "person"), "knows", Vertex(1, "dog")))) assert {"@type": "g:VertexProperty", "@value": {"id": "blah", "label": "keyA", "value": True, - "vertex": {"@type": "g:Vertex", - "@value": {"id": "stephen", - "label": "vertex"}}}} == json.loads( + "vertex": "stephen"}} == json.loads( self.graphson_writer.writeObject(VertexProperty("blah", "keyA", True, Vertex("stephen")))) - assert {"@type": "g:Property", "@value": {"key": "name", "value": "marko", "element": {"@type": "g:Vertex", - "@value": { - "id": "bob", - "label": "guy"}}}} == json.loads( - self.graphson_writer.writeObject(Property("name", "marko", Vertex("bob", "guy")))) + + assert {"@type": "g:Property", + "@value": {"key": "name", "value": "marko", "element": {"@type": "g:VertexProperty", + "@value": { + "vertex": "vertexId", + "value": True, + "id": "anId", + "label": "aKey"}}}} == json.loads( + self.graphson_writer.writeObject( + Property("name", "marko", VertexProperty("anId", "aKey", True, Vertex("vertexId"))))) def test_custom_mapping(self): # extended mapping