neography 0.0.31 → 1.0.0

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.
Files changed (85) hide show
  1. data/.gitignore +3 -0
  2. data/.travis.yml +1 -1
  3. data/CONTRIBUTORS +2 -1
  4. data/README.md +247 -0
  5. data/Rakefile +1 -2
  6. data/lib/neography/config.rb +48 -16
  7. data/lib/neography/connection.rb +151 -0
  8. data/lib/neography/errors.rb +42 -0
  9. data/lib/neography/node.rb +17 -14
  10. data/lib/neography/node_relationship.rb +3 -1
  11. data/lib/neography/node_traverser.rb +24 -20
  12. data/lib/neography/property.rb +31 -28
  13. data/lib/neography/property_container.rb +1 -1
  14. data/lib/neography/relationship.rb +16 -19
  15. data/lib/neography/rest/auto_indexes.rb +64 -0
  16. data/lib/neography/rest/batch.rb +262 -0
  17. data/lib/neography/rest/clean.rb +19 -0
  18. data/lib/neography/rest/cypher.rb +24 -0
  19. data/lib/neography/rest/gremlin.rb +24 -0
  20. data/lib/neography/rest/helpers.rb +26 -0
  21. data/lib/neography/rest/indexes.rb +97 -0
  22. data/lib/neography/rest/node_auto_indexes.rb +14 -0
  23. data/lib/neography/rest/node_indexes.rb +35 -0
  24. data/lib/neography/rest/node_paths.rb +57 -0
  25. data/lib/neography/rest/node_properties.rb +11 -0
  26. data/lib/neography/rest/node_relationships.rb +53 -0
  27. data/lib/neography/rest/node_traversal.rb +81 -0
  28. data/lib/neography/rest/nodes.rb +102 -0
  29. data/lib/neography/rest/paths.rb +36 -0
  30. data/lib/neography/rest/properties.rb +56 -0
  31. data/lib/neography/rest/relationship_auto_indexes.rb +14 -0
  32. data/lib/neography/rest/relationship_indexes.rb +35 -0
  33. data/lib/neography/rest/relationship_properties.rb +11 -0
  34. data/lib/neography/rest/relationships.rb +23 -0
  35. data/lib/neography/rest.rb +285 -615
  36. data/lib/neography/tasks.rb +1 -1
  37. data/lib/neography/version.rb +1 -1
  38. data/lib/neography.rb +13 -2
  39. data/neography.gemspec +8 -8
  40. data/spec/integration/authorization_spec.rb +2 -2
  41. data/spec/integration/index_spec.rb +4 -4
  42. data/spec/integration/neography_spec.rb +2 -2
  43. data/spec/integration/node_path_spec.rb +2 -2
  44. data/spec/integration/node_relationship_spec.rb +5 -3
  45. data/spec/integration/node_spec.rb +20 -19
  46. data/spec/integration/parsing_spec.rb +2 -2
  47. data/spec/integration/relationship_spec.rb +2 -2
  48. data/spec/integration/rest_batch_spec.rb +28 -28
  49. data/spec/integration/rest_bulk_spec.rb +2 -2
  50. data/spec/integration/rest_experimental_spec.rb +2 -2
  51. data/spec/integration/rest_gremlin_fail_spec.rb +2 -2
  52. data/spec/integration/rest_header_spec.rb +4 -9
  53. data/spec/integration/rest_index_spec.rb +21 -1
  54. data/spec/integration/rest_node_spec.rb +58 -44
  55. data/spec/integration/rest_path_spec.rb +5 -5
  56. data/spec/integration/rest_plugin_spec.rb +8 -2
  57. data/spec/integration/rest_relationship_spec.rb +35 -30
  58. data/spec/integration/rest_traverse_spec.rb +2 -2
  59. data/spec/matchers.rb +33 -0
  60. data/spec/neography_spec.rb +23 -0
  61. data/spec/spec_helper.rb +19 -1
  62. data/spec/unit/config_spec.rb +46 -0
  63. data/spec/unit/connection_spec.rb +205 -0
  64. data/spec/unit/node_spec.rb +100 -0
  65. data/spec/unit/properties_spec.rb +136 -0
  66. data/spec/unit/relationship_spec.rb +118 -0
  67. data/spec/unit/rest/batch_spec.rb +243 -0
  68. data/spec/unit/rest/clean_spec.rb +17 -0
  69. data/spec/unit/rest/cypher_spec.rb +21 -0
  70. data/spec/unit/rest/gremlin_spec.rb +26 -0
  71. data/spec/unit/rest/node_auto_indexes_spec.rb +67 -0
  72. data/spec/unit/rest/node_indexes_spec.rb +126 -0
  73. data/spec/unit/rest/node_paths_spec.rb +80 -0
  74. data/spec/unit/rest/node_properties_spec.rb +80 -0
  75. data/spec/unit/rest/node_relationships_spec.rb +78 -0
  76. data/spec/unit/rest/node_traversal_spec.rb +128 -0
  77. data/spec/unit/rest/nodes_spec.rb +188 -0
  78. data/spec/unit/rest/paths_spec.rb +69 -0
  79. data/spec/unit/rest/relationship_auto_indexes_spec.rb +67 -0
  80. data/spec/unit/rest/relationship_indexes_spec.rb +128 -0
  81. data/spec/unit/rest/relationship_properties_spec.rb +80 -0
  82. data/spec/unit/rest/relationships_spec.rb +22 -0
  83. metadata +86 -19
  84. data/Gemfile.lock +0 -44
  85. data/README.rdoc +0 -420
