neo4j-core 3.0.8 → 3.1.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.
@@ -34,7 +34,7 @@ module Neo4j::Server
34
34
 
35
35
  def load_resource
36
36
  if resource_data.nil? || resource_data.empty?
37
- @resource_data = @session._query_or_fail("START n=relationship(#{id}) RETURN n", true) # r.first_data
37
+ @resource_data = @session._query_or_fail("#{match_start} RETURN n", true) # r.first_data
38
38
  end
39
39
  end
40
40
 
@@ -69,15 +69,15 @@ module Neo4j::Server
69
69
  end
70
70
 
71
71
  def get_property(key)
72
- @session._query_or_fail("START n=relationship(#{id}) RETURN n.`#{key}`", true)
72
+ @session._query_or_fail("#{match_start} RETURN n.`#{key}`", true)
73
73
  end
74
74
 
75
75
  def set_property(key,value)
76
- @session._query_or_fail("START n=relationship(#{id}) SET n.`#{key}` = {value}", false, {value: value})
76
+ @session._query_or_fail("#{match_start} SET n.`#{key}` = {value}", false, {value: value})
77
77
  end
78
78
 
79
79
  def remove_property(key)
80
- @session._query_or_fail("START n=relationship(#{id}) REMOVE n.`#{key}`")
80
+ @session._query_or_fail("#{match_start} REMOVE n.`#{key}`")
81
81
  end
82
82
 
83
83
  # (see Neo4j::Relationship#props)
@@ -85,21 +85,21 @@ module Neo4j::Server
85
85
  if @props
86
86
  @props
87
87
  else
88
- hash = @session._query_entity_data("START n=relationship(#{neo_id}) RETURN n")
88
+ hash = @session._query_entity_data("#{match_start} RETURN n")
89
89
  @props = Hash[hash['data'].map{ |k, v| [k.to_sym, v] }]
90
90
  end
91
91
  end
92
92
 
93
93
  # (see Neo4j::Relationship#props=)
94
94
  def props=(properties)
95
- @session._query_or_fail("START n=relationship(#{neo_id}) SET n = { props }", false, {props: properties})
95
+ @session._query_or_fail("#{match_start} SET n = { props }", false, {props: properties})
96
96
  properties
97
97
  end
98
98
 
99
99
  # (see Neo4j::Relationship#update_props)
100
100
  def update_props(properties)
101
101
  return if properties.empty?
102
- q = "START n=relationship(#{neo_id}) SET " + properties.keys.map do |k|
102
+ q = "#{match_start} SET " + properties.keys.map do |k|
103
103
  "n.`#{k}`= #{escape_value(properties[k])}"
104
104
  end.join(',')
105
105
  @session._query_or_fail(q)
@@ -111,24 +111,21 @@ module Neo4j::Server
111
111
  end
112
112
 
113
113
  def del
114
- id = neo_id
115
- @session._query("START n=relationship(#{id}) DELETE n").raise_unless_response_code(200)
114
+ @session._query("#{match_start} DELETE n").raise_unless_response_code(200)
116
115
  end
117
116
  alias_method :delete, :del
118
117
  alias_method :destroy, :del
119
118
 
120
119
  def exist?
121
- id = neo_id
122
- response = @session._query("START n=relationship(#{id}) RETURN n")
123
-
124
- if (!response.error?)
125
- return true
126
- elsif (response.error_status == 'BadInputException') # TODO see github issue neo4j/1061
127
- return false
128
- else
129
- response.raise_error
130
- end
120
+ response = @session._query("#{match_start} RETURN n")
121
+ # binding.pry
122
+ (response.data.nil? || response.data.empty?) ? false : true
131
123
  end
132
124
 
125
+ private
126
+
127
+ def match_start(identifier = 'n')
128
+ "MATCH (node)-[#{identifier}]-() WHERE ID(#{identifier}) = #{neo_id}"
129
+ end
133
130
  end
134
131
  end
@@ -10,7 +10,15 @@ module Neo4j::Server
10
10
  include Neo4j::Core::CypherTranslator
11
11
 
