neo4j-core 3.1.0 → 3.1.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6f4890cd93db0d6c36f8208fc1e9389c587edaf2
4
- data.tar.gz: dea68555caf4904ac68214b6cea915cb1c8462e9
3
+ metadata.gz: bb8493440e6f8164e499189ebc58e95998b5bad1
4
+ data.tar.gz: 02678788be0642f10aa6781bdcb82fd11ab5fe97
5
5
  SHA512:
6
- metadata.gz: 3e34f33523134c71bb13aa7858a3f2444bcfb252f39d2dc54c41417d8c291347e47a8730c200639e1cb0ef7094b1c84941312b1210877c46f4471c4bcaca84ce
7
- data.tar.gz: 2a0cb02bb6ea67c92e9964643c5743a2bca5b35385cc7079b02433c283014eb929c6d403f1ef148b66b8d3eda9a2d214be9f5d6c23e3db621d120764c6dee40d
6
+ metadata.gz: 82882d368b6ff790c061653f0cb68a2af37e328ef2ea948c507671108976d0a7ee60fac78653b6e254ca4a5d00c6cedf1bcda3bce15e038b446665042363fe5d
7
+ data.tar.gz: 76be0d527c6d6710eb3753fd370b747341efd3f099654447d9297a18d29bb01c330764183d206ef48fa59aab78ecdfa600cdb55879e0ad106a177e0188970035
@@ -1,5 +1,5 @@
1
1
  module Neo4j
2
2
  module Core
3
- VERSION = "3.1.0"
3
+ VERSION = "3.1.1"
4
4
  end
5
5
  end
@@ -35,11 +35,16 @@ module Neo4j::Server
35
35
  # Uses the given username and password to obtain a token, then adds the token to the connection's parameters.
36
36
  # @return [String] An access token provided by the server.
37
37
  def authenticate
38
- auth_response = connection.get("#{url}/authentication")
39
- return nil if auth_response.body.empty?
40
- auth_body = JSON.parse(auth_response.body)
41
- token = auth_body['errors'][0]['code'] == 'Neo.ClientError.Security.AuthorizationFailed' ? obtain_token : nil
42
- add_auth_headers(token) unless token.nil?
38
+ auth_response = auth_connection("#{url}/authentication")
39
+ auth_hash = if auth_response.body.empty?
40
+ nil
41
+ elsif auth_response.body.is_a?(String)
42
+ JSON.parse(auth_response.body)['errors'][0]['code'] == 'Neo.ClientError.Security.AuthorizationFailed' ? auth_attempt : nil
43
+ else
44
+ auth_response
45
+ end
46
+ return nil if auth_hash.nil?
47
+ add_auth_headers(token_or_error(auth_hash))
43
48
  end
44
49
 
45
50
  # Invalidates the existing token, which will invalidate all conncetions using this token, applies for a new token, adds this into
@@ -47,21 +52,32 @@ module Neo4j::Server
47
52
  # @param [String] password The current server password.
48
53
  def reauthenticate(password)
49
54
  invalidate_token(password)
50
- add_auth_headers(obtain_token)
55
+ add_auth_headers(token_or_error(auth_attempt))
51
56
  end
52
57
 
53
58
  # Requests a token from the authentication endpoint using the given username and password.
54
- # @return [String] A plain-text token.
55
- def obtain_token
59
+ # @return [Faraday::Response] The server's response, to be interpreted.
60
+ def auth_attempt
56
61
  begin
57
62
  user = params[:basic_auth][:username]
58
63
  pass = params[:basic_auth][:password]
59
64
  rescue NoMethodError
60
65
  raise MissingCredentialsError, 'Neo4j authentication is enabled, username/password are required but missing'
61
66
  end