@@ -1,691 +1,361 @@
1
+ require 'forwardable'
2
+
3
+ require 'neography/rest/helpers'
4
+ require 'neography/rest/paths'
5
+
6
+ require 'neography/rest/properties'
7
+ require 'neography/rest/indexes'
8
+ require 'neography/rest/auto_indexes'
9
+
10
+ require 'neography/rest/nodes'
11
+ require 'neography/rest/node_properties'
12
+ require 'neography/rest/node_relationships'
13
+ require 'neography/rest/node_indexes'
14
+ require 'neography/rest/node_auto_indexes'
15
+ require 'neography/rest/node_traversal'
16
+ require 'neography/rest/node_paths'
17
+ require 'neography/rest/relationships'
18
+ require 'neography/rest/relationship_properties'
19
+ require 'neography/rest/relationship_indexes'
20
+ require 'neography/rest/relationship_auto_indexes'
21
+ require 'neography/rest/cypher'
22
+ require 'neography/rest/gremlin'
23
+ require 'neography/rest/batch'
24
+ require 'neography/rest/clean'
25
+
26
+ require 'neography/errors'
27
+
28
+ require 'neography/connection'
29
+
1
30
  module Neography
2
-
31
+
3
32
  class Rest
4
33
  include HTTParty
5
- USER_AGENT = "Neography/#{Neography::VERSION}"
6
-
7
- attr_accessor :protocol, :server, :port, :directory, :cypher_path, :gremlin_path, :log_file, :log_enabled, :logger, :max_threads, :authentication, :username, :password, :parser
8
-
9
- def initialize(options=ENV['NEO4J_URL'] || {})
10
- init = {:protocol => Neography::Config.protocol,
11
- :server => Neography::Config.server,
12
- :port => Neography::Config.port,
13
- :directory => Neography::Config.directory,
14
- :cypher_path => Neography::Config.cypher_path,
15
- :gremlin_path => Neography::Config.gremlin_path,
16
- :log_file => Neography::Config.log_file,
17
- :log_enabled => Neography::Config.log_enabled,
18
- :max_threads => Neography::Config.max_threads,
19
- :authentication => Neography::Config.authentication,
20
- :username => Neography::Config.username,
21
- :password => Neography::Config.password,
22
- :parser => Neography::Config.parser
23
- }
24
-
25
- unless options.respond_to?(:each_pair)
26
- url = URI.parse(options)
27
- options = Hash.new
28
- options[:protocol] = url.scheme + "://"
29
- options[:server] = url.host
30
- options[:port] = url.port
31
- options[:directory] = url.path
32
- options[:username] = url.user
33
- options[:password] = url.password
34
- options[:authentication] = 'basic' unless url.user.nil?
35
- end
36
-
37
- init.merge!(options)
38
-
39
- @protocol = init[:protocol]
40
- @server = init[:server]
41
- @port = init[:port]
42
- @directory = init[:directory]
43
- @cypher_path = init[:cypher_path]
44
- @gremlin_path = init[:gremlin_path]
45
- @log_file = init[:log_file]
46
- @log_enabled = init[:log_enabled]
47
- @logger = Logger.new(@log_file) if @log_enabled
48
- @max_threads = init[:max_threads]
49
- @authentication = Hash.new
50
- @authentication = {"#{init[:authentication]}_auth".to_sym => {:username => init[:username], :password => init[:password]}} unless init[:authentication].empty?
51
- @parser = init[:parser]
52
- @user_agent = {"User-Agent" => USER_AGENT}
53
- end
34
+ include Helpers
35
+ extend Forwardable
54
36
 
55
- def configure(protocol, server, port, directory)
56
- @protocol = protocol
57
- @server = server
58
- @port = port
59
- @directory = directory
60
- end
37
+ attr_reader :connection
61
38
 
62
- def configuration
63
- @protocol + @server + ':' + @port.to_s + @directory + "/db/data"
64
- end
39
+ def_delegators :@connection, :configuration
65
40
 
66
- def get_root
67
- get("/node/#{get_id(get('/')["reference_node"])}")
68
- end
41
+ def initialize(options = ENV['NEO4J_URL'] || {})
42
+ @connection = Connection.new(options)
69
43
 
70
- def create_node(*args)
71
- if args[0].respond_to?(:each_pair) && args[0]
72
- options = { :body => args[0].delete_if { |k, v| v.nil? }.to_json, :headers => {'Content-Type' => 'application/json'} }
73
- post("/node", options)
74
- else
75
- post("/node")
76
- end
77
- end
44
+ @nodes = Nodes.new(@connection)
45
+ @node_properties = NodeProperties.new(@connection)
46
+ @node_relationships = NodeRelationships.new(@connection)
47
+ @node_indexes = NodeIndexes.new(@connection)
48
+ @node_auto_indexes = NodeAutoIndexes.new(@connection)
49
+ @node_traversal = NodeTraversal.new(@connection)
50
+ @node_paths = NodePaths.new(@connection)
78
51
 
79
- def create_nodes(nodes)
80
- nodes = Array.new(nodes) if nodes.kind_of? Fixnum
81
- created_nodes = Array.new
82
- nodes.each do |node|
83
- created_nodes << create_node(node)
84
- end
85
- created_nodes
86
- end
52
+ @relationships = Relationships.new(@connection)
53
+ @relationship_properties = RelationshipProperties.new(@connection)
54
+ @relationship_indexes = RelationshipIndexes.new(@connection)
55
+ @relationship_auto_indexes = RelationshipAutoIndexes.new(@connection)
87
56
 