12
12
  alias_method :super_query, :query
13
- attr_reader :connection
13
+ attr_reader :connection, :auth
14
+
15
+ def initialize(data_url, connection, auth_obj = nil)
16
+ @connection = connection
17
+ @auth = auth_obj if auth_obj
18
+ Neo4j::Session.register(self)
19
+ initialize_resource(data_url)
20
+ Neo4j::Session._notify_listeners(:session_available, self)
21
+ end
14
22
 
15
23
  # @param [Hash] params could be empty or contain basic authentication user and password
16
24
  # @return [Faraday]
@@ -26,7 +34,7 @@ module Neo4j::Server
26
34
  b.use Faraday::Adapter::NetHttpPersistent
27
35
  # b.adapter Faraday.default_adapter
28
36
  end
29
- conn.headers = {'Content-Type' => 'application/json', 'User-Agent' => ::Neo4j::Session.user_agent_string}
37
+ conn.headers = { 'Content-Type' => 'application/json', 'User-Agent' => ::Neo4j::Session.user_agent_string }
30
38
  conn
31
39
  end
32
40
 
@@ -35,18 +43,21 @@ module Neo4j::Server
35
43
  #
36
44
  # @param [String] endpoint_url - the url to the neo4j server, defaults to 'http://localhost:7474'
37
45
  # @param [Hash] params faraday params, see #create_connection or an already created faraday connection
38
- def self.open(endpoint_url=nil, params = {})
46
+ def self.open(endpoint_url = nil, params = {})
39
47
  extract_basic_auth(endpoint_url, params)
40
48
  connection = params[:connection] || create_connection(params)
41
49
  url = endpoint_url || 'http://localhost:7474'
50
+ auth_obj = CypherAuthentication.new(url, connection, params)
51
+ auth_obj.authenticate
42
52
  response = connection.get(url)
43
53
  raise "Server not available on #{url} (response code #{response.status})" unless response.status == 200
54
+ establish_session(response.body, connection, auth_obj)
55
+ end
44
56
 
45
- root_data = response.body
57
+ def self.establish_session(root_data, connection, auth_obj)
46
58
  data_url = root_data['data']
47
59
  data_url << '/' unless data_url.end_with?('/')
48
-
49
- CypherSession.new(data_url, connection)
60
+ CypherSession.new(data_url, connection, auth_obj)
50
61
  end
51
62
 
52
63
  def self.extract_basic_auth(url, params)
@@ -56,14 +67,8 @@ module Neo4j::Server
56
67
  password: URI(url).password
57
68
  }
58
69
  end
59
- private_class_method :extract_basic_auth
60
70
 
61
- def initialize(data_url, connection)
62
- @connection = connection
63
- Neo4j::Session.register(self)
64
- initialize_resource(data_url)
65
- Neo4j::Session._notify_listeners(:session_available, self)
66
- end
71
+ private_class_method :extract_basic_auth
67
72
 
68
73
  def db_type
69
74
  :server_db
@@ -105,21 +110,16 @@ module Neo4j::Server
105
110
  Neo4j::Transaction.current
106
111
  end
107
112
 
108
- def create_node(props=nil, labels=[])
109
- l = labels.empty? ? "" : ":" + labels.map{|k| "`#{k}`"}.join(':')
110
- q = "CREATE (n#{l} #{cypher_prop_list(props)}) RETURN ID(n)"
111
- cypher_response = _query_or_fail(q, true)
112
- CypherNode.new(self, cypher_response)
113
+ def create_node(props = nil, labels = [])
114
+ CypherNode.new self, _query_or_fail(cypher_string(labels, props), true, cypher_prop_list(props))
113
115
  end
114
116
 
115
117
  def load_node(neo_id)
116
- cypher_response = _query("START n=node(#{neo_id}) RETURN n")
117
- load_entity(CypherNode, cypher_response)
118
+ load_entity(CypherNode, _query("MATCH (n) WHERE ID(n) = #{neo_id} RETURN n"))
118
119
  end
119
120
 
120
121
  def load_relationship(neo_id)
