--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT. This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You are allowed to redistribute it and sell it, alone or is a part of
+# another product.
+
+# Uses JSON as a storage medium for a Neo4j subgraph.
+module neo4j::json_store
+
+import neo4j
+private import template
+
+# A Neo4j graph that uses as a storage medium.
+#
+# The graph is stored as a JSON object with the following properties:
+#
+# * `"nodes"`: An array with all nodes. Each node is an object with the
+# following properties:
+# * `"id"`: The ID (`Int`) that uniquely identifies the node in the current
+# graph.
+# * `"labels"`: An array of all applied labels.
+# * `"properties"`: An object mapping each defined property to its value.
+# * `"links"`: An array with all relationships. Each relationship is an object
+# with the following properties:
+# * `"type"`: The type (`String`) of the relationship.
+# * `"properties"`: An object mapping each defined property to its value.
+# * `"from"`: The ID (`Int`) of the source node.
+# * `"to"`: The ID (`Int`) of the destination node.
+#
+# TODO Refine the graph API instead when it will be available.
+class JsonGraph
+ super Jsonable
+
+ # All nodes in the graph.
+ var nodes: SimpleCollection[NeoNode] = new Array[NeoNode]
+
+ # All relationships in the graph.
+ var links: SimpleCollection[NeoEdge] = new Array[NeoEdge]
+
+ # Create an empty graph.
+ init do end
+
+ # Retrieve the graph from the specified JSON value.
+ #
+ # var graph = new JsonGraph
+ # var a = new NeoNode
+ # a.labels.add "Foo"
+ # a["answer"] = 42
+ # a["Ultimate question of"] = new JsonArray.from(["life",
+ # "the Universe", "and Everything."])
+ # graph.nodes.add a
+ # var b = new NeoNode
+ # b.labels.add "Foo"
+ # b.labels.add "Bar"
+ # graph.nodes.add b
+ # graph.links.add new NeoEdge(a, "BAZ", b)
+ # #
+ # graph = new JsonGraph.from_json(graph.to_json)
+ # assert 1 == graph.links.length
+ # for link in graph.links do
+ # assert "BAZ" == link.rel_type
+ # assert a.labels == link.from.labels
+ # for k, v in a.properties do assert v == link.from.properties[k]
+ # assert b.labels == link.to.labels
+ # for k, v in b.properties do assert v == link.to.properties[k]
+ # end
+ # assert 2 == graph.nodes.length
+ init from_json(t: Text) do
+ from_json_object(t.to_jsonable.as(JsonObject))
+ end
+
+ # Retrieve the graph from the specified JSON object.
+ init from_json_object(o: JsonObject) do
+ var node_by_id = new HashMap[Int, NeoNode]
+ var nodes = o["nodes"].as(JsonArray)
+ for json_node in nodes do
+ assert json_node isa JsonObject
+ var node = new NeoNode.from_json_object(json_node)
+ node_by_id[json_node["id"].as(Int)] = node
+ self.nodes.add node
+ end
+ var links = o["links"].as(JsonArray)
+ for json_link in links do
+ assert json_link isa JsonObject
+ var from = node_by_id[json_link["from"].as(Int)]
+ var to = node_by_id[json_link["to"].as(Int)]
+ var rel_type = json_link["type"].as(String)
+ var json_properties = json_link["properties"].as(JsonObject)
+ var link = new NeoEdge(from, rel_type, to)
+ link.properties.recover_with(json_properties)
+ self.links.add link
+ end
+ end
+
+ redef fun to_json do
+ var t = new Template
+ t.add "\{\"nodes\":["
+ var i = 0
+ for n in nodes do
+ if i > 0 then t.add ","
+ t.add n.to_json
+ i += 1
+ end
+ t.add "],\"links\":["
+ i = 0
+ for link in links do
+ if i > 0 then t.add ","
+ t.add link.to_json
+ i += 1
+ end
+ t.add "]\}"
+ return t.write_to_string
+ end
+end
+
+# Make `NeoNode` `Jsonable`.
+redef class NeoNode
+ super Jsonable
+
+ # Retrieve the node from the specified JSON value.
+ #
+ # Note: Here, the `"id"` is optional and ignored.
+ #
+ # SEE: `JsonGraph`
+ #
+ # var node = new NeoNode.from_json("""
+ # {
+ # "labels": ["foo", "Bar"],
+ # "properties": {
+ # "baz": 42
+ # }
+ # }
+ # """)
+ # assert ["foo", "Bar"] == node.labels
+ # assert 42 == node["baz"]
+ init from_json(t: Text) do
+ from_json_object(t.to_jsonable.as(JsonObject))
+ end
+
+ # Retrieve the node from the specified JSON value.
+ #
+ # Note: Here, the `"id"` is optional and ignored.
+ #
+ # SEE: `JsonGraph`
+ init from_json_object(o: JsonObject) do
+ init
+ var labels = o["labels"].as(JsonArray)
+ for lab in labels do self.labels.add(lab.as(String))
+ var json_properties = o["properties"].as(JsonObject)
+ properties.recover_with(json_properties)
+ end
+
+ # Get the JSON representation of `self`.
+ #
+ # SEE: `JsonGraph`
+ redef fun to_json do
+ var t = new Template
+ t.add "\{\"id\":"
+ t.add object_id.to_json
+ t.add ",\"labels\":["
+ var i = 0
+ for lab in labels do
+ if i > 0 then t.add ","
+ t.add lab.to_json
+ i += 1
+ end
+ t.add "],\"properties\":"
+ t.add properties.to_json
+ t.add "}"
+ return t.write_to_string
+ end
+
+ redef fun to_s do return to_json
+end
+
+# Make `NeoEdge` `Jsonable`.
+redef class NeoEdge
+ super Jsonable
+
+ redef fun to_json do
+ var t = new Template
+ t.add "\{\"type\":"
+ t.add rel_type.to_json
+ t.add ",\"properties\":"
+ t.add properties.to_json
+ t.add ",\"from\":"
+ t.add from.object_id.to_json
+ t.add ",\"to\":"
+ t.add to.object_id.to_json
+ t.add "}"
+ return t.write_to_string
+ end
+
+ redef fun to_s do return to_json
+end