88
- def create_nodes_threaded(nodes)
89
- nodes = Array.new(nodes) if nodes.kind_of? Fixnum
90
-
91
- node_queue = Queue.new
92
- thread_pool = []
93
- responses = Queue.new
94
-
95
- nodes.each do |node|
96
- node_queue.push node
97
- end
98
-
99
- [nodes.size, @max_threads].min.times do
100
- thread_pool << Thread.new do
101
- until node_queue.empty? do
102
- node = node_queue.pop
103
- if node.respond_to?(:each_pair)
104
- responses.push( post("/node", { :body => node.to_json, :headers => {'Content-Type' => 'application/json'} } ) )
105
- else
106
- responses.push( post("/node") )
107
- end
108
- end
109
- self.join
110
- end
111
- end
112
-
113
- created_nodes = Array.new
114
-
115
- while created_nodes.size < nodes.size
116
- created_nodes << responses.pop
117
- end
118
- created_nodes
119
- end
57
+ @cypher = Cypher.new(@connection)
58
+ @gremlin = Gremlin.new(@connection)
59
+ @batch = Batch.new(@connection)
60
+ @clean = Clean.new(@connection)
61
+ end
120
62
 
121
- # This is not yet implemented in the REST API
122
- #
123
- # def get_all_node
124
- # puts "get all nodes"
125
- # get("/nodes/")
126
- # end
63
+ # nodes
127
64
 
128
- def get_node(id)
129
- get("/node/#{get_id(id)}")
130
- end
65
+ def get_root
66
+ @nodes.root
67
+ end
131
68
 
132
- def get_nodes(*nodes)
133
- gotten_nodes = Array.new
134
- Array(nodes).flatten.each do |node|
135
- gotten_nodes << get_node(node)
136
- end
137
- gotten_nodes
138
- end
69
+ def get_node(id)
70
+ @nodes.get(id)
71
+ end
139
72
 
140
- def reset_node_properties(id, properties)
141
- options = { :body => properties.to_json, :headers => {'Content-Type' => 'application/json'} }
142
- put("/node/#{get_id(id)}/properties", options)
143
- end
73
+ def get_nodes(*args)
74
+ @nodes.get_each(*args)
75
+ end
144
76
 
145
- def get_node_properties(id, properties = nil)
146
- if properties.nil?
147
- get("/node/#{get_id(id)}/properties")
148
- else
149
- node_properties = Hash.new
150
- Array(properties).each do |property|
151
- value = get("/node/#{get_id(id)}/properties/#{property}")
152
- node_properties[property] = value unless value.nil?
153
- end
154
- return nil if node_properties.empty?
155
- node_properties
156
- end
157
- end
77
+ def create_node(*args)
78
+ @nodes.create(*args)
79
+ end
158
80
 
159
- def remove_node_properties(id, properties = nil)
160
- if properties.nil?
161
- delete("/node/#{get_id(id)}/properties")
162
- else
163
- Array(properties).each do |property|
164
- delete("/node/#{get_id(id)}/properties/#{property}")
165
- end
166
- end
167
- end
81
+ def create_nodes(args)
82
+ @nodes.create_multiple(args)
83
+ end
168
84
 
169
- def set_node_properties(id, properties)
170
- properties.each do |key, value|
171
- options = { :body => value.to_json, :headers => {'Content-Type' => 'application/json'} }
172
- put("/node/#{get_id(id)}/properties/#{key}", options)
173
- end
174
- end
85
+ def create_nodes_threaded(args)
86
+ @nodes.create_multiple_threaded(args)
87
+ end
175
88
 
176
- def delete_node(id)
177
- delete("/node/#{get_id(id)}")
178
- end
89
+ def delete_node(id)
90
+ @nodes.delete(id)
91
+ end
179
92
 
180
- def create_relationship(type, from, to, props = nil)
181
- options = { :body => {:to => self.configuration + "/node/#{get_id(to)}", :data => props, :type => type }.to_json, :headers => {'Content-Type' => 'application/json'} }
182
- post("/node/#{get_id(from)}/relationships", options)
183
- end
93
+ def delete_node!(id)
94
+ relationships = get_node_relationships(get_id(id))
95
+ relationships.each do |relationship|
96
+ delete_relationship(relationship["self"].split('/').last)
97
+ end unless relationships.nil?
184
98
 
185
- def create_unique_relationship(index, key, value, type, from, to)
186
- body = {:key=>key,:value=>value, :type => type }
187
- body[:start] = self.configuration + "/node/#{get_id(from)}"
188
- body[:end] = self.configuration + "/node/#{get_id(to)}"
189
- options = { :body => body.to_json, :headers => {'Content-Type' => 'application/json'} }
190
- post("/index/relationship/#{index}?unique", options)
191
- end
99
+ delete_node(id)
100
+ end
192
101
 
193
- def get_relationship(id)
194
- get("/relationship/#{get_id(id)}")
195
- end
102
+ # This is not yet implemented in the REST API
103
+ #
104
+ # def get_all_node
105
+ # puts "get all nodes"
106
+ # get("/nodes/")
107
+ # end
196
108
 
197
- def get_relationship_start_node(rel)
198
- get_node(rel["start"])
199
- end
200
-
201
- def get_relationship_end_node(rel)
202
- get_node(rel["end"])
203
- end
204
-
205
- def reset_relationship_properties(id, properties)
206
- options = { :body => properties.to_json, :headers => {'Content-Type' => 'application/json'} }
207
- put("/relationship/#{get_id(id)}/properties", options)
208
- end
109
+ # node properties
209
110
 
210
- def get_relationship_properties(id, properties = nil)
211
- if properties.nil?
212
- get("/relationship/#{get_id(id)}/properties")
213
- else
214
- relationship_properties = Hash.new
215
- Array(properties).each do |property|
216
- value = get("/relationship/#{get_id(id)}/properties/#{property}")
217
- relationship_properties[property] = value unless value.nil?
218
- end
219
- return nil if relationship_properties.empty?
220
- relationship_properties
221
- end
222
- end
111
+ def get_node_properties(id, *properties)
112
+ @node_properties.get(id, *properties.flatten)
113
+ end
223
114
 