121
- cypher_response = _query("START r=relationship(#{neo_id}) RETURN r")
122
- load_entity(CypherRelationship, cypher_response)
122
+ load_entity(CypherRelationship, _query("MATCH (n)-[r]-() WHERE ID(r) = #{neo_id} RETURN r"))
123
123
  end
124
124
 
125
125
  def load_entity(clazz, cypher_response)
@@ -144,36 +144,21 @@ module Neo4j::Server
144
144
  end
145
145
 
146
146
  def uniqueness_constraints(label)
147
- response = @connection.get("#{@resource_url}schema/constraint/#{label}/uniqueness")
148
- expect_response_code(response, 200)
149
- data_resource = response.body
150
-
151
- property_keys = data_resource.map do |row|
152
- row['property_keys'].map(&:to_sym)
153
- end
154
-
155
- {
156
- property_keys: property_keys
157
- }
147
+ schema_properties("#{@resource_url}schema/constraint/#{label}/uniqueness")
158
148
  end
159
149
 
160
150
  def indexes(label)
161
- response = @connection.get("#{@resource_url}schema/index/#{label}")
162
- expect_response_code(response, 200)
163
- data_resource = response.body
164
-
165
- property_keys = data_resource.map do |row|
166
- row['property_keys'].map(&:to_sym)
167
- end
151
+ schema_properties("#{@resource_url}schema/index/#{label}")
152
+ end
168
153
 
169
- {
170
- property_keys: property_keys
171
- }
154
+ def schema_properties(query_string)
155
+ response = @connection.get(query_string)
156
+ expect_response_code(response, 200)
157
+ { property_keys: response.body.map { |row| row['property_keys'].map(&:to_sym) } }
172
158
  end
173
159
 
174
160
  def find_all_nodes(label_name)
175
- response = _query_or_fail("MATCH (n:`#{label_name}`) RETURN ID(n)")
176
- search_result_to_enumerable_first_column(response)
161
+ search_result_to_enumerable_first_column(_query_or_fail("MATCH (n:`#{label_name}`) RETURN ID(n)"))
177
162
  end
178
163
 
179
164
  def find_nodes(label_name, key, value)
@@ -254,41 +239,16 @@ module Neo4j::Server
254
239
  yielder << CypherNode.new(self, data[0]).wrapper
255
240
  end
256
241
  end
257
- end
242
+ end
258
243
 
259
244
  def map_column(key, map, data)
260
- case map[key]
261
- when :node
262
- CypherNode.new(self, data).wrapper
263
- when :rel, :relationship
264
- CypherRelationship.new(self, data)
265
- else
266
- data
245
+ if map[key] == :node
246
+ CypherNode.new(self, data).wrapper
247
+ elsif map[key] == :rel || map[:key] || :relationship
248
+ CypherRelationship.new(self, data)
249
+ else
250
+ data
267
251
  end
268
252
  end
269
-
270
-
271
- # def search_result_to_enumerable(response, ret, map)
272
- # return [] unless response.data
273
-
274
- # if (ret.size == 1)
275
- # Enumerator.new do |yielder|
276
- # response.data.each do |data|
277
- # yielder << map_column(key, map, data[0])
278
- # end
279
- # end
280
-
281
- # else
282
- # Enumerator.new do |yielder|
283
- # response.data.each do |data|
284
- # hash = {}
285
- # ret.each_with_index do |key, i|
286
- # hash[key] = map_column(key, map, data[i])
287
- # end
288
- # yielder << hash
289
- # end
290
- # end
291
- # end
292
- # end
293
253
  end
294
254
  end
@@ -1,15 +1,31 @@
1
1
  module Neo4j
2
2
  module Tasks
3
-
4
3
  module ConfigServer
5
4
 
6
- def config(data, port)
7
- s = set_property(data, 'org.neo4j.server.webserver.https.enabled', 'false')
5
+ def config(source_text, port)
6
+ s = set_property(source_text, 'org.neo4j.server.webserver.https.enabled', 'false')
8
7
  set_property(s, 'org.neo4j.server.webserver.port', port)
9
8
  end