62
- auth_response = connection.post("#{url}/authentication", { 'username' => user, 'password' => pass })
63
- raise PasswordChangeRequiredError, "Server requires a password change, please visit #{url}" if auth_response.body['password_change_required']
64
- raise InvalidPasswordError, "Neo4j server responded with: #{auth_response.body['errors'][0]['message']}" if auth_response.status.to_i == 422
67
+ connection.post("#{url}/authentication", { 'username' => user, 'password' => pass })
68
+ end
69
+
70
+ # Takes a response object from the server and returns a token or fails with an error.
71
+ # Todo: more error states!
72
+ # @param [Farday::Response] auth_response The response after attempting authentication
73
+ # @return [String] An authentication token.
74
+ def token_or_error(auth_response)
75
+ begin
76
+ raise PasswordChangeRequiredError, "Server requires a password change, please visit #{url}" if auth_response.body['password_change_required']
77
+ raise InvalidPasswordError, "Neo4j server responded with: #{auth_response.body['errors'][0]['message']}" if auth_response.status.to_i == 422
78
+ rescue NoMethodError
79
+ raise 'Unexpected auth response, please open an issue at https://github.com/neo4jrb/neo4j-core/issues'
80
+ end
65
81
  auth_response.body['authorization_token']
66
82
  end
67
83
 
@@ -72,6 +88,7 @@ module Neo4j::Server
72
88
  end
73
89
 
74
90
  # Stores an authentication token in the properly-formatted header.
91
+ # This does not do any checking that what it has been given is a token. Whatever param is given will be base64 encoded and used as the header.
75
92
  # @param [String] token The authentication token provided by the database.
76
93
  def add_auth_headers(token)
77
94
  @token = token
@@ -80,6 +97,11 @@ module Neo4j::Server
80
97
 
81
98
  private
82
99
 
100
+ # Makes testing easier, we can stub this method to simulate different responses
101
+ def auth_connection(url)
102
+ connection.get(url)
103
+ end
104
+
83
105
  def self.new_connection
84
106
  conn = Faraday.new do |b|
85
107
  b.request :json
@@ -95,7 +117,7 @@ module Neo4j::Server
95
117
  end
96
118
 
97
119
  def token_hash(token)
98
- Base64.strict_encode64(":#{token}")
120
+ ::Base64.strict_encode64(":#{token}")
99
121
  end
100
122
  end
101
123
  end
@@ -46,7 +46,7 @@ module Neo4j::Server
46
46
  if @props
47
47
  @props
48
48
  else
49
- hash = @session._query_entity_data("#{match_start} RETURN n")
49
+ hash = @session._query_entity_data("#{match_start} RETURN n", nil, neo_id: neo_id)
50
50
  @props = Hash[hash['data'].map{ |k, v| [k.to_sym, v] }]
51
51
  end
52
52
  end
@@ -58,20 +58,20 @@ module Neo4j::Server
58
58
  # (see Neo4j::Node#remove_property)
59
59
  def remove_property(key)
60
60
  refresh
61
- @session._query_or_fail("#{match_start} REMOVE n.`#{key}`")
61
+ @session._query_or_fail("#{match_start} REMOVE n.`#{key}`", false, { neo_id: neo_id })
62
62
  end
63
63
 
64
64
  # (see Neo4j::Node#set_property)
65
65
  def set_property(key,value)
66
66
  refresh
67
- @session._query_or_fail("#{match_start} SET n.`#{key}` = { value }", false, value: value)
67
+ @session._query_or_fail("#{match_start} SET n.`#{key}` = { value }", false, { value: value, neo_id: neo_id })
68
68
  value
69
69
  end
70
70
 
71
71
  # (see Neo4j::Node#props=)
72
72
  def props=(properties)
73
73
  refresh
74
- @session._query_or_fail("#{match_start} SET n = { props }", false, {props: properties})
74
+ @session._query_or_fail("#{match_start} SET n = { props }", false, { props: properties, neo_id: neo_id })
75
75
  properties
76
76
  end
77
77
 
@@ -80,7 +80,7 @@ module Neo4j::Server
80
80
  q = "#{match_start} REMOVE " + properties.map do |k|
81
81
  "n.`#{k}`"
82
82
  end.join(', ')