224
- def remove_relationship_properties(id, properties = nil)
225
- if properties.nil?
226
- delete("/relationship/#{get_id(id)}/properties")
227
- else
228
- Array(properties).each do |property|
229
- delete("/relationship/#{get_id(id)}/properties/#{property}")
230
- end
231
- end
232
- end
115
+ def set_node_properties(id, properties)
116
+ @node_properties.set(id, properties)
117
+ end
233
118
 
234
- def set_relationship_properties(id, properties)
235
- properties.each do |key, value|
236
- options = { :body => value.to_json, :headers => {'Content-Type' => 'application/json'} }
237
- put("/relationship/#{get_id(id)}/properties/#{key}", options)
238
- end
239
- end
119
+ def reset_node_properties(id, properties)
120
+ @node_properties.reset(id, properties)
121
+ end
240
122
 
241
- def delete_relationship(id)
242
- delete("/relationship/#{get_id(id)}")
243
- end
123
+ def remove_node_properties(id, *properties)
124
+ @node_properties.remove(id, *properties.flatten)
125
+ end
244
126
 
245
- def get_node_relationships(id, dir=nil, types=nil)
246
- dir = get_dir(dir)
127
+ # relationships
247
128
 
248
- if types.nil?
249
- node_relationships = get("/node/#{get_id(id)}/relationships/#{dir}") || Array.new
250
- else
251
- node_relationships = get("/node/#{get_id(id)}/relationships/#{dir}/#{Array(types).join('&')}") || Array.new
252
- end
253
- return nil if node_relationships.empty?
254
- node_relationships
255
- end
129
+ def get_relationship(id)
130
+ @relationships.get(id)
131
+ end
256
132
 
257
- def delete_node!(id)
258
- relationships = get_node_relationships(get_id(id))
259
- relationships.each { |r| delete_relationship(r["self"].split('/').last) } unless relationships.nil?
260
- delete("/node/#{get_id(id)}")
261
- end
133
+ def delete_relationship(id)
134
+ @relationships.delete(id)
135
+ end
262
136
 
263
- def list_node_indexes
264
- get("/index/node")
265
- end
137
+ def get_relationship_start_node(rel)
138
+ get_node(rel["start"])
139
+ end
266
140
 
267
- def create_node_index(name, type = "exact", provider = "lucene")
268
- options = { :body => ({:name => name, :config => {:type => type, :provider => provider}}).to_json, :headers => {'Content-Type' => 'application/json'} }
269
- post("/index/node", options)
270
- end
141
+ def get_relationship_end_node(rel)
142
+ get_node(rel["end"])
143
+ end
271
144
 
272
- def create_node_auto_index(type = "exact", provider = "lucene")
273
- create_node_index("node_auto_index", type, provider)
274
- end
145
+ # relationship properties
275
146
 
276
- def add_node_to_index(index, key, value, id)
277
- options = { :body => ({:uri => self.configuration + "/node/#{get_id(id)}", :key => key, :value => value }).to_json, :headers => {'Content-Type' => 'application/json'} }
278
- post("/index/node/#{index}", options)
279
- end
147
+ def get_relationship_properties(id, *properties)
148
+ @relationship_properties.get(id, *properties.flatten)
149
+ end
280
150
 
281
- def create_unique_node(index, key, value, props={})
282
- options = { :body => ({:properties=>props, :key => key, :value => value }).to_json, :headers => {'Content-Type' => 'application/json'} }
283
- post("/index/node/#{index}?unique", options)
284
- end
151
+ def set_relationship_properties(id, properties)
152
+ @relationship_properties.set(id, properties)
153
+ end
285
154
 
286
- def remove_node_from_index(*args)
287
- case args.size
288
- when 4 then delete("/index/node/#{args[0]}/#{args[1]}/#{args[2]}/#{get_id(args[3])}")
289
- when 3 then delete("/index/node/#{args[0]}/#{args[1]}/#{get_id(args[2])}")
290
- when 2 then delete("/index/node/#{args[0]}/#{get_id(args[1])}")
291
- end
292
- end
155
+ def reset_relationship_properties(id, properties)
156
+ @relationship_properties.reset(id, properties)
157
+ end
293
158
 
294
- def get_node_index(index, key, value)
295
- index = get("/index/node/#{index}/#{key}/#{value}") || Array.new
296
- return nil if index.empty?
297
- index
298
- end
159
+ def remove_relationship_properties(id, *properties)
160
+ @relationship_properties.remove(id, *properties.flatten)
161
+ end
299
162
 
300
- def get_node_auto_index(key, value)
301
- index = get("/index/auto/node/#{key}/#{value}") || Array.new
302
- return nil if index.empty?
303
- index
304
- end
163
+ # node relationships
305
164
 
306
- def find_node_auto_index(*args)
307
- case args.size
308
- when 2 then index = get("/index/auto/node/#{args[0]}/#{args[1]}") || Array.new
309
- when 1 then index = get("/index/auto/node/?query=#{args[0]}") || Array.new
310
- end
311
- return nil if index.empty?
312
- index
313
- end
165
+ def get_node_relationships(id, dir = nil, types = nil)
166
+ @node_relationships.get(id, dir, types)
167
+ end
314
168
 
315
- def find_node_index(*args)
316
- case args.size
317
- when 3 then index = get("/index/node/#{args[0]}/#{args[1]}?query=\"#{args[2]}\"") || Array.new
318
- when 2 then index = get("/index/node/#{args[0]}?query=#{args[1]}") || Array.new
319
- end
320
- return nil if index.empty?
321
- index
322
- end
169
+ def create_relationship(type, from, to, props = nil)
170
+ @node_relationships.create(type, from, to, props)
171
+ end
323
172
 