10
9
 
11
- def set_property(data, property, value)
12
- data.gsub(/#{property}\s*=\s*(\w+)/, "#{property}=#{value}")
10
+ def set_property(source_text, property, value)
11
+ source_text.gsub(/#{property}\s*=\s*(\w+)/, "#{property}=#{value}")
12
+ end
13
+
14
+ # Toggles the status of Neo4j 2.2's basic auth
15
+ def toggle_auth(status, source_text)
16
+ status_string = status == :enable ? 'true' : 'false'
17
+ set_property(source_text, 'dbms.security.authorization_enabled', status_string)
18
+ end
19
+
20
+ # POSTs to an endpoint with the form required to change a Neo4j password
21
+ # @param [String] target_address The server address, with protocol and port, against which the form should be POSTed
22
+ # @param [String] old_password The existing password for the "neo4j" user account
23
+ # @param [String] new_password The new password you want to use. Shocking, isn't it?
24
+ # @return [Hash] The response from the server indicating success/failure.
25
+ def change_password(target_address, old_password, new_password)
26
+ uri = URI.parse("#{target_address}/user/neo4j/password")
27
+ response = Net::HTTP.post_form(uri, { 'password' => old_password, 'new_password' => new_password })
28
+ JSON.parse(response.body)
13
29
  end
14
30
 
15
31
  extend self
@@ -1,3 +1,4 @@
1
+ # :nocov:
1
2
  # borrowed from architect4r
2
3
  require 'os'
3
4
  require 'httparty'
@@ -6,24 +7,18 @@ require 'httparty'
6
7
  require File.expand_path("../config_server", __FILE__)
7
8
 
8
9
  namespace :neo4j do
9
-
10
10
  def download_neo4j(file)
11
- if OS::Underlying.windows? then
12
- file_name = "neo4j.zip"
13
- download_url = "http://dist.neo4j.org/neo4j-#{file}-windows.zip"
14
- else
15
- file_name = "neo4j-unix.tar.gz"
16
- download_url = "http://dist.neo4j.org/neo4j-#{file}-unix.tar.gz"
17
- end
11
+ file_name, download_url = if OS::Underlying.windows?
12
+ ["neo4j.zip", "http://dist.neo4j.org/neo4j-#{file}-windows.zip"]
13
+ else
14
+ ["neo4j-unix.tar.gz", "http://dist.neo4j.org/neo4j-#{file}-unix.tar.gz"]
15
+ end
18
16
 
19
17
  unless File.exist?(file_name)
20
18
  # check if file is available
21
19
  status = HTTParty.head(download_url).code
22
20
  raise "#{file} is not available to download, try a different version" if status < 200 || status >= 300
23
-
24
21
  df = File.open(file_name, 'wb')
25
-
26
-
27
22
  success = false
28
23
  begin
29
24
  df << HTTParty.get(download_url)
@@ -34,8 +29,6 @@ namespace :neo4j do
34
29
  end
35
30
  end
36
31
 
37
-
38
-
39
32
  # # http://download.neo4j.org/artifact?edition=community&version=2.1.2&distribution=tarball&dlid=3462770&_ga=1.110610309.1220184053.1399636580
40
33
  #
41
34
  # parsed_url = URI.parse(download_url)
@@ -67,25 +60,29 @@ namespace :neo4j do
67
60
  "db/neo4j/#{get_environment(args)}"
68
61
  end
69
62
 
70
- desc "Install Neo4j, example neo4j:install[community-2.1.3,development]"
63
+ def config_location(args)
64
+ "#{install_location(args)}/conf/neo4j-server.properties"
65
+ end
66
+
67
+ desc "Install Neo4j with auth disabled in v2.2+, example neo4j:install[community-2.1.3,development]"
71
68
  task :install, :edition, :environment do |_, args|
72
69
  file = args[:edition]
73
70
  environment = get_environment(args)
74
71
  puts "Installing Neo4j-#{file} environment: #{environment}"
75
72
 
76
73
  downloaded_file = download_neo4j file
77
-
74
+
78
75
  if OS::Underlying.windows?
79
76
  # Extract and move to neo4j directory
80
77
  unless File.exist?(install_location(args))
81
78
  Zip::ZipFile.open(downloaded_file) do |zip_file|
82
79
  zip_file.each do |f|
83
- f_path=File.join(".", f.name)
80
+ f_path = File.join(".", f.name)
84
81
  FileUtils.mkdir_p(File.dirname(f_path))
85
82
  begin
86
83
  zip_file.extract(f, f_path) unless File.exist?(f_path)
87
84
  rescue
88
- puts f.name + " failed to extract."
85
+ puts "#{f.name} failed to extract."
89
86
  end
90
87
  end
91
88
  end
@@ -105,19 +102,20 @@ namespace :neo4j do
105
102
  %x[rm #{downloaded_file}]
106
103
  puts "Neo4j Installed in to neo4j directory."
107
104
  end
105
+ rake_auth_toggle(args, :disable) unless /-2\.0|1\.[0-9]/.match(args[:edition])
108
106
  puts "Type 'rake neo4j:start' or 'rake neo4j:start[ENVIRONMENT]' to start it\nType 'neo4j:config[ENVIRONMENT,PORT]' for changing server port, (default 7474)"
109
107
  end
110
-
108
+
111
109
  desc "Start the Neo4j Server"
112
110
  task :start, :environment do |_, args|
113
111
  puts "Starting Neo4j #{get_environment(args)}..."
114
- if OS::Underlying.windows?
115
- if %x[reg query "HKU\\S-1-5-19"].size > 0
112
+ if OS::Underlying.windows?
113
+ if %x[reg query "HKU\\S-1-5-19"].size > 0
116
114
  %x[#{install_location(args)}/bin/Neo4j.bat start] #start service
117
115
  else
118
116
  puts "Starting Neo4j directly, not as a service."
119
117
  %x[#{install_location(args)}/bin/Neo4j.bat]
120
- end
118
+ end
121
119
  else
122
120
  %x[#{install_location(args)}/bin/neo4j start]
123
121
  end
@@ -129,7 +127,7 @@ namespace :neo4j do
129
127
  port = args[:port]
130
128
  raise "no port given" unless port
131
129
  puts "Config Neo4j #{get_environment(args)} for port #{port}"
132
- location = "#{install_location(args)}/conf/neo4j-server.properties"
130
+ location = config_location(args)
133
131
  text = File.read(location)
134
132
  replace = Neo4j::Tasks::ConfigServer.config(text, port)
135
133
  File.open(location, "w") {|file| file.puts replace}
@@ -138,13 +136,13 @@ namespace :neo4j do
138
136
  desc "Stop the Neo4j Server"
139
137
  task :stop, :environment do |_, args|
140
138
  puts "Stopping Neo4j #{get_environment(args)}..."
141
- if OS::Underlying.windows?
139
+ if OS::Underlying.windows?
142
140
  if %x[reg query "HKU\\S-1-5-19"].size > 0
143
141
  %x[#{install_location(args)}/bin/Neo4j.bat stop] #stop service
144
142
  else
145
- puts "You do not have administrative rights to stop the Neo4j Service"
143
+ puts "You do not have administrative rights to stop the Neo4j Service"
146
144
  end
147
- else
145
+ else
148
146
  %x[#{install_location(args)}/bin/neo4j stop]
149
147
  end
150
148
  end
@@ -166,13 +164,13 @@ namespace :neo4j do
166
164
  desc "Restart the Neo4j Server"
167
165
  task :restart, :environment do |_, args|
168
166
  puts "Restarting Neo4j #{get_environment(args)}..."
169
- if OS::Underlying.windows?
167
+ if OS::Underlying.windows?
170
168
  if %x[reg query "HKU\\S-1-5-19"].size > 0
171
169
  %x[#{install_location(args)}/bin/Neo4j.bat restart]
172
170
  else
173
- puts "You do not have administrative rights to restart the Neo4j Service"
171
+ puts "You do not have administrative rights to restart the Neo4j Service"
174
172
  end
175
- else
173
+ else
176
174
  %x[#{install_location(args)}/bin/neo4j restart]
177
175
  end
178
176
  end
@@ -180,36 +178,83 @@ namespace :neo4j do
180
178
  desc "Reset the Neo4j Server"
181
179
  task :reset_yes_i_am_sure, :environment do |_, args|
182
180
  # Stop the server
183
- if OS::Underlying.windows?
181
+ if OS::Underlying.windows?
184
182
  if %x[reg query "HKU\\S-1-5-19"].size > 0
185
183
  %x[#{install_location(args)}/bin/Neo4j.bat stop]
186
-
184
+
187
185
  # Reset the database
188
186
  FileUtils.rm_rf("#{install_location(args)}/data/graph.db")
189
187
  FileUtils.mkdir("#{install_location(args)}/data/graph.db")
190
-
188
+
191
189
  # Remove log files
192
190
  FileUtils.rm_rf("#{install_location(args)}/data/log")
193
191
  FileUtils.mkdir("#{install_location(args)}/data/log")
194
192
 
195
193
  %x[#{install_location(args)}/bin/Neo4j.bat start]
196
194
  else
197
- puts "You do not have administrative rights to reset the Neo4j Service"
195
+ puts "You do not have administrative rights to reset the Neo4j Service"
198
196
  end
199
- else
197
+ else
200
198
  %x[#{install_location(args)}/bin/neo4j stop]
201
-
199
+
202
200
  # Reset the database
203
201
  FileUtils.rm_rf("#{install_location(args)}/data/graph.db")
204
202
  FileUtils.mkdir("#{install_location(args)}/data/graph.db")
205
-
203
+
206
204
  # Remove log files
207
205
  FileUtils.rm_rf("#{install_location(args)}/data/log")
208
206
  FileUtils.mkdir("#{install_location(args)}/data/log")
209
-
207
+
210
208
  # Start the server
211
209
  %x[#{install_location(args)}/bin/neo4j start]
212
210
  end
213
211
  end
214
212
 
215
- end
213
+ desc "Neo4j 2.2: Change connection password"
214
+ task :change_password do |_, args|
215
+ puts "This will change the password for a Neo4j server"
216
+ puts "Enter target IP address or host name without protocal and port, press enter for http://localhost:7474"
217
+ address = STDIN.gets.chomp
218
+ target_address = address.empty? ? "http://localhost:7474" : address
219
+
220
+ puts "Input current password. Leave blank if this is a fresh installation of Neo4j."
221
+ password = STDIN.gets.chomp
222
+ old_password = password.empty? ? "neo4j" : password
223
+
224
+ puts "Input new password."
225
+ new_password = STDIN.gets.chomp
226
+ raise 'A new password is required' if new_password.empty?
227
+
228
+ body = Neo4j::Tasks::ConfigServer.change_password(target_address, old_password, new_password)
229
+ if body['errors']
230
+ puts "An error was returned: #{body['errors'][0]['message']}"
231
+ else
232
+ puts "Password changed successfully! Please update your app to use:"
233
+ puts "username: neo4j"
234
+ puts "password: #{new_password}"
235
+ end
236
+ end
237
+
238
+ def rake_auth_toggle(args, status)
239
+ location = config_location(args)
240
+ text = File.read(location)
241
+ replace = Neo4j::Tasks::ConfigServer.toggle_auth(status, text)
242
+ File.open(location, "w") {|file| file.puts replace}
243
+ end
244
+
245
+ def auth_toggle_complete(status)
246
+ puts "Neo4j basic authentication #{status}. Restart server to apply."
247
+ end
248
+
249
+ desc "Neo4j 2.2: Enable Auth"
250
+ task :enable_auth, :environment do |_, args|
251
+ rake_auth_toggle(args, :enable)
252
+ auth_toggle_complete('enabled')
253
+ end
254
+
255
+ desc "Neo4j 2.2: Disable Auth"
256
+ task :disable_auth, :environment do |_, args|
257
+ rake_auth_toggle(args, :disable)
258
+ auth_toggle_complete('disabled')
259
+ end
260
+ end