83
- @session._query_or_fail(q)
83
+ @session._query_or_fail(q, false, neo_id: neo_id)
84
84
  end
85
85
 
86
86
  # (see Neo4j::Node#update_props)
@@ -92,25 +92,19 @@ module Neo4j::Server
92
92
  remove_properties(removed_keys) unless removed_keys.empty?
93
93
  properties_to_set = properties.keys - removed_keys
94
94
  return if properties_to_set.empty?
95
- q = "#{match_start} SET " + properties_to_set.map do |k|
96
- "n.`#{k}`= #{escape_value(properties[k])}"
97
- end.join(',')
98
- @session._query_or_fail(q)
95
+ props_list = cypher_prop_list(properties)[:props].merge({ neo_id: neo_id })
96
+ @session._query_or_fail("#{match_start} SET #{cypher_properties(properties_to_set)}", false, props_list)
99
97
  properties
100
98
  end
101
99
 
102
100
  # (see Neo4j::Node#get_property)
103
101
  def get_property(key)
104
- if @props
105
- @props[key.to_sym]
106
- else
107
- @session._query_or_fail("#{match_start} RETURN n.`#{key}`", true)
108
- end
102
+ @props ? @props[key.to_sym] : @session._query_or_fail("#{match_start} RETURN n.`#{key}`", true, neo_id: neo_id)
109
103
  end
110
104
 
111
105
  # (see Neo4j::Node#labels)
112
106
  def labels
113
- @labels ||= @session._query_or_fail("#{match_start} RETURN labels(n) as labels", true)
107
+ @labels ||= @session._query_or_fail("#{match_start} RETURN labels(n) as labels", true, neo_id: neo_id)
114
108
  @labels.map(&:to_sym)
115
109
  end
116
110
 
@@ -119,22 +113,21 @@ module Neo4j::Server
119
113
  end
120
114
 
121
115
  def add_label(*labels)
122
- @session._query_or_fail("#{match_start} SET n #{_cypher_label_list(labels)}")
116
+ @session._query_or_fail("#{match_start} SET n #{_cypher_label_list(labels)}", false, neo_id: neo_id)
123
117
  end
124
118
 
125
119
  def remove_label(*labels)
126
- @session._query_or_fail("#{match_start} REMOVE n #{_cypher_label_list(labels)}")
120
+ @session._query_or_fail("#{match_start} REMOVE n #{_cypher_label_list(labels)}", false, neo_id: neo_id)
127
121
  end
128
122
 
129
123
  def set_label(*label_names)
130
- q = "#{match_start} #{remove_labels_if_needed} #{set_labels_if_needed(label_names)}"
131
- @session._query_or_fail(q)
124
+ q = "#{match_start} #{remove_labels_if_needed} #{set_labels_if_needed(label_names)}"
125
+ @session._query_or_fail(q, false, neo_id: neo_id)
132
126
  end
133
127
 
134
128
  # (see Neo4j::Node#del)
135
129
  def del
136
- @session._query_or_fail("#{match_start} MATCH n-[r]-() DELETE r")
137
- @session._query_or_fail("#{match_start} DELETE n")
130
+ @session._query_or_fail("#{match_start} OPTIONAL MATCH n-[r]-() DELETE n, r", false, neo_id: neo_id)
138
131
  end
139
132
 
140
133
  alias_method :delete, :del
@@ -142,7 +135,7 @@ module Neo4j::Server
142
135
 
143
136
  # (see Neo4j::Node#exist?)
144
137
  def exist?
145
- @session._query("#{match_start} RETURN ID(n)").data.empty? ? false : true
138
+ @session._query("#{match_start} RETURN ID(n)", neo_id: neo_id).data.empty? ? false : true
146
139
  end
147
140
 
148
141
  # (see Neo4j::Node#node)
@@ -181,7 +174,7 @@ module Neo4j::Server
181
174
  between_id = match[:between] ? "MATCH (p) WHERE ID(p) = #{match[:between].neo_id}" : ""