324
- alias_method :list_indexes, :list_node_indexes
325
- alias_method :add_to_index, :add_node_to_index
326
- alias_method :remove_from_index, :remove_node_from_index
327
- alias_method :get_index, :get_node_index
173
+ # node indexes
328
174
 
329
- def list_relationship_indexes
330
- get("/index/relationship")
331
- end
175
+ def list_node_indexes
176
+ @node_indexes.list
177
+ end
178
+ alias_method :list_indexes, :list_node_indexes
332
179
 
333
- def create_relationship_index(name, type = "exact", provider = "lucene")
334
- options = { :body => ({:name => name, :config => {:type => type, :provider => provider}}).to_json, :headers => {'Content-Type' => 'application/json'} }
335
- post("/index/relationship", options)
336
- end
180
+ def create_node_index(name, type = "exact", provider = "lucene")
181
+ @node_indexes.create(name, type, provider)
182
+ end
337
183
 
338
- def create_relationship_auto_index(type = "exact", provider = "lucene")
339
- create_relationship_index("relationship_auto_index", type, provider)
340
- end
184
+ def create_node_auto_index(type = "exact", provider = "lucene")
185
+ @node_indexes.create_auto(type, provider)
186
+ end
341
187
 
342
- def add_relationship_to_index(index, key, value, id)
343
- options = { :body => ({:uri => self.configuration + "/relationship/#{get_id(id)}", :key => key, :value => value}).to_json, :headers => {'Content-Type' => 'application/json'} }
344
- post("/index/relationship/#{index}", options)
345
- end
188
+ def create_unique_node(index, key, value, props={})
189
+ @node_indexes.create_unique(index, key, value, props)
190
+ end
346
191
 
347
- def remove_relationship_from_index(*args)
348
- case args.size
349
- when 4 then delete("/index/relationship/#{args[0]}/#{args[1]}/#{args[2]}/#{get_id(args[3])}")
350
- when 3 then delete("/index/relationship/#{args[0]}/#{args[1]}/#{get_id(args[2])}")
351
- when 2 then delete("/index/relationship/#{args[0]}/#{get_id(args[1])}")
352
- end
353
- end
192
+ def add_node_to_index(index, key, value, id)
193
+ @node_indexes.add(index, key, value, id)
194
+ end
195
+ alias_method :add_to_index, :add_node_to_index
354
196
 
355
- def get_relationship_index(index, key, value)
356
- index = get("/index/relationship/#{index}/#{key}/#{value}") || Array.new
357
- return nil if index.empty?
358
- index
359
- end
197
+ def remove_node_from_index(index, id_or_key, id_or_value = nil, id = nil)
198
+ @node_indexes.remove(index, id_or_key, id_or_value, id)
199
+ end
200
+ alias_method :remove_from_index, :remove_node_from_index
360
201
 
361
- def find_relationship_index(*args)
362
- case args.size
363
- when 3 then index = get("/index/relationship/#{args[0]}/#{args[1]}?query=#{args[2]}") || Array.new
364
- when 2 then index = get("/index/relationship/#{args[0]}?query=#{args[1]}") || Array.new
365
- end
366
- return nil if index.empty?
367
- index
368
- end
202
+ def get_node_index(index, key, value)
203
+ @node_indexes.get(index, key, value)
204
+ end
205
+ alias_method :get_index, :get_node_index
369
206
 
370
- def get_relationship_auto_index(key, value)
371
- index = get("/index/auto/relationship/#{key}/#{value}") || Array.new
372
- return nil if index.empty?
373
- index
374
- end
207
+ def find_node_index(index, key_or_query, value = nil)
208
+ @node_indexes.find(index, key_or_query, value)
209
+ end
375
210
 
376
- def find_relationship_auto_index(*args)
377
- case args.size
378
- when 2 then index = get("/index/auto/relationship/#{args[0]}/#{args[1]}") || Array.new
379
- when 1 then index = get("/index/auto/relationship/?query=#{args[0]}") || Array.new
380
- end
381
- return nil if index.empty?
382
- index
383
- end
211
+ # auto node indexes
384
212
 
385
- def get_node_auto_index_status
386
- get("/index/auto/node/status")
387
- end
213
+ def get_node_auto_index(key, value)
214
+ @node_auto_indexes.get(key, value)
215
+ end
388
216
 
389
- def get_relationship_auto_index_status
390
- get("/index/auto/relationship/status")
391
- end
217
+ def find_node_auto_index(key_or_query, value = nil)
218
+ @node_auto_indexes.find_or_query(key_or_query, value)
219
+ end
392
220
 
393
- def set_node_auto_index_status(change_to = true)
394
- options = { :body => change_to.to_json, :headers => {'Content-Type' => 'application/json'} }
395
- put("/index/auto/node/status", options)
396
- end
221
+ def get_node_auto_index_status
222
+ @node_auto_indexes.status
223
+ end
397
224
 
398
- def set_relationship_auto_index_status(change_to = true)
399
- options = { :body => change_to.to_json, :headers => {'Content-Type' => 'application/json'} }
400
- put("/index/auto/relationship/status", options)
401
- end
225
+ def set_node_auto_index_status(change_to = true)
226
+ @node_auto_indexes.status = change_to
227
+ end
402
228
 
403
- def get_node_auto_index_properties
404
- get("/index/auto/node/properties")
405
- end
229
+ def get_node_auto_index_properties
230
+ @node_auto_indexes.properties
231
+ end
406
232
 
407
- def get_relationship_auto_index_properties
408
- get("/index/auto/relationship/properties")
409
- end
233
+ def add_node_auto_index_property(property)
234
+ @node_auto_indexes.add_property(property)
235
+ end
410
236
 
