neo4j 1.0.0.beta.9 → 1.0.0.beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +5 -1971
- data/lib/neo4j/mapping/class_methods/relationship.rb +2 -2
- data/lib/neo4j/mapping/decl_relationship_dsl.rb +6 -1
- data/lib/neo4j/mapping/has_n.rb +17 -1
- data/lib/neo4j/node_traverser.rb +14 -1
- data/lib/neo4j/rails/model.rb +127 -31
- data/lib/neo4j/rails/tx_methods.rb +11 -0
- data/lib/neo4j/rails/value.rb +44 -1
- data/lib/neo4j/version.rb +1 -1
- data/lib/neo4j.rb +1 -0
- metadata +4 -59
- data/lib/neo4j.old/batch_inserter.rb +0 -144
- data/lib/neo4j.old/config.rb +0 -138
- data/lib/neo4j.old/event_handler.rb +0 -73
- data/lib/neo4j.old/extensions/activemodel.rb +0 -158
- data/lib/neo4j.old/extensions/aggregate/aggregate_enum.rb +0 -40
- data/lib/neo4j.old/extensions/aggregate/ext/node_mixin.rb +0 -69
- data/lib/neo4j.old/extensions/aggregate/node_aggregate.rb +0 -8
- data/lib/neo4j.old/extensions/aggregate/node_aggregate_mixin.rb +0 -331
- data/lib/neo4j.old/extensions/aggregate/node_aggregator.rb +0 -216
- data/lib/neo4j.old/extensions/aggregate/node_group.rb +0 -43
- data/lib/neo4j.old/extensions/aggregate/prop_group.rb +0 -30
- data/lib/neo4j.old/extensions/aggregate/property_enum.rb +0 -24
- data/lib/neo4j.old/extensions/aggregate/props_aggregate.rb +0 -8
- data/lib/neo4j.old/extensions/aggregate/props_aggregate_mixin.rb +0 -31
- data/lib/neo4j.old/extensions/aggregate/props_aggregator.rb +0 -80
- data/lib/neo4j.old/extensions/aggregate.rb +0 -12
- data/lib/neo4j.old/extensions/find_path.rb +0 -117
- data/lib/neo4j.old/extensions/graph_algo/all_simple_paths.rb +0 -133
- data/lib/neo4j.old/extensions/graph_algo/neo4j-graph-algo-0.3.jar +0 -0
- data/lib/neo4j.old/extensions/graph_algo.rb +0 -1
- data/lib/neo4j.old/extensions/reindexer.rb +0 -104
- data/lib/neo4j.old/extensions/rest/rest.rb +0 -336
- data/lib/neo4j.old/extensions/rest/rest_mixin.rb +0 -193
- data/lib/neo4j.old/extensions/rest/server.rb +0 -50
- data/lib/neo4j.old/extensions/rest/stubs.rb +0 -141
- data/lib/neo4j.old/extensions/rest.rb +0 -21
- data/lib/neo4j.old/extensions/rest_master.rb +0 -34
- data/lib/neo4j.old/extensions/rest_slave.rb +0 -31
- data/lib/neo4j.old/extensions/tx_tracker.rb +0 -392
- data/lib/neo4j.old/indexer.rb +0 -187
- data/lib/neo4j.old/jars/geronimo-jta_1.1_spec-1.1.1.jar +0 -0
- data/lib/neo4j.old/jars/neo4j-kernel-1.0.jar +0 -0
- data/lib/neo4j.old/jars.rb +0 -6
- data/lib/neo4j.old/mixins/java_list_mixin.rb +0 -139
- data/lib/neo4j.old/mixins/java_node_mixin.rb +0 -205
- data/lib/neo4j.old/mixins/java_property_mixin.rb +0 -169
- data/lib/neo4j.old/mixins/java_relationship_mixin.rb +0 -60
- data/lib/neo4j.old/mixins/migration_mixin.rb +0 -157
- data/lib/neo4j.old/mixins/node_mixin.rb +0 -249
- data/lib/neo4j.old/mixins/property_class_methods.rb +0 -265
- data/lib/neo4j.old/mixins/rel_class_methods.rb +0 -167
- data/lib/neo4j.old/mixins/relationship_mixin.rb +0 -103
- data/lib/neo4j.old/neo.rb +0 -247
- data/lib/neo4j.old/node.rb +0 -49
- data/lib/neo4j.old/reference_node.rb +0 -15
- data/lib/neo4j.old/relationship.rb +0 -85
- data/lib/neo4j.old/relationships/decl_relationship_dsl.rb +0 -164
- data/lib/neo4j.old/relationships/has_list.rb +0 -101
- data/lib/neo4j.old/relationships/has_n.rb +0 -129
- data/lib/neo4j.old/relationships/node_traverser.rb +0 -138
- data/lib/neo4j.old/relationships/relationship_dsl.rb +0 -149
- data/lib/neo4j.old/relationships/traversal_position.rb +0 -50
- data/lib/neo4j.old/relationships/wrappers.rb +0 -51
- data/lib/neo4j.old/search_result.rb +0 -72
- data/lib/neo4j.old/transaction.rb +0 -254
- data/lib/neo4j.old/version.rb +0 -3
@@ -1,336 +0,0 @@
|
|
1
|
-
module Neo4j
|
2
|
-
|
3
|
-
module Rest #:nodoc: all
|
4
|
-
# contains a list of rest node class resources
|
5
|
-
REST_NODE_CLASSES = {}
|
6
|
-
|
7
|
-
class RestException < StandardError
|
8
|
-
def code;
|
9
|
-
500;
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
class NotAllowed < RestException
|
14
|
-
def code;
|
15
|
-
403;
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
class Conflict < RestException
|
20
|
-
def code;
|
21
|
-
409;
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def self.base_uri
|
26
|
-
host = Sinatra::Application.host
|
27
|
-
port = Sinatra::Application.port
|
28
|
-
"http://#{host}:#{port}"
|
29
|
-
end
|
30
|
-
|
31
|
-
def self.load_class(clazz)
|
32
|
-
clazz.split("::").inject(Kernel) do |container, name|
|
33
|
-
container.const_get(name.to_s)
|
34
|
-
end
|
35
|
-
rescue NameError
|
36
|
-
raise Sinatra::NotFound
|
37
|
-
end
|
38
|
-
|
39
|
-
|
40
|
-
# Extracts query parameters from a URL; e.g. if <code>/resource?foo=bar</code> was requested,
|
41
|
-
# <code>{'foo' => 'bar'}</code> is returned.
|
42
|
-
def self.query_from_params(params)
|
43
|
-
query = nil
|
44
|
-
unless (params.nil?)
|
45
|
-
query = params.clone
|
46
|
-
query.delete('neo_id')
|
47
|
-
query.delete('class')
|
48
|
-
query.delete('prop')
|
49
|
-
query.delete('rel')
|
50
|
-
end
|
51
|
-
query
|
52
|
-
end
|
53
|
-
|
54
|
-
# -------------------------------------------------------------------------
|
55
|
-
# /neo
|
56
|
-
# -------------------------------------------------------------------------
|
57
|
-
|
58
|
-
Sinatra::Application.post("/neo") do
|
59
|
-
body = request.body.read
|
60
|
-
Object.class_eval body
|
61
|
-
200
|
62
|
-
end
|
63
|
-
|
64
|
-
|
65
|
-
Sinatra::Application.get("/neo") do
|
66
|
-
if request.accept.include?("text/html")
|
67
|
-
html = "<html><body><h2>Neo4j.rb v #{Neo4j::VERSION} is alive !</h2><p/><h3>Defined REST classes</h3>"
|
68
|
-
REST_NODE_CLASSES.keys.each {|clazz| html << "Class '" + clazz + "' <br/>"}
|
69
|
-
html << "</body></html>"
|
70
|
-
html
|
71
|
-
else
|
72
|
-
content_type :json
|
73
|
-
# make it look like it was a node - todo maybe it should be a real Neo4j::Node ...
|
74
|
-
properties = {:classes => REST_NODE_CLASSES.keys, :ref_node => Neo4j.ref_node._uri}
|
75
|
-
{:properties => properties}.to_json
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
|
80
|
-
# -------------------------------------------------------------------------
|
81
|
-
# /rels/<id>
|
82
|
-
# -------------------------------------------------------------------------
|
83
|
-
|
84
|
-
Sinatra::Application.get("/rels/:id") do
|
85
|
-
content_type :json
|
86
|
-
begin
|
87
|
-
Neo4j::Transaction.run do
|
88
|
-
rel = Neo4j.load_rel(params[:id].to_i)
|
89
|
-
return 404, "Can't find relationship with id #{params[:id]}" if rel.nil?
|
90
|
-
# include hyperlink to end_node if that has an _uri method
|
91
|
-
end_node_hash = {:uri => rel.end_node._uri}
|
92
|
-
|
93
|
-
# include hyperlink to start_node if that has an _uri method
|
94
|
-
start_node_hash = {:uri => rel.start_node._uri}
|
95
|
-
|
96
|
-
{:properties => rel.props, :start_node => start_node_hash, :end_node => end_node_hash}.to_json
|
97
|
-
end
|
98
|
-
rescue RestException => exception
|
99
|
-
return exception.code, {'error' => $!}.to_json
|
100
|
-
rescue Exception => e
|
101
|
-
return 500, {'error' => $!, 'backtrace' => e.backtrace}.to_json
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
|
106
|
-
# -------------------------------------------------------------------------
|
107
|
-
# /nodes/<classname>
|
108
|
-
# -------------------------------------------------------------------------
|
109
|
-
|
110
|
-
# Allows searching for nodes (provided that they are indexed). Supports the following:
|
111
|
-
# <code>/nodes/classname?search=name:hello~</code>:: Lucene query string
|
112
|
-
# <code>/nodes/classname?name=hello</code>:: Exact match on property
|
113
|
-
# <code>/nodes/classname?sort=name,desc</code>:: Specify sorting order
|
114
|
-
# <code>/nodes/classname?limit=100,20</code>:: Specify offset and number of nodes (for pagination)
|
115
|
-
Sinatra::Application.get("/nodes/:class") do
|
116
|
-
content_type :json
|
117
|
-
clazz = Neo4j::Rest.load_class(params[:class])
|
118
|
-
return 404, "Can't find class '#{classname}'" if clazz.nil?
|
119
|
-
|
120
|
-
begin
|
121
|
-
Neo4j::Transaction.run do
|
122
|
-
resources = clazz.find(Neo4j::Rest.query_from_params(params)) # uses overridden find method -- see below
|
123
|
-
resources.map{|res| res.props}.to_json
|
124
|
-
end
|
125
|
-
rescue RestException => exception
|
126
|
-
return exception.code, {'error' => $!}.to_json
|
127
|
-
rescue Exception => e
|
128
|
-
return 500, {'error' => $!, 'backtrace' => e.backtrace}.to_json
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
Sinatra::Application.post("/nodes/:class") do
|
133
|
-
content_type :json
|
134
|
-
|
135
|
-
clazz = Neo4j::Rest.load_class(params[:class])
|
136
|
-
return 404, "Can't find class '#{classname}'" if clazz.nil?
|
137
|
-
|
138
|
-
begin
|
139
|
-
uri = Neo4j::Transaction.run do
|
140
|
-
node = clazz.new
|
141
|
-
data = JSON.parse(request.body.read)
|
142
|
-
properties = data['properties']
|
143
|
-
node.update(properties, Neo4j::Rest.query_from_params(params))
|
144
|
-
node._uri
|
145
|
-
end
|
146
|
-
redirect "#{uri}", 201 # created
|
147
|
-
rescue RestException => exception
|
148
|
-
return exception.code, {'error' => $!}.to_json
|
149
|
-
rescue Exception => e
|
150
|
-
return 500, {'error' => $!, 'backtrace' => e.backtrace}.to_json
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
|
155
|
-
# -------------------------------------------------------------------------
|
156
|
-
# /nodes/<classname>/<id>
|
157
|
-
# -------------------------------------------------------------------------
|
158
|
-
|
159
|
-
Sinatra::Application.get("/nodes/:class/:id") do
|
160
|
-
content_type :json
|
161
|
-
|
162
|
-
begin
|
163
|
-
Neo4j::Transaction.run do
|
164
|
-
node = Neo4j.load_node(params[:id])
|
165
|
-
return 404, "Can't find node with id #{params[:id]}" if node.nil?
|
166
|
-
node.read(Neo4j::Rest.query_from_params(params))
|
167
|
-
relationships = node.rels.outgoing.inject({}) do |hash, v|
|
168
|
-
type = v.relationship_type.to_s
|
169
|
-
hash[type] ||= []
|
170
|
-
hash[type] << "#{Neo4j::Rest.base_uri}/rels/#{v.neo_id}"
|
171
|
-
hash
|
172
|
-
end
|
173
|
-
{:rels => relationships, :properties => node.props}.to_json
|
174
|
-
end
|
175
|
-
rescue RestException => exception
|
176
|
-
return exception.code, {'error' => $!}.to_json
|
177
|
-
rescue Exception => e
|
178
|
-
return 500, {'error' => $!, 'backtrace' => e.backtrace}.to_json
|
179
|
-
end
|
180
|
-
end
|
181
|
-
|
182
|
-
Sinatra::Application.put("/nodes/:class/:id") do
|
183
|
-
content_type :json
|
184
|
-
begin
|
185
|
-
Neo4j::Transaction.run do
|
186
|
-
body = request.body.read
|
187
|
-
data = JSON.parse(body)
|
188
|
-
properties = data['properties'] || {}
|
189
|
-
node = Neo4j.load_node(params[:id])
|
190
|
-
node.update(properties, Neo4j::Rest.query_from_params(params).merge({:strict => true}))
|
191
|
-
node.props.to_json
|
192
|
-
end
|
193
|
-
rescue RestException => exception
|
194
|
-
return exception.code, {'error' => $!}.to_json
|
195
|
-
rescue Exception => e
|
196
|
-
return 500, {'error' => $!, 'backtrace' => e.backtrace}.to_json
|
197
|
-
end
|
198
|
-
end
|
199
|
-
|
200
|
-
Sinatra::Application.delete("/nodes/:class/:id") do
|
201
|
-
content_type :json
|
202
|
-
begin
|
203
|
-
Neo4j::Transaction.run do
|
204
|
-
node = Neo4j.load_node(params[:id])
|
205
|
-
return 404, "Can't find node with id #{params[:id]}" if node.nil?
|
206
|
-
node.del(Neo4j::Rest.query_from_params(params))
|
207
|
-
""
|
208
|
-
end
|
209
|
-
rescue RestException => exception
|
210
|
-
return exception.code, {'error' => $!}.to_json
|
211
|
-
rescue Exception => e
|
212
|
-
return 500, {'error' => $!, 'backtrace' => e.backtrace}.to_json
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
|
-
|
217
|
-
# -------------------------------------------------------------------------
|
218
|
-
# /nodes/<classname>/<id>/<property>
|
219
|
-
# -------------------------------------------------------------------------
|
220
|
-
|
221
|
-
Sinatra::Application.get("/nodes/:class/:id/traverse") do
|
222
|
-
content_type :json
|
223
|
-
begin
|
224
|
-
Neo4j::Transaction.run do
|
225
|
-
node = Neo4j.load_node(params[:id])
|
226
|
-
return 404, {'error' => "Can't find node with id #{params[:id]}"}.to_json if node.nil?
|
227
|
-
|
228
|
-
relationship = params['relationship']
|
229
|
-
depth = case params['depth']
|
230
|
-
when nil then
|
231
|
-
1
|
232
|
-
when 'all' then
|
233
|
-
:all
|
234
|
-
else
|
235
|
-
params['depth'].to_i
|
236
|
-
end
|
237
|
-
return 400, {'error' => "invalid depth parameter - must be an integer"}.to_json if depth == 0
|
238
|
-
|
239
|
-
uris = node.traverse.outgoing(relationship.to_sym).depth(depth).collect{|node| node._uri}
|
240
|
-
{'uri_list' => uris}.to_json
|
241
|
-
end
|
242
|
-
rescue RestException => exception
|
243
|
-
return exception.code, {'error' => $!}.to_json
|
244
|
-
rescue Exception => e
|
245
|
-
return 500, {'error' => $!, 'backtrace' => e.backtrace}.to_json
|
246
|
-
end
|
247
|
-
end
|
248
|
-
|
249
|
-
|
250
|
-
Sinatra::Application.get("/nodes/:class/:id/:prop") do
|
251
|
-
content_type :json
|
252
|
-
|
253
|
-
begin
|
254
|
-
Neo4j::Transaction.run do
|
255
|
-
node = Neo4j.load_node(params[:id])
|
256
|
-
return 404, "Can't find node with id #{params[:id]}" if node.nil?
|
257
|
-
prop = params[:prop].to_sym
|
258
|
-
# check if prop is a relationship defined by has_n or has_one
|
259
|
-
if node.class.decl_relationships.keys.include?(prop)
|
260
|
-
# instead of returning properties return the relationship properties
|
261
|
-
rels = node.send(prop) || []
|
262
|
-
# is it a has_n or has_one relationship ?
|
263
|
-
# if it is a has_n then return an array of properties of that relationship (can be a large json struct)
|
264
|
-
(rels.respond_to?(:props) ? rels.props : rels.map{|rel| rel.props}).to_json
|
265
|
-
else
|
266
|
-
{prop => node[prop]}.to_json
|
267
|
-
end
|
268
|
-
end
|
269
|
-
rescue RestException => exception
|
270
|
-
return exception.code, {'error' => $!}.to_json
|
271
|
-
rescue Exception => e
|
272
|
-
return 500, {'error' => $!, 'backtrace' => e.backtrace}.to_json
|
273
|
-
end
|
274
|
-
end
|
275
|
-
|
276
|
-
|
277
|
-
Sinatra::Application.put("/nodes/:class/:id/:prop") do
|
278
|
-
content_type :json
|
279
|
-
begin
|
280
|
-
Neo4j::Transaction.run do
|
281
|
-
node = Neo4j.load_node(params[:id])
|
282
|
-
property = params[:prop]
|
283
|
-
body = request.body.read
|
284
|
-
data = JSON.parse(body)
|
285
|
-
value = data[property]
|
286
|
-
return 409, "Can't set property #{property} with JSON data '#{body}'" if value.nil?
|
287
|
-
node[property] = value
|
288
|
-
200
|
289
|
-
end
|
290
|
-
rescue RestException => exception
|
291
|
-
return exception.code, {'error' => $!}.to_json
|
292
|
-
rescue Exception => e
|
293
|
-
return 500, {'error' => $!, 'backtrace' => e.backtrace}.to_json
|
294
|
-
end
|
295
|
-
end
|
296
|
-
|
297
|
-
URL_REGEXP = Regexp.new '((http[s]?|ftp):\/)?\/?([^:\/\s]+)((\/\w+)*\/)([\w\-\.]+\/[\w\-\.]+)$' #:nodoc:
|
298
|
-
|
299
|
-
Sinatra::Application.post("/nodes/:class/:id/:rel") do
|
300
|
-
content_type :json
|
301
|
-
begin
|
302
|
-
new_id = Neo4j::Transaction.run do
|
303
|
-
node = Neo4j.load_node(params[:id])
|
304
|
-
return 404, "Can't find node with id #{params[:id]}" if node.nil?
|
305
|
-
rel = params[:rel]
|
306
|
-
|
307
|
-
body = request.body.read
|
308
|
-
data = JSON.parse(body)
|
309
|
-
uri = data['uri']
|
310
|
-
match = URL_REGEXP.match(uri)
|
311
|
-
return 400, "Bad node uri '#{uri}'" if match.nil?
|
312
|
-
to_clazz, to_node_id = match[6].split('/')
|
313
|
-
|
314
|
-
other_node = Neo4j.load_node(to_node_id.to_i)
|
315
|
-
return 400, "Unknown other node with id '#{to_node_id}'" if other_node.nil?
|
316
|
-
|
317
|
-
if to_clazz != other_node.class.to_s
|
318
|
-
return 400, "Wrong type id '#{to_node_id}' expected '#{to_clazz}' got '#{other_node.class.to_s}'"
|
319
|
-
end
|
320
|
-
|
321
|
-
rel_obj = node.add_rel(rel, other_node)
|
322
|
-
|
323
|
-
return 400, "Can't create relationship to #{to_clazz}" if rel_obj.nil?
|
324
|
-
|
325
|
-
rel_obj.neo_id
|
326
|
-
end
|
327
|
-
redirect "/rels/#{new_id}", 201 # created
|
328
|
-
rescue RestException => exception
|
329
|
-
return exception.code, {'error' => $!}.to_json
|
330
|
-
rescue Exception => e
|
331
|
-
return 500, {'error' => $!, 'backtrace' => e.backtrace}.to_json
|
332
|
-
end
|
333
|
-
end
|
334
|
-
end
|
335
|
-
|
336
|
-
end
|
@@ -1,193 +0,0 @@
|
|
1
|
-
module Neo4j
|
2
|
-
|
3
|
-
org.neo4j.kernel.impl.core.NodeProxy.class_eval do
|
4
|
-
# See Neo4j::RestMixin#read
|
5
|
-
def read
|
6
|
-
end
|
7
|
-
end
|
8
|
-
|
9
|
-
# Creates a number of resources for the class using this mixin.
|
10
|
-
#
|
11
|
-
# The following resources are created:
|
12
|
-
#
|
13
|
-
# <b>add new class</b>:: <code>POST /neo</code> post ruby code of a neo4j node class
|
14
|
-
# <b>node classes</b>:: <code>GET /neo</code> - returns hyperlinks to /nodes/classname
|
15
|
-
# <b>search nodes</b>:: <code>GET /nodes/classname?name=p</code>
|
16
|
-
# <b>view all nodes</b>:: <code>GET /nodes/classname</code>
|
17
|
-
# <b>update property</b>:: <code>PUT nodes/classname/id/property_name</code>
|
18
|
-
# <b>view property</b>:: <code>GET nodes/classname/id/property_name</code>
|
19
|
-
# <b>delete node</b>:: <code>DELETE nodes/classname/node_id</code>
|
20
|
-
# <b>update properties</b>:: <code>PUT nodes/classname/node_id</code>
|
21
|
-
# <b>view node</b>:: <code>GET /nodes/classname/id</code>
|
22
|
-
# <b>create node</b>:: <code>POST /nodes/classname</code>
|
23
|
-
# <b>view relationship</b>:: <code>GET /rels/id</code>
|
24
|
-
# <b>list rels</b>:: <code>GET /nodes/classname/id/relationship-type</code>
|
25
|
-
# <b>add relationship</b>:: <code>POST /nodes/classname/id/relationship-type</code>
|
26
|
-
# <b>traversal</b>:: <code>GET nodes/classname/id/traverse?relationship=relationship-type&depth=depth</code>
|
27
|
-
#
|
28
|
-
# Also provides lucene queries
|
29
|
-
# <b>Lucene query string</b>:: <code>/nodes/classname?search=name:hello~</code>
|
30
|
-
# <b>Exact match on property</b>:: <code>/nodes/classname?name=hello</code>
|
31
|
-
# <b>Specify sorting order</b>:: <code>/nodes/classname?sort=name,desc</code>
|
32
|
-
# <b>Pagination (offset,num)</b>:: <code>/nodes/classname?limit=100,20</code>#
|
33
|
-
#
|
34
|
-
# When create a new node by posting to <code>/nodes/classname</code> a 201 will be return with the 'Location' header set to the
|
35
|
-
# URI of the newly created node.
|
36
|
-
#
|
37
|
-
# The JSON representation of a node looks like this
|
38
|
-
#
|
39
|
-
# {"rels" : {"type1":"http://0.0.0.0:4567/rels/0","type2":"http://0.0.0.0:4567/rels/1"},
|
40
|
-
# "properties" : {"_neo_id":1,"_classname":"MyNode"}}
|
41
|
-
#
|
42
|
-
module RestMixin
|
43
|
-
|
44
|
-
def _uri
|
45
|
-
"#{Neo4j::Rest.base_uri}#{_uri_rel}"
|
46
|
-
end
|
47
|
-
|
48
|
-
def _uri_rel
|
49
|
-
clazz = self.class.root_class.to_s #.gsub(/::/, '-') TODO urlencoding
|
50
|
-
"/nodes/#{clazz}/#{neo_id}"
|
51
|
-
end
|
52
|
-
|
53
|
-
# Called by the REST API if this node is accessed directly by ID. Any query parameters
|
54
|
-
# in the request are passed in a hash. For example if <code>GET /nodes/MyClass/1?foo=bar</code>
|
55
|
-
# is requested, <code>MyClass#accessed</code> is called with <code>{'foo' => 'bar'}</code>.
|
56
|
-
# By default this method does nothing, but model classes may override it to achieve specific
|
57
|
-
# behaviour.
|
58
|
-
def read(options={})
|
59
|
-
end
|
60
|
-
|
61
|
-
# Called by the REST API if this node is deleted. Any query parameters in the request are passed
|
62
|
-
# in a hash.
|
63
|
-
def del(options={})
|
64
|
-
super()
|
65
|
-
end
|
66
|
-
|
67
|
-
|
68
|
-
def self.included(c)
|
69
|
-
c.extend ClassMethods
|
70
|
-
uri_rel = c._uri_rel
|
71
|
-
# just for debugging and logging purpose so we know which classes uses this mixin, TODO - probablly not needed
|
72
|
-
Neo4j::Rest::REST_NODE_CLASSES[uri_rel] = c
|
73
|
-
end
|
74
|
-
|
75
|
-
|
76
|
-
module ClassMethods
|
77
|
-
|
78
|
-
# todo remove
|
79
|
-
def _uri_rel # :nodoc:
|
80
|
-
clazz = root_class.to_s #.gsub(/::/, '-') TODO urlencoding
|
81
|
-
"/nodes/#{clazz}"
|
82
|
-
end
|
83
|
-
|
84
|
-
|
85
|
-
# Overrides 'find' so that we can simply pass a query parameters object to it, and
|
86
|
-
# search resources accordingly.
|
87
|
-
def find(query=nil, &block)
|
88
|
-
return super(query, &block) if query.nil? || query.kind_of?(String)
|
89
|
-
|
90
|
-
query = symbolize_keys(query)
|
91
|
-
|
92
|
-
if query[:search]
|
93
|
-
# Use Lucene
|
94
|
-
results = super(query[:search])
|
95
|
-
results = [*apply_lucene_sort(query[:sort], results)] rescue [*super(query[:search])]
|
96
|
-
|
97
|
-
else
|
98
|
-
# Use traverser
|
99
|
-
results = apply_ruby_sort(query[:sort], apply_traverser_conditions(query))
|
100
|
-
end
|
101
|
-
|
102
|
-
apply_limits(query[:limit], results)
|
103
|
-
end
|
104
|
-
|
105
|
-
# :nodoc:
|
106
|
-
def symbolize_keys(hash)
|
107
|
-
# Borrowed from ActiveSupport
|
108
|
-
hash.inject({}) do |options, (key, value)|
|
109
|
-
options[(key.to_sym rescue key) || key] = value
|
110
|
-
options
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
protected
|
115
|
-
|
116
|
-
# Searches for nodes matching conditions by using a traverser.
|
117
|
-
def apply_traverser_conditions(query)
|
118
|
-
query = query.reject{|key, value| [:sort, :limit, :classname].include? key }
|
119
|
-
|
120
|
-
index_node = Neo4j::IndexNode.instance
|
121
|
-
raise 'Index node is nil. Make sure you have called Neo4j.load_reindexer' if index_node.nil?
|
122
|
-
traverser = index_node.traverse.outgoing(root_class)
|
123
|
-
|
124
|
-
traverser.filter do |position|
|
125
|
-
node = position.current_node
|
126
|
-
position.depth == 1 and
|
127
|
-
query.inject(true) do |meets_condition, (key, value)|
|
128
|
-
meets_condition && (node.send(key) == value)
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
# Sorts a list of results according to a string of comma-separated fieldnames (optionally
|
134
|
-
# with 'asc' or 'desc' thrown in). For use in cases where we don't go via Lucene.
|
135
|
-
def apply_ruby_sort(sort_string, results)
|
136
|
-
if sort_string
|
137
|
-
sort_fields = sort_string.to_s.split(/,/)
|
138
|
-
[*results].sort do |x,y|
|
139
|
-
catch(:item_order) do
|
140
|
-
sort_fields.each_index do |index|
|
141
|
-
field = sort_fields[index]
|
142
|
-
unless %w(asc desc).include?(field)
|
143
|
-
item_order = if sort_fields[index + 1] == 'desc'
|
144
|
-
(y.send(field) || '') <=> (x.send(field) || '')
|
145
|
-
else
|
146
|
-
(x.send(field) || '') <=> (y.send(field) || '')
|
147
|
-
end
|
148
|
-
throw :item_order, item_order unless item_order == 0
|
149
|
-
end
|
150
|
-
end
|
151
|
-
0
|
152
|
-
end
|
153
|
-
end
|
154
|
-
else
|
155
|
-
[*results]
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
# Applies Lucene sort instructions to a Neo4j::SearchResult object.
|
160
|
-
def apply_lucene_sort(sort_string, results)
|
161
|
-
return results if sort_string.nil?
|
162
|
-
last_field = nil
|
163
|
-
|
164
|
-
sort_string.to_s.split(/,/).each do |field|
|
165
|
-
if %w(asc desc).include? field
|
166
|
-
results = results.sort_by(field == 'asc' ? Lucene::Asc[last_field] : Lucene::Desc[last_field])
|
167
|
-
last_field = nil
|
168
|
-
else
|
169
|
-
results = results.sort_by(Lucene::Asc[last_field]) unless last_field.nil?
|
170
|
-
last_field = field
|
171
|
-
end
|
172
|
-
end
|
173
|
-
results.sort_by(Lucene::Asc[last_field]) unless last_field.nil?
|
174
|
-
results
|
175
|
-
end
|
176
|
-
|
177
|
-
# Return only the requested subset of results for pagination
|
178
|
-
# (TODO: can this be done more efficiently within Lucene?)
|
179
|
-
def apply_limits(limit_string, results)
|
180
|
-
if limit_string
|
181
|
-
limit = limit_string.to_s.split(/,/).map{|i| i.to_i}
|
182
|
-
limit.unshift(0) if limit.size == 1
|
183
|
-
|
184
|
-
(limit[0]...(limit[0]+limit[1])).map{|n| results[n] }
|
185
|
-
else
|
186
|
-
results
|
187
|
-
end
|
188
|
-
end
|
189
|
-
|
190
|
-
end
|
191
|
-
end
|
192
|
-
|
193
|
-
end
|
@@ -1,50 +0,0 @@
|
|
1
|
-
module Neo4j
|
2
|
-
|
3
|
-
module Rest
|
4
|
-
# todo move inside namepace Rest
|
5
|
-
|
6
|
-
class RestServer #:nodoc:
|
7
|
-
class << self
|
8
|
-
attr_accessor :thread
|
9
|
-
|
10
|
-
def on_neo_started(neo_instance)
|
11
|
-
start
|
12
|
-
end
|
13
|
-
|
14
|
-
def on_neo_stopped(neo_instance)
|
15
|
-
stop
|
16
|
-
end
|
17
|
-
|
18
|
-
|
19
|
-
def start
|
20
|
-
puts "RESTful already started" if @thread
|
21
|
-
return if @thread
|
22
|
-
|
23
|
-
@thread = Thread.new do
|
24
|
-
puts "Start Restful server at port #{Neo4j::Config[:rest_port]}"
|
25
|
-
Sinatra::Application.run! :port => Neo4j::Config[:rest_port]
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
def stop
|
30
|
-
if @thread
|
31
|
-
# TODO must be a nicer way to do this - to shutdown sinatra
|
32
|
-
@thread.kill
|
33
|
-
@thread = nil
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
|
40
|
-
def self.load_rest #:nodoc:
|
41
|
-
Neo4j::Config.defaults[:rest_port] = 9123
|
42
|
-
Neo4j.event_handler.add(RestServer)
|
43
|
-
end
|
44
|
-
|
45
|
-
load_rest
|
46
|
-
|
47
|
-
end
|
48
|
-
|
49
|
-
|
50
|
-
end
|