182
175
  dir_func = to_dir[match[:dir] || :both]
183
176
  cypher = "#{match_start} #{between_id} MATCH (n)#{dir_func.call(cypher_rel)}(p) RETURN #{returns}"
184
- r = @session._query(cypher)
177
+ r = @session._query(cypher, neo_id: neo_id)
185
178
  r.raise_error if r.error?
186
179
  _map_result(r)
187
180
  end
@@ -192,6 +185,10 @@ module Neo4j::Server
192
185
 
193
186
  private
194
187
 
188
+ def cypher_properties(properties_to_set)
189
+ properties_to_set.map! { |k| "n.`#{k}` = {`#{k}`}"}.join(',')
190
+ end
191
+
195
192
  def remove_labels_if_needed
196
193
  if labels.empty?
197
194
  ""
@@ -215,7 +212,7 @@ module Neo4j::Server
215
212
  end
216
213
 
217
214
  def match_start(identifier = 'n')
218
- "MATCH (#{identifier}) WHERE ID(#{identifier}) = #{neo_id}"
215
+ "MATCH (#{identifier}) WHERE ID(#{identifier}) = {neo_id}"
219
216
  end
220
217
  end
221
218
  end
@@ -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("#{match_start} RETURN n", true) # r.first_data
37
+ @resource_data = @session._query_or_fail("#{match_start} RETURN n", true, neo_id: neo_id) # 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("#{match_start} RETURN n.`#{key}`", true)
72
+ @session._query_or_fail("#{match_start} RETURN n.`#{key}`", true, neo_id: neo_id )
73
73
  end
74
74
 
75
75
  def set_property(key,value)
76
- @session._query_or_fail("#{match_start} SET n.`#{key}` = {value}", false, {value: value})
76
+ @session._query_or_fail("#{match_start} SET n.`#{key}` = {value}", false, { value: value, neo_id: neo_id })
77
77
  end
78
78
 
79
79
  def remove_property(key)
80
- @session._query_or_fail("#{match_start} REMOVE n.`#{key}`")
80
+ @session._query_or_fail("#{match_start} REMOVE n.`#{key}`", false, neo_id: neo_id)
81
81
  end
82
82
 
83
83
  # (see Neo4j::Relationship#props)
@@ -85,14 +85,14 @@ module Neo4j::Server
85
85
  if @props
86
86
  @props
87
87
  else
88
- hash = @session._query_entity_data("#{match_start} RETURN n")
88
+ hash = @session._query_entity_data("#{match_start} RETURN n", nil, neo_id: neo_id)
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("#{match_start} SET n = { props }", false, {props: properties})
95
+ @session._query_or_fail("#{match_start} SET n = { props }", false, { props: properties, neo_id: neo_id })
96
96
  properties
97
97
  end
98
98
 
@@ -102,7 +102,7 @@ module Neo4j::Server
102
102
  q = "#{match_start} SET " + properties.keys.map do |k|
103
103
  "n.`#{k}`= #{escape_value(properties[k])}"
104
104
  end.join(',')
105
- @session._query_or_fail(q)
105
+ @session._query_or_fail(q, false, neo_id: neo_id)
106
106
  properties
107
107
  end
108
108
 
@@ -111,13 +111,13 @@ module Neo4j::Server
111
111
  end
112
112
 
113
113
  def del
114
- @session._query("#{match_start} DELETE n").raise_unless_response_code(200)
114
+ @session._query("#{match_start} DELETE n", neo_id: neo_id).raise_unless_response_code(200)
115
115
  end
116
116
  alias_method :delete, :del
117
117
  alias_method :destroy, :del
118
118
 
119
119
  def exist?
120
- response = @session._query("#{match_start} RETURN n")
120
+ response = @session._query("#{match_start} RETURN n", neo_id: neo_id)
121
121
  # binding.pry
122
122
  (response.data.nil? || response.data.empty?) ? false : true
123
123
  end
@@ -125,7 +125,7 @@ module Neo4j::Server
125
125
  private