411
- def add_node_auto_index_property(property)
412
- options = { :body => property, :headers => {'Content-Type' => 'application/json'} }
413
- post("/index/auto/node/properties", options)
414
- end
237
+ def remove_node_auto_index_property(property)
238
+ @node_auto_indexes.remove_property(property)
239
+ end
415
240
 
416
- def remove_node_auto_index_property(property)
417
- delete("/index/auto/node/properties/#{property}")
418
- end
241
+ # relationship indexes
419
242
 
420
- def add_relationship_auto_index_property(property)
421
- options = { :body => property, :headers => {'Content-Type' => 'application/json'} }
422
- post("/index/auto/relationship/properties", options)
423
- end
243
+ def list_relationship_indexes
244
+ @relationship_indexes.list
245
+ end
424
246
 
425
- def remove_relationship_auto_index_property(property)
426
- delete("/index/auto/relationship/properties/#{property}")
427
- end
247
+ def create_relationship_index(name, type = "exact", provider = "lucene")
248
+ @relationship_indexes.create(name, type, provider)
249
+ end
428
250
 
429
- def traverse(id, return_type, description)
430
- options = { :body => {"order" => get_order(description["order"]),
431
- "uniqueness" => get_uniqueness(description["uniqueness"]),
432
- "relationships" => description["relationships"],
433
- "prune_evaluator" => description["prune evaluator"],
434
- "return_filter" => description["return filter"],
435
- "max_depth" => get_depth(description["depth"]), }.to_json, :headers => {'Content-Type' => 'application/json'} }
436
- traversal = post("/node/#{get_id(id)}/traverse/#{get_type(return_type)}", options) || Array.new
437
- end
251
+ def create_relationship_auto_index(type = "exact", provider = "lucene")
252
+ @relationship_indexes.create_auto(type, provider)
253
+ end
438
254
 
439
- def get_path(from, to, relationships, depth=1, algorithm="shortestPath")
440
- options = { :body => {"to" => self.configuration + "/node/#{get_id(to)}", "relationships" => relationships, "max_depth" => depth, "algorithm" => get_algorithm(algorithm) }.to_json, :headers => {'Content-Type' => 'application/json'} }
441
- path = post("/node/#{get_id(from)}/path", options) || Hash.new
442
- end
255
+ def create_unique_relationship(index, key, value, type, from, to)
256
+ @relationship_indexes.create_unique(index, key, value, type, from, to)
257
+ end
443
258
 
444
- def get_paths(from, to, relationships, depth=1, algorithm="allPaths")
445
- options = { :body => {"to" => self.configuration + "/node/#{get_id(to)}", "relationships" => relationships, "max_depth" => depth, "algorithm" => get_algorithm(algorithm) }.to_json, :headers => {'Content-Type' => 'application/json'} }
446
- paths = post("/node/#{get_id(from)}/paths", options) || Array.new
447
- end
448
-
449
- def get_shortest_weighted_path(from, to, relationships, weight_attr='weight', depth=1, algorithm="dijkstra")
450
- options = { :body => {"to" => self.configuration + "/node/#{get_id(to)}", "relationships" => relationships, "cost_property" => weight_attr, "max_depth" => depth, "algorithm" => get_algorithm(algorithm) }.to_json, :headers => {'Content-Type' => 'application/json'} }
451
- paths = post("/node/#{get_id(from)}/paths", options) || Hash.new
452
- end
259
+ def add_relationship_to_index(index, key, value, id)
260
+ @relationship_indexes.add(index, key, value, id)
261
+ end
453
262
 
454
- def execute_query(query, params = {})
455
- options = { :body => {:query => query, :params => params}.to_json, :headers => {'Content-Type' => 'application/json', 'Accept' => 'application/json;stream=true'} }
456
- result = post(@cypher_path, options)
457
- end
458
-
459
- def execute_script(script, params = {})
460
- options = { :body => {:script => script, :params => params}.to_json , :headers => {'Content-Type' => 'application/json'} }
461
- result = post(@gremlin_path, options)
462
- result == "null" ? nil : result
463
- end
263
+ def remove_relationship_from_index(index, id_or_key, id_or_value = nil, id = nil)
264
+ @relationship_indexes.remove(index, id_or_key, id_or_value, id)
265
+ end
464
266
 
465
- def batch(*args)
466
- batch = []
467
- Array(args).each_with_index do |c,i|
468
- batch << {:id => i}.merge(get_batch(c))
469
- end
470
- options = { :body => batch.to_json, :headers => {'Content-Type' => 'application/json', 'Accept' => 'application/json;stream=true'} }
471
- post("/batch", options)
472
- end
473
-
474
- def batch_not_streaming(*args)
475
- batch = []
476
- Array(args).each_with_index do |c,i|
477
- batch << {:id => i}.merge(get_batch(c))
478
- end
479
- options = { :body => batch.to_json, :headers => {'Content-Type' => 'application/json'} }
480
- post("/batch", options)
481
- end
482
-
483
- # For testing (use a separate neo4j instance)
484
- # call this before each test or spec
485
- def clean_database(sanity_check = "not_really")
486
- if sanity_check == "yes_i_really_want_to_clean_the_database"
487
- delete("/cleandb/secret-key")
488
- true
489
- else
490
- false
491
- end
492
- end
267
+ def get_relationship_index(index, key, value)
268
+ @relationship_indexes.get(index, key, value)
269
+ end
493
270
 
