neo4j-core 5.0.1 → 5.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.
@@ -1,3 +1,5 @@
1
+ require 'uri'
2
+
1
3
  module Neo4j
2
4
  module Server
3
5
  Neo4j::Session.register_db(:server_db) do |endpoint_url, url_opts|
@@ -6,7 +8,6 @@ module Neo4j
6
8
 
7
9
  class CypherSession < Neo4j::Session
8
10
  include Resource
9
- include Neo4j::Core::CypherTranslator
10
11
 
11
12
  alias_method :super_query, :query
12
13
  attr_reader :connection
@@ -100,9 +101,14 @@ module Neo4j
100
101
  end
101
102
 
102
103
  def create_node(props = nil, labels = [])
103
- id = _query_or_fail(cypher_string(labels, props), true, cypher_prop_list!(props))
104
- value = props.nil? ? id : {id: id, metadata: {labels: labels}, data: props}
105
- CypherNode.new(self, value)
104
+ label_string = labels.empty? ? '' : (':' + labels.map { |k| "`#{k}`" }.join(':'))
105
+ if !props.nil?
106
+ prop = '{props}'
107
+ props.each_key { |k| props.delete(k) if props[k].nil? }
108
+ end
109
+
110
+ id = _query_or_fail("CREATE (n#{label_string} #{prop}) RETURN ID(n)", true, props: props)
111
+ CypherNode.new(self, props.nil? ? id : {id: id, metadata: {labels: labels}, data: props})
106
112
  end
107
113
 
108
114
  def load_node(neo_id)
@@ -112,11 +118,9 @@ module Neo4j
112
118
  def load_relationship(neo_id)
113
119
  query.unwrapped.optional_match('(n)-[r]-()').where(r: {neo_id: neo_id}).pluck(:r).first
114
120
  rescue Neo4j::Session::CypherError => cypher_error
115
- if cypher_error.message.match(/not found$/)
116
- nil
117
- else
118
- raise cypher_error
119
- end
121
+ return nil if cypher_error.message.match(/not found$/)
122
+
123
+ raise cypher_error
120
124
  end
121
125
 
122
126
  def create_label(name)
@@ -195,26 +199,24 @@ module Neo4j
195
199
  end
196
200
 
197
201
  def _query_entity_data(query, id = nil, params = {})
198
- _query_response(query, params).entity_data(id)
199
- end
200
-
201
- def _query_response(query, params = {})
202
202
  _query(query, params).tap do |response|
203
203
  response.raise_error if response.error?
204
- end
204
+ end.entity_data(id)
205
205
  end
206
206
 
207
- def _query(query, params = {})
207
+ def _query(query, params = {}, options = {})
208
208
  query, params = query_and_params(query, params)
209
209
 
210
210
  curr_tx = Neo4j::Transaction.current
211
- if curr_tx
212
- curr_tx._query(query, params)
213
- else
214
- url = resource_url(:cypher)
215
- query = params.nil? ? {'query' => query} : {'query' => query, 'params' => params}
216
- response = @connection.post(url, query)
217
- CypherResponse.create_with_no_tx(response)
211
+ ActiveSupport::Notifications.instrument('neo4j.cypher_query', params: params, context: options[:context],
212
+ cypher: query, pretty_cypher: options[:pretty_cypher]) do
213
+ if curr_tx
214
+ curr_tx._query(query, params)
215
+ else
216
+ query = params.nil? ? {'query' => query} : {'query' => query, 'params' => params}
217
+ response = @connection.post(resource_url(:cypher), query)
218
+ CypherResponse.create_with_no_tx(response)
219
+ end
218
220
  end
219
221
  end
220
222
 
@@ -235,12 +237,14 @@ module Neo4j
235
237
  end
236
238
 
237
239
  EMPTY = ''
240
+ NEWLINE_W_SPACES = "\n "
238
241
  def self.log_with
