progression: Add an API for progression tracking.
[nit.git] / lib / neo4j / json_store.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # This file is free software, which comes along with NIT. This software is
4 # distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
5 # without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
6 # PARTICULAR PURPOSE. You can modify it is you want, provided this header
7 # is kept unaltered, and a notification of the changes is added.
8 # You are allowed to redistribute it and sell it, alone or is a part of
9 # another product.
10
11 # Uses JSON as a storage medium for a Neo4j subgraph.
12 module neo4j::json_store
13
14 import neo4j
15 private import template
16
17 # A Neo4j graph that uses as a storage medium.
18 #
19 # The graph is stored as a JSON object with the following properties:
20 #
21 # * `"nodes"`: An array with all nodes. Each node is an object with the
22 # following properties:
23 # * `"id"`: The ID (`Int`) that uniquely identifies the node in the current
24 # graph.
25 # * `"labels"`: An array of all applied labels.
26 # * `"properties"`: An object mapping each defined property to its value.
27 # * `"links"`: An array with all relationships. Each relationship is an object
28 # with the following properties:
29 # * `"type"`: The type (`String`) of the relationship.
30 # * `"properties"`: An object mapping each defined property to its value.
31 # * `"from"`: The ID (`Int`) of the source node.
32 # * `"to"`: The ID (`Int`) of the destination node.
33 #
34 # TODO Refine the graph API instead when it will be available.
35 class JsonGraph
36 super Jsonable
37
38 # All nodes in the graph.
39 var nodes: SimpleCollection[NeoNode] = new Array[NeoNode]
40
41 # All relationships in the graph.
42 var links: SimpleCollection[NeoEdge] = new Array[NeoEdge]
43
44 # Create an empty graph.
45 init do end
46
47 # Retrieve the graph from the specified JSON value.
48 #
49 # var graph = new JsonGraph
50 # var a = new NeoNode
51 # a.labels.add "Foo"
52 # a["answer"] = 42
53 # a["Ultimate question of"] = new JsonArray.from(["life",
54 # "the Universe", "and Everything."])
55 # graph.nodes.add a
56 # var b = new NeoNode
57 # b.labels.add "Foo"
58 # b.labels.add "Bar"
59 # graph.nodes.add b
60 # graph.links.add new NeoEdge(a, "BAZ", b)
61 # #
62 # graph = new JsonGraph.from_json(graph.to_json)
63 # assert 1 == graph.links.length
64 # for link in graph.links do
65 # assert "BAZ" == link.rel_type
66 # assert a.labels == link.from.labels
67 # for k, v in a.properties do assert v == link.from.properties[k]
68 # assert b.labels == link.to.labels
69 # for k, v in b.properties do assert v == link.to.properties[k]
70 # end
71 # assert 2 == graph.nodes.length
72 init from_json(t: Text) do
73 from_json_object(t.parse_json.as(JsonObject))
74 end
75
76 # Retrieve the graph from the specified JSON object.
77 init from_json_object(o: JsonObject) do
78 var node_by_id = new HashMap[Int, NeoNode]
79 var nodes = o["nodes"].as(JsonArray)
80 for json_node in nodes do
81 assert json_node isa JsonObject
82 var node = new NeoNode.from_json_object(json_node)
83 node_by_id[json_node["id"].as(Int)] = node
84 self.nodes.add node
85 end
86 var links = o["links"].as(JsonArray)
87 for json_link in links do
88 assert json_link isa JsonObject
89 var from = node_by_id[json_link["from"].as(Int)]
90 var to = node_by_id[json_link["to"].as(Int)]
91 var rel_type = json_link["type"].as(String)
92 var json_properties = json_link["properties"].as(JsonObject)
93 var link = new NeoEdge(from, rel_type, to)
94 link.properties.recover_with(json_properties)
95 self.links.add link
96 end
97 end
98
99 redef fun to_json do
100 var t = new Template
101 t.add "\{\"nodes\":["
102 var i = 0
103 for n in nodes do
104 if i > 0 then t.add ","
105 t.add n.to_json
106 i += 1
107 end
108 t.add "],\"links\":["
109 i = 0
110 for link in links do
111 if i > 0 then t.add ","
112 t.add link.to_json
113 i += 1
114 end
115 t.add "]\}"
116 return t.write_to_string
117 end
118 end
119
120 # Make `NeoNode` `Jsonable`.
121 redef class NeoNode
122 super Jsonable
123
124 # Retrieve the node from the specified JSON value.
125 #
126 # Note: Here, the `"id"` is optional and ignored.
127 #
128 # SEE: `JsonGraph`
129 #
130 # var node = new NeoNode.from_json("""
131 # {
132 # "labels": ["foo", "Bar"],
133 # "properties": {
134 # "baz": 42
135 # }
136 # }
137 # """)
138 # assert ["foo", "Bar"] == node.labels
139 # assert 42 == node["baz"]
140 init from_json(t: Text) do
141 from_json_object(t.parse_json.as(JsonObject))
142 end
143
144 # Retrieve the node from the specified JSON value.
145 #
146 # Note: Here, the `"id"` is optional and ignored.
147 #
148 # SEE: `JsonGraph`
149 init from_json_object(o: JsonObject) do
150 init
151 var labels = o["labels"].as(JsonArray)
152 for lab in labels do self.labels.add(lab.as(String))
153 var json_properties = o["properties"].as(JsonObject)
154 properties.recover_with(json_properties)
155 end
156
157 # Get the JSON representation of `self`.
158 #
159 # SEE: `JsonGraph`
160 redef fun to_json do
161 var t = new Template
162 t.add "\{\"id\":"
163 t.add object_id.to_json
164 t.add ",\"labels\":["
165 var i = 0
166 for lab in labels do
167 if i > 0 then t.add ","
168 t.add lab.to_json
169 i += 1
170 end
171 t.add "],\"properties\":"
172 t.add properties.to_json
173 t.add "}"
174 return t.write_to_string
175 end
176
177 redef fun to_s do return to_json
178 end
179
180 # Make `NeoEdge` `Jsonable`.
181 redef class NeoEdge
182 super Jsonable
183
184 redef fun to_json do
185 var t = new Template
186 t.add "\{\"type\":"
187 t.add rel_type.to_json
188 t.add ",\"properties\":"
189 t.add properties.to_json
190 t.add ",\"from\":"
191 t.add from.object_id.to_json
192 t.add ",\"to\":"
193 t.add to.object_id.to_json
194 t.add "}"
195 return t.write_to_string
196 end
197
198 redef fun to_s do return to_json
199 end