494
- def merge_options(options)
495
- merged_options = options.merge!(@authentication).merge!(@parser)
496
- merged_options[:headers].merge!(@user_agent) if merged_options[:headers]
497
- merged_options
498
- end
499
-
500
- private
501
-
502
- def get_batch(args)
503
- case args[0]
504
- when :get_node
505
- {:method => "GET", :to => "/node/#{get_id(args[1])}"}
506
- when :create_node
507
- {:method => "POST", :to => "/node/", :body => args[1]}
508
- when :create_unique_node
509
- {:method => "POST", :to => "/index/node/#{args[1]}?unique", :body => {:key => args[2], :value => args[3], :properties => args[4]}}
510
- when :set_node_property
511
- {:method => "PUT", :to => "/node/#{get_id(args[1])}/properties/#{args[2].keys.first}", :body => args[2].values.first}
512
- when :reset_node_properties
513
- {:method => "PUT", :to => "/node/#{get_id(args[1])}/properties", :body => args[2]}
514
- when :get_relationship
515
- {:method => "GET", :to => "/relationship/#{get_id(args[1])}"}
516
- when :create_relationship
517
- {:method => "POST", :to => (args[2].is_a?(String) && args[2].start_with?("{") ? "" : "/node/") + "#{get_id(args[2])}/relationships", :body => {:to => (args[3].is_a?(String) && args[3].start_with?("{") ? "" : "/node/") + "#{get_id(args[3])}", :type => args[1], :data => args[4] } }
518
- when :create_unique_relationship
519
- {:method => "POST", :to => "/index/relationship/#{args[1]}?unique", :body => {:key => args[2], :value => args[3], :type => args[4], :start => (args[5].is_a?(String) && args[5].start_with?("{") ? "" : "/node/") + "#{get_id(args[5])}", :end=> (args[6].is_a?(String) && args[6].start_with?("{") ? "" : "/node/") + "#{get_id(args[6])}"} }
520
- when :delete_relationship
521
- {:method => "DELETE", :to => "/relationship/#{get_id(args[1])}"}
522
- when :set_relationship_property
523
- {:method => "PUT", :to => "/relationship/#{get_id(args[1])}/properties/#{args[2].keys.first}", :body => args[2].values.first}
524
- when :reset_relationship_properties
525
- {:method => "PUT", :to => (args[1].is_a?(String) && args[1].start_with?("{") ? "" : "/relationship/") + "#{get_id(args[1])}/properties", :body => args[2]}
526
- when :add_node_to_index
527
- {:method => "POST", :to => "/index/node/#{args[1]}", :body => {:uri => (args[4].is_a?(String) && args[4].start_with?("{") ? "" : "/node/") + "#{get_id(args[4])}", :key => args[2], :value => args[3] } }
528
- when :add_relationship_to_index
529
- {:method => "POST", :to => "/index/relationship/#{args[1]}", :body => {:uri => (args[4].is_a?(String) && args[4].start_with?("{") ? "" : "/relationship/") + "#{get_id(args[4])}", :key => args[2], :value => args[3] } }
530
- when :get_node_index
531
- {:method => "GET", :to => "/index/node/#{args[1]}/#{args[2]}/#{args[3]}"}
532
- when :get_relationship_index
533
- {:method => "GET", :to => "/index/relationship/#{args[1]}/#{args[2]}/#{args[3]}"}
534
- when :get_node_relationships
535
- {:method => "GET", :to => "/node/#{get_id(args[1])}/relationships/#{args[2] || 'all'}"}
536
- when :execute_script
537
- {:method => "POST", :to => @gremlin_path, :body => {:script => args[1], :params => args[2]}}
538
- when :execute_query
539
- if args[2]
540
- {:method => "POST", :to => @cypher_path, :body => {:query => args[1], :params => args[2]}}
541
- else
542
- {:method => "POST", :to => @cypher_path, :body => {:query => args[1]}}
543
- end
544
- when :remove_node_from_index
545
- case args.size
546
- when 5 then {:method => "DELETE", :to => "/index/node/#{args[1]}/#{args[2]}/#{args[3]}/#{get_id(args[4])}" }
547
- when 4 then {:method => "DELETE", :to => "/index/node/#{args[1]}/#{args[2]}/#{get_id(args[3])}" }
548
- when 3 then {:method => "DELETE", :to => "/index/node/#{args[1]}/#{get_id(args[2])}" }
549
- end
550
- when :remove_relationship_from_index
551
- case args.size
552
- when 5 then {:method => "DELETE", :to => "/index/relationship/#{args[1]}/#{args[2]}/#{args[3]}/#{get_id(args[4])}" }
553
- when 4 then {:method => "DELETE", :to => "/index/relationship/#{args[1]}/#{args[2]}/#{get_id(args[3])}" }
554
- when 3 then {:method => "DELETE", :to => "/index/relationship/#{args[1]}/#{get_id(args[2])}" }
555
- end
556
- when :delete_node
557
- {:method => "DELETE", :to => "/node/#{get_id(args[1])}"}
558
- else
559
- raise "Unknown option #{args[0]}"
560
- end
561
- end
271
+ def find_relationship_index(index, key_or_query, value = nil)
272
+ @relationship_indexes.find(index, key_or_query, value)
273
+ end
562
274
 
563
- def evaluate_response(response)
564
- code = response.code
565
- body = response.body
566
- case code
567
- when 200
568
- @logger.debug "OK" if @log_enabled
569
- response.parsed_response
570
- when 201
571
- @logger.debug "OK, created #{body}" if @log_enabled
572
- response.parsed_response
573
- when 204
574
- @logger.debug "OK, no content returned" if @log_enabled
575
- nil
576
- when 400
577
- @logger.error "Invalid data sent #{body}" if @log_enabled
578
- nil
579
- when 404
580
- @logger.error "Not Found #{body}" if @log_enabled
581
- nil
582
- when 409
583
- @logger.error "Node could not be deleted (still has relationships?)" if @log_enabled
584
- nil
585
- end
586
- end
275
+ # relationship auto indexes
587
276
 
588
- def get(path,options={})
589
- evaluate_response(HTTParty.get(configuration + URI.encode(path), merge_options(options)))
590
- end
591
-
592
- def post(path,options={})
593
- evaluate_response(HTTParty.post(configuration + URI.encode(path), merge_options(options)))
594
- end
595
-
596
- def put(path,options={})
597
- evaluate_response(HTTParty.put(configuration + URI.encode(path), merge_options(options)))
598
- end
599
-
600
- def delete(path,options={})
601
- evaluate_response(HTTParty.delete(configuration + URI.encode(path), merge_options(options)))
602
- end
603
-
604
- def get_id(id)
605
- case id
606
- when Array
607
- get_id(id.first)
608
- when Hash
609
- id["self"].split('/').last
610
- when String
611
- id.split('/').last
612
- when Neography::Node, Neography::Relationship
613
- id.neo_id
614
- else
615
- id
616
- end
617
- end
277
+ def get_relationship_auto_index(key, value)
278
+ @relationship_auto_indexes.get(key, value)
279
+ end
618
280
 
619
- def get_dir(dir)
620
- case dir
621
- when :incoming, "incoming", :in, "in"
622
- "in"
623
- when :outgoing, "outgoing", :out, "out"
624
- "out"
625
- else
626
- "all"
627
- end
628
- end
281
+ def find_relationship_auto_index(key_or_query, value = nil)
282
+ @relationship_auto_indexes.find_or_query(key_or_query, value)
283
+ end
629
284
 
630
- def get_algorithm(algorithm)
631
- case algorithm
632
- when :shortest, "shortest", :shortestPath, "shortestPath", :short, "short"
633
- "shortestPath"
634
- when :allSimplePaths, "allSimplePaths", :simple, "simple"
635
- "allSimplePaths"
636
- when :dijkstra, "dijkstra"
637
- "dijkstra"
638
- else
639
- "allPaths"
640
- end
641
- end
285
+ def get_relationship_auto_index_status
286
+ @relationship_auto_indexes.status
287
+ end
642
288
 
643
- def get_order(order)
644
- case order
645
- when :breadth, "breadth", "breadth first", "breadthFirst", :wide, "wide"
646
- "breadth first"
647
- else
648
- "depth first"
649
- end
650
- end
289
+ def set_relationship_auto_index_status(change_to = true)
290
+ @relationship_auto_indexes.status = change_to
291
+ end
651
292
 
652
- def get_type(type)
653
- case type
654
- when :relationship, "relationship", :relationships, "relationships"
655
- "relationship"
656
- when :path, "path", :paths, "paths"
657
- "path"
658
- when :fullpath, "fullpath", :fullpaths, "fullpaths"
659
- "fullpath"
660
- else
661
- "node"
662
- end
663
- end
293
+ def get_relationship_auto_index_properties
294
+ @relationship_auto_indexes.properties
295
+ end
664
296
 
665
- def get_uniqueness(uniqueness)
666
- case uniqueness
667
- when :nodeglobal, "node global", "nodeglobal", "node_global"
668
- "node global"
669
- when :nodepath, "node path", "nodepath", "node_path"
670
- "node path"
671
- when :noderecent, "node recent", "noderecent", "node_recent"
672
- "node recent"
673
- when :relationshipglobal, "relationship global", "relationshipglobal", "relationship_global"
674
- "relationship global"
675
- when :relationshippath, "relationship path", "relationshippath", "relationship_path"
676
- "relationship path"
677
- when :relationshiprecent, "relationship recent", "relationshiprecent", "relationship_recent"
678
- "relationship recent"
679
- else
680
- "none"
681
- end
682
- end
297
+ def add_relationship_auto_index_property(property)
298
+ @relationship_auto_indexes.add_property(property)
299
+ end
300
+
301
+ def remove_relationship_auto_index_property(property)
302
+ @relationship_auto_indexes.remove_property(property)
303
+ end
304
+
305
+ # traversal
306
+
307
+ def traverse(id, return_type, description)
308
+ @node_traversal.traverse(id, return_type, description)
309
+ end
310
+
311
+ # paths
312
+
313
+ def get_path(from, to, relationships, depth = 1, algorithm = "shortestPath")
314
+ @node_paths.get(from, to, relationships, depth, algorithm)
315
+ end
316
+
317
+ def get_paths(from, to, relationships, depth = 1, algorithm = "allPaths")
318
+ @node_paths.get_all(from, to, relationships, depth, algorithm)
319
+ end
320
+
321
+ def get_shortest_weighted_path(from, to, relationships, weight_attr = "weight", depth = 1, algorithm = "dijkstra")
322
+ @node_paths.shortest_weighted(from, to, relationships, weight_attr, depth, algorithm)
323
+ end
324
+
325
+ # cypher query
326
+
327
+ def execute_query(query, params = {})
328
+ @cypher.query(query, params)
329
+ end
330
+
331
+ # gremlin script
332
+
333
+ def execute_script(script, params = {})
334
+ @gremlin.execute(script, params)
335
+ end
336
+
337
+ # batch
338
+
339
+ def batch(*args)
340
+ @batch.execute(*args)
341
+ end
342
+
343
+ def batch_not_streaming(*args)
344
+ @batch.not_streaming(*args)
345
+ end
346
+
347
+ # clean database
683
348
 
684
- def get_depth(depth)
685
- return nil if depth.nil?
686
- return 1 if depth.to_i == 0
687
- depth.to_i
349
+ # For testing (use a separate neo4j instance)
350
+ # call this before each test or spec
351
+ def clean_database(sanity_check = "not_really")
352
+ if sanity_check == "yes_i_really_want_to_clean_the_database"
353
+ @clean.execute
354
+ true
355
+ else
356
+ false
688
357
  end
358
+ end
689
359
 
690
360
  end
691
361
  end