239
- clear, yellow, cyan = %W(\e[0m \e[33m \e[36m)
240
242
  ActiveSupport::Notifications.subscribe('neo4j.cypher_query') do |_, start, finish, _id, payload|
241
243
  ms = (finish - start) * 1000
242
- params_string = (payload[:params].size > 0 ? "| #{payload[:params].inspect}" : EMPTY)
243
- yield(" #{cyan}#{payload[:context]}#{clear} #{yellow}#{ms.round}ms#{clear} #{payload[:cypher]} #{params_string}")
244
+ params_string = (payload[:params] && payload[:params].size > 0 ? "| #{payload[:params].inspect}" : EMPTY)
245
+ cypher = payload[:pretty_cypher] ? NEWLINE_W_SPACES + payload[:pretty_cypher].gsub(/\n/, NEWLINE_W_SPACES) : payload[:cypher]
246
+
247
+ yield(" #{ANSI::CYAN}#{payload[:context] || 'CYPHER'}#{ANSI::CLEAR} #{ANSI::YELLOW}#{ms.round}ms#{ANSI::CLEAR} #{cypher} #{params_string}")
244
248
  end
245
249
  end
246
250
  end
@@ -9,7 +9,6 @@ module Neo4j
9
9
  # If a transaction is created and then closed without performing any queries, an OpenStruct is returned that behaves like a successfully closed query.
10
10
  class CypherTransaction
11
11
  include Neo4j::Transaction::Instance
12
- include Neo4j::Core::CypherTranslator
13
12
  include Resource
14
13
 
15
14
  attr_reader :commit_url, :query_url, :base_url, :connection
data/lib/neo4j-server.rb CHANGED
@@ -7,7 +7,6 @@ require 'neo4j-server/cypher_node'
7
7
  require 'neo4j-server/cypher_label'
8
8
  require 'neo4j-server/label'
9
9
  require 'neo4j-server/cypher_session'
10
- require 'neo4j-server/cypher_node_uncommited'
11
10
  require 'neo4j-server/cypher_relationship'
12
11
  require 'neo4j-server/cypher_response'
13
12
  require 'neo4j-server/cypher_transaction'
data/neo4j-core.gemspec CHANGED
@@ -30,11 +30,10 @@ Neo4j-core provides classes and methods to work with the graph database Neo4j.
30
30
  s.add_dependency('httpclient')
31
31
  s.add_dependency('faraday_middleware', '~> 0.9.1')
32
32
  s.add_dependency('json')
33
- s.add_dependency('os') # for Rake task
34
- s.add_dependency('zip') # for Rake task
35
33
  s.add_dependency('activesupport') # For ActiveSupport::Notifications
36
34
  s.add_dependency('multi_json')
37
35
  s.add_dependency('faraday_middleware-multi_json')
36
+ s.add_dependency('neo4j-rake_tasks')
38
37
 
39
38
  s.add_development_dependency('pry')
40
39
  s.add_development_dependency('yard')
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: neo4j-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.1
4
+ version: 5.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andreas Ronge, Chris Grigg, Brian Underwood
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-24 00:00:00.000000000 Z
11
+ date: 2015-08-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -95,21 +95,7 @@ dependencies:
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
- name: os
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: '0'
104
- type: :runtime
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- version: '0'
111
- - !ruby/object:Gem::Dependency
112
- name: zip
98
+ name: activesupport
113
99
  requirement: !ruby/object:Gem::Requirement
114
100
  requirements:
115
101
  - - ">="
@@ -123,7 +109,7 @@ dependencies:
123
109
  - !ruby/object:Gem::Version
124
110
  version: '0'
125
111
  - !ruby/object:Gem::Dependency
126
- name: activesupport
112
+ name: multi_json
127
113
  requirement: !ruby/object:Gem::Requirement
128
114
  requirements:
129
115
  - - ">="
@@ -137,7 +123,7 @@ dependencies:
137
123
  - !ruby/object:Gem::Version
138
124
  version: '0'
139
125
  - !ruby/object:Gem::Dependency
140
- name: multi_json
126
+ name: faraday_middleware-multi_json
141
127
  requirement: !ruby/object:Gem::Requirement
142
128
  requirements:
143
129
  - - ">="
@@ -151,7 +137,7 @@ dependencies:
151
137
  - !ruby/object:Gem::Version
152
138
  version: '0'
153
139
  - !ruby/object:Gem::Dependency
154
- name: faraday_middleware-multi_json
140
+ name: neo4j-rake_tasks
155
141
  requirement: !ruby/object:Gem::Requirement
156
142
  requirements:
157
143
  - - ">="
@@ -261,8 +247,6 @@ files:
261
247
  - lib/ext/kernel.rb
262
248
  - lib/neo4j-core.rb
263
249
  - lib/neo4j-core/active_entity.rb
264
- - lib/neo4j-core/cypher_translator.rb
265
- - lib/neo4j-core/hash_with_indifferent_access.rb
266
250
  - lib/neo4j-core/helpers.rb
267
251
  - lib/neo4j-core/label.rb
268
252
  - lib/neo4j-core/query.rb
@@ -285,13 +269,13 @@ files:
285
269
  - lib/neo4j-server.rb
286
270
  - lib/neo4j-server/cypher_label.rb
287
271
  - lib/neo4j-server/cypher_node.rb
288
- - lib/neo4j-server/cypher_node_uncommited.rb
289
272
  - lib/neo4j-server/cypher_relationship.rb
290
273
  - lib/neo4j-server/cypher_response.rb
291
274
  - lib/neo4j-server/cypher_session.rb
292
275
  - lib/neo4j-server/cypher_transaction.rb
293
276
  - lib/neo4j-server/label.rb
294
277
  - lib/neo4j-server/resource.rb
278
+ - lib/neo4j/ansi.rb
295
279
  - lib/neo4j/entity_equality.rb
296
280
  - lib/neo4j/label.rb
297
281
  - lib/neo4j/node.rb
@@ -299,8 +283,6 @@ files:
299
283
  - lib/neo4j/property_validator.rb
300
284
  - lib/neo4j/relationship.rb
301
285
  - lib/neo4j/session.rb
302
- - lib/neo4j/tasks/config_server.rb
303
- - lib/neo4j/tasks/neo4j_server.rake
304
286
  - lib/neo4j/transaction.rb
305
287
  - neo4j-core.gemspec
306
288
  homepage: https://github.com/neo4jrb/neo4j-core
@@ -1,36 +0,0 @@
1
- module Neo4j
2
- module Tasks
3
- module ConfigServer
4
- def config(source_text, port)
5
- s = set_property(source_text, 'org.neo4j.server.webserver.https.enabled', 'false')
6
- set_property(s, 'org.neo4j.server.webserver.port', port)
7
- end
8
-
9
- def set_property(source_text, property, value)
10
- source_text.gsub(/#{property}\s*=\s*(\w+)/, "#{property}=#{value}")
11
- end
12
-
13
- # Toggles the status of Neo4j 2.2's basic auth
14
- def toggle_auth(status, source_text)
15
- status_string = status == :enable ? 'true' : 'false'
16
- %w(dbms.security.authorization_enabled dbms.security.auth_enabled).each do |key|
17
- source_text = set_property(source_text, key, status_string)
18
- end
19
- source_text
20
- end
21
-
22
- # POSTs to an endpoint with the form required to change a Neo4j password
23
- # @param [String] target_address The server address, with protocol and port, against which the form should be POSTed
24
- # @param [String] old_password The existing password for the "neo4j" user account
25
- # @param [String] new_password The new password you want to use. Shocking, isn't it?
26
- # @return [Hash] The response from the server indicating success/failure.
27
- def change_password(target_address, old_password, new_password)
28
- uri = URI.parse("#{target_address}/user/neo4j/password")
29
- response = Net::HTTP.post_form(uri, 'password' => old_password, 'new_password' => new_password)
30
- JSON.parse(response.body)
31
- end
32
-
33
- extend self
34
- end
35
- end
36
- end
@@ -1,245 +0,0 @@
1
- # :nocov:
2
- # borrowed from architect4r
3
- require 'os'
4
- require 'httparty'
5
- require 'zip'
6
- require 'httparty'
7
- require File.expand_path('../config_server', __FILE__)
8
-
9
- namespace :neo4j do
10
- def file_name
11
- OS::Underlying.windows? ? 'neo4j.zip' : 'neo4j-unix.tar.gz'
12
- end
13
-
14
- def download_url(edition)
15
- "http://dist.neo4j.org/neo4j-#{edition}-#{OS::Underlying.windows? ? 'windows.zip' : 'unix.tar.gz'}"
16
- end
17
-
18
- def download_neo4j_unless_exists(edition)
19
- download_neo4j(edition) unless File.exist?(file_name)
20
- end
21
-
22
- def download_neo4j(edition)
23
- success = false
24
-
25
- File.open(file_name, 'wb') do |file|
26
- file << request_url(download_url(edition))
27
- success = true
28
- end
29
-
30
- file_name
31
- ensure
32
- File.delete(file_name) unless success
33
- end
34
-
35
- def request_url(url)
36
- status = HTTParty.head(url).code
37
- fail "#{edition} is not available to download, try a different version" if status < 200 || status >= 300
38
-
39
- HTTParty.get(url)
40
- end
41
-
42
- def get_environment(args)
43
- args[:environment] || 'development'
44
- end
45
-
46
- def install_location(args)
47
- FileUtils.mkdir_p('db/neo4j')
48
- "db/neo4j/#{get_environment(args)}"
49
- end
50
-
51
- def config_location(args)
52
- "#{install_location(args)}/conf/neo4j-server.properties"
53
- end
54
-
55
- def start_server(command, args)
56
- puts "Starting Neo4j #{get_environment(args)}..."
57
- if OS::Underlying.windows?
58
- start_windows_server(command, args)
59
- else
60
- start_starnix_server(command, args)
61
- end
62
- end
63
-
64
- def system_or_fail(command)
65
- system(command) or fail "Unable to run: #{command}" # rubocop:disable Style/AndOr
66
- end
67
-
68
- def start_windows_server(command, args)
69
- if system_or_fail!('reg query "HKU\\S-1-5-19"').size > 0
70
- system_or_fail("#{install_location(args)}/bin/Neo4j.bat #{command}") # start service
71
- else
72
- puts 'Starting Neo4j directly, not as a service.'
73
- system_or_fail("#{install_location(args)}/bin/Neo4j.bat")
74
- end
75
- end
76
-
77
- def start_starnix_server(command, args)
78
- system_or_fail("#{install_location(args)}/bin/neo4j #{command}")
79
- end
80
-
81
- desc 'Install Neo4j with auth disabled in v2.2+, example neo4j:install[community-2.1.3,development]'
82
- task :install, :edition, :environment do |_, args|
83
- edition = args[:edition]
84
- environment = get_environment(args)
85
- puts "Installing Neo4j-#{edition} environment: #{environment}"
86
-
87
- downloaded_file = download_neo4j_unless_exists edition
88
-
89
- if OS::Underlying.windows?
90
- # Extract and move to neo4j directory
91
- unless File.exist?(install_location(args))
92
- Zip::ZipFile.open(downloaded_file) do |zip_file|
93
- zip_file.each do |f|
94
- f_path = File.join('.', f.name)
95
- FileUtils.mkdir_p(File.dirname(f_path))
96
- begin
97
- zip_file.extract(f, f_path) unless File.exist?(f_path)
98
- rescue
99
- puts "#{f.name} failed to extract."
100
- end
101
- end
102
- end
103
- FileUtils.mv "neo4j-#{edition}", install_location(args)
104
- FileUtils.rm downloaded_file
105
- end
106
-
107
- # Install if running with Admin Privileges
108
- if system_or_fail('reg query "HKU\\S-1-5-19"').size > 0
109
- system_or_fail("\"#{install_location(args)}/bin/neo4j install\"")
110
- puts 'Neo4j Installed as a service.'
111
- end
112
-
113
- else
114
- system_or_fail("tar -xvf #{downloaded_file}")
115
- system_or_fail("mv neo4j-#{edition} #{install_location(args)}")
116
- system_or_fail("rm #{downloaded_file}")
117
- puts 'Neo4j Installed in to neo4j directory.'
118
- end
119
- rake_auth_toggle(args, :disable) unless /-2\.0|1\.[0-9]/.match(args[:edition])
120
- puts "Type 'rake neo4j:start' or 'rake neo4j:start[ENVIRONMENT]' to start it\nType 'neo4j:config[ENVIRONMENT,PORT]' for changing server port, (default 7474)"
121
- end
122
-
123
- desc 'Start the Neo4j Server'
124
- task :start, :environment do |_, args|
125
- start_server('start', args)
126
- end
127
-
128
- desc 'Start the Neo4j Server asynchronously'
129
- task :start_no_wait, :environment do |_, args|
130
- start_server('start-no-wait', args)
131
- end
132
-
133
- desc 'Configure Server, e.g. rake neo4j:config[development,8888]'
134
- task :config, :environment, :port do |_, args|
135
- port = args[:port]
136
- fail 'no port given' unless port
137
- puts "Config Neo4j #{get_environment(args)} for port #{port}"
138
- location = config_location(args)
139
- text = File.read(location)
140
- replace = Neo4j::Tasks::ConfigServer.config(text, port)
141
- File.open(location, 'w') { |file| file.puts replace }
142
- end
143
-
144
- def validate_is_system_admin!
145
- return unless OS::Underlying.windows?
146
- return if system_or_fail("reg query \"HKU\\S-1-5-19\"").size > 0
147
-
148
- fail 'You do not have administrative rights to stop the Neo4j Service'
149
- end
150
-
151
- def run_neo4j_command_or_fail!(args, command)
152
- binary = OS::Underlying.windows? ? 'Neo4j.bat' : 'neo4j'
153
-
154
- system_or_fail("#{install_location(args)}/bin/#{binary} #{command}")
155
- end
156
-
157
- desc 'Stop the Neo4j Server'
158
- task :stop, :environment do |_, args|
159
- puts "Stopping Neo4j #{get_environment(args)}..."
160
- validate_is_system_admin!
161
-
162
- run_neo4j_command_or_fail!(args, :stop)
163
- end
164
-
165
- desc 'Get info the Neo4j Server'
166
- task :info, :environment do |_, args|
167
- puts "Info from Neo4j #{get_environment(args)}..."
168
- validate_is_system_admin!
169
-
170
- run_neo4j_command_or_fail!(args, :info)
171
- end
172
-
173
- desc 'Restart the Neo4j Server'
174
- task :restart, :environment do |_, args|
175
- puts "Restarting Neo4j #{get_environment(args)}..."
176
- validate_is_system_admin!
177
-
178
- run_neo4j_command_or_fail!(args, :restart)
179
- end
180
-
181
- desc 'Reset the Neo4j Server'
182
- task :reset_yes_i_am_sure, :environment do |_, args|
183
- validate_is_system_admin!
184
-
185
- run_neo4j_command_or_fail!(args, :stop)
186
-
187
- # Reset the database
188
- FileUtils.rm_rf("#{install_location(args)}/data/graph.db")
189
- FileUtils.mkdir("#{install_location(args)}/data/graph.db")
190
-
191
- # Remove log files
192
- FileUtils.rm_rf("#{install_location(args)}/data/log")
193
- FileUtils.mkdir("#{install_location(args)}/data/log")
194
-
195
- run_neo4j_command_or_fail!(args, :start)
196
- end
197
-
198
- desc 'Neo4j 2.2: Change connection password'
199
- task :change_password do
200
- puts 'This will change the password for a Neo4j server'
201
- puts 'Enter target IP address or host name without protocal and port, press enter for http://localhost:7474'
202
- address = STDIN.gets.chomp
203
- target_address = address.empty? ? 'http://localhost:7474' : address
204
-
205
- puts 'Input current password. Leave blank if this is a fresh installation of Neo4j.'
206
- password = STDIN.gets.chomp
207
- old_password = password.empty? ? 'neo4j' : password
208
-
209
- puts 'Input new password.'
210
- new_password = STDIN.gets.chomp
211
- fail 'A new password is required' if new_password.empty?
212
-
213
- body = Neo4j::Tasks::ConfigServer.change_password(target_address, old_password, new_password)
214
- if body['errors']
215
- puts "An error was returned: #{body['errors'][0]['message']}"
216
- else
217
- puts 'Password changed successfully! Please update your app to use:'
218
- puts 'username: neo4j'
219
- puts "password: #{new_password}"
220
- end
221
- end
222
-
223
- def rake_auth_toggle(args, status)
224
- location = config_location(args)
225
- text = File.read(location)
226
- replace = Neo4j::Tasks::ConfigServer.toggle_auth(status, text)
227
- File.open(location, 'w') { |file| file.puts replace }
228
- end
229
-
230
- def auth_toggle_complete(status)
231
- puts "Neo4j basic authentication #{status}. Restart server to apply."
232
- end
233
-
234
- desc 'Neo4j 2.2: Enable Auth'
235
- task :enable_auth, :environment do |_, args|
236
- rake_auth_toggle(args, :enable)
237
- auth_toggle_complete('enabled')
238
- end
239
-
240
- desc 'Neo4j 2.2: Disable Auth'
241
- task :disable_auth, :environment do |_, args|
242
- rake_auth_toggle(args, :disable)
243
- auth_toggle_complete('disabled')
244
- end
245
- end
@@ -1,76 +0,0 @@
1
- module Neo4j
2
- module Core
3
- module CypherTranslator
4
- # Cypher Helper
5
- def escape_value(value)
6
- if value.is_a?(String) || value.is_a?(Symbol)
7
- "'#{escape_quotes(sanitize_escape_sequences(value.to_s))}'"
8
- else
9
- value
10
- end
11
- end
12
-
13
- # Like escape_value but it does not wrap the value in quotes
14
- def create_escape_value(value)
15
- if value.is_a?(String) || value.is_a?(Symbol)
16
- "#{sanitize_escape_sequences(value.to_s)}"
17
- else
18
- value
19
- end
20
- end
21
-
22
- # Only following escape sequence characters are allowed in Cypher:
23
- #
24
- # \t Tab
25
- # \b Backspace
26
- # \n Newline
27
- # \r Carriage return
28
- # \f Form feed
29
- # \' Single quote
30
- # \" Double quote
31
- # \\ Backslash
32
- #
33
- # From:
34
- # http://docs.neo4j.org/chunked/stable/cypher-expressions.html#_note_on_string_literals
35
- SANITIZE_ESCAPED_REGEXP = /(?<!\\)\\(\\\\)*(?![futbnr'"\\])/
36
- EMPTY_PROPS = ''
37
-
38
- def sanitize_escape_sequences(s)
39
- s.gsub SANITIZE_ESCAPED_REGEXP, EMPTY_PROPS
40
- end
41
-
42
- def escape_quotes(s)
43
- s.gsub("'", %q(\\\'))
44
- end
45
-
46
- # Cypher Helper
47
- def cypher_prop_list!(props)
48
- return nil unless props
49
- props.reject! { |_, v| v.nil? }
50
- {props: props.each { |k, v| props[k] = create_escape_value(v) }}
51
- end
52
-
53
- # Stolen from keymaker
54
- # https://github.com/therubymug/keymaker/blob/master/lib/keymaker/parsers/cypher_response_parser.rb
55
- def self.translate_response(response_body, result)
56
- Hashie::Mash.new(Hash[sanitized_column_names(response_body).zip(result)])
57
- end
58
-
59
- def self.sanitized_column_names(response_body)
60
- response_body.columns.map { |column| column[/[^\.]+$/] }
61
- end
62
-
63
- def cypher_string(labels, props)
64
- "CREATE (n#{label_string(labels)} #{prop_identifier(props)}) RETURN ID(n)"
65
- end
66
-
67
- def label_string(labels)
68
- labels.empty? ? '' : ":#{labels.map { |k| "`#{k}`" }.join(':')}"
69
- end
70
-
71
- def prop_identifier(props)
72
- '{props}' unless props.nil?
73
- end
74
- end
75
- end
76
- end