126
126
 
127
127
  def match_start(identifier = 'n')
128
- "MATCH (node)-[#{identifier}]-() WHERE ID(#{identifier}) = #{neo_id}"
128
+ "MATCH (node)-[#{identifier}]-() WHERE ID(#{identifier}) = {neo_id}"
129
129
  end
130
130
  end
131
131
  end
@@ -56,7 +56,7 @@ module Neo4j::Server
56
56
 
57
57
  def self.establish_session(root_data, connection, auth_obj)
58
58
  data_url = root_data['data']
59
- data_url << '/' unless data_url.end_with?('/')
59
+ data_url << '/' unless data_url.nil? || data_url.end_with?('/')
60
60
  CypherSession.new(data_url, connection, auth_obj)
61
61
  end
62
62
 
@@ -196,13 +196,13 @@ module Neo4j::Server
196
196
  single_row ? response.first_data : response
197
197
  end
198
198
 
199
- def _query_entity_data(q, id=nil)
200
- response = _query(q)
199
+ def _query_entity_data(q, id = nil, params = nil)
200
+ response = _query(q, params)
201
201
  response.raise_error if response.error?
202
202
  response.entity_data(id)
203
203
  end
204
204
 
205
- def _query(q, params=nil)
205
+ def _query(q, params = nil)
206
206
  curr_tx = Neo4j::Transaction.current
207
207
  if (curr_tx)
208
208
  curr_tx._query(q, params)
@@ -6,13 +6,12 @@ require 'neo4j-core/version'
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "neo4j-core"
8
8
  s.version = Neo4j::Core::VERSION
9
- s.required_ruby_version = ">= 1.8.7"
9
+ s.required_ruby_version = ">= 1.9.3"
10
10
 
11
- s.authors = "Andreas Ronge"
12
- s.email = 'andreas.ronge@gmail.com'
11
+ s.authors = "Andreas Ronge, Chris Grigg, Brian Underwood"
12
+ s.email = 'andreas.ronge@gmail.com, chris@subvertallmedia.com, brian@brian-underwood.codes'
13
13
  s.homepage = "https://github.com/neo4jrb/neo4j-core"
14
- s.rubyforge_project = 'neo4j-core'
15
- s.summary = "A graph database for Ruby"
14
+ s.summary = "A basic library to work with the graph database Neo4j."
16
15
  s.license = 'MIT'
17
16
 
18
17
  s.description = <<-EOF
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: 3.1.0
4
+ version: 3.1.1
5
5
  platform: ruby
6
6
  authors:
7
- - Andreas Ronge
7
+ - Andreas Ronge, Chris Grigg, Brian Underwood
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-05 00:00:00.000000000 Z
11
+ date: 2014-12-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -138,7 +138,7 @@ dependencies:
138
138
  version: '0'
139
139
  description: |
140
140
  Neo4j-core provides classes and methods to work with the graph database Neo4j.
141
- email: andreas.ronge@gmail.com
141
+ email: andreas.ronge@gmail.com, chris@subvertallmedia.com, brian@brian-underwood.codes
142
142
  executables: []
143
143
  extensions: []
144
144
  extra_rdoc_files:
@@ -208,17 +208,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
208
208
  requirements:
209
209
  - - ">="
210
210
  - !ruby/object:Gem::Version
211
- version: 1.8.7
211
+ version: 1.9.3
212
212
  required_rubygems_version: !ruby/object:Gem::Requirement
213
213
  requirements:
214
214
  - - ">="
215
215
  - !ruby/object:Gem::Version
216
216
  version: '0'
217
217
  requirements: []
218
- rubyforge_project: neo4j-core
219
- rubygems_version: 2.4.3
218
+ rubyforge_project:
219
+ rubygems_version: 2.4.5
220
220
  signing_key:
221
221
  specification_version: 4
222
- summary: A graph database for Ruby
222
+ summary: A basic library to work with the graph database Neo4j.
223
223
  test_files: []
224
224
  has_rdoc: true