neo4j-core 4.0.7 → 5.0.0.rc.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.
@@ -36,54 +36,79 @@ module Neo4j
36
36
  "Enumerable query: '#{@query}'"
37
37
  end
38
38
 
39
- def each(&block)
39
+ def each
40
40
  @response.each_data_row do |row|
41
- yield(row.each_with_index.each_with_object(struct.new) do |(value, i), result|
42
- result[columns[i].to_sym] = value
43
- end)
41
+ yield struct_rows(row)
42
+ end
43
+ end
44
+
45
+ def struct_rows(row)
46
+ struct.new.tap do |result|
47
+ row.each_with_index { |value, i| result[columns[i]] = value }
44
48
  end
45
49
  end
46
50
  end
47
51
 
48
- def to_struct_enumeration(cypher = '')
52
+ EMPTY_STRING = ''
53
+ def to_struct_enumeration(cypher = EMPTY_STRING)
49
54
  HashEnumeration.new(self, cypher)
50
55
  end
51
56
 
52
- def to_node_enumeration(cypher = '', session = Neo4j::Session.current)
57
+ def to_node_enumeration(cypher = EMPTY_STRING, session = Neo4j::Session.current)
53
58
  Enumerator.new do |yielder|
54
59
  @result_index = 0
55
60
  to_struct_enumeration(cypher).each do |row|
56
61
  @row_index = 0
57
- yielder << row.each_pair.each_with_object(@struct.new) do |(column, value), result|
58
- result[column] = map_row_value(value, session)
59
- @row_index += 1
60
- end
62
+ yielder << row_pair_in_struct(row, session)
61
63
  @result_index += 1
62
64
  end
63
65
  end
64
66
  end
65
67
 
68
+ def row_pair_in_struct(row, session)
69
+ @struct.new.tap do |result|
70
+ row.each_pair do |column, value|
71
+ result[column] = map_row_value(value, session)
72
+ @row_index += 1
73
+ end
74
+ end
75
+ end
76
+
66
77
  def map_row_value(value, session)
67
78
  if value.is_a?(Hash)
68
79
  hash_value_as_object(value, session)
69
80
  elsif value.is_a?(Array)
70
- value.map { |v| map_row_value(v, session) }
81
+ value.map! { |v| map_row_value(v, session) }
71
82
  else
72
83
  value
73
84
  end
74
85
  end
75
86
 
76
87
  def hash_value_as_object(value, session)
77
- return value unless value['labels'] || value['type'] || transaction_response?
88
+ data = case
89
+ when transaction_response?
90
+ add_transaction_entity_id
91
+ mapped_rest_data
92
+ when value[:labels] || value[:type]
93
+ add_entity_id(value)
94
+ value
95
+ else
96
+ return value
97
+ end
98
+ basic_obj = (node?(value) ? CypherNode : CypherRelationship).new(session, data)
99
+ unwrapped? ? basic_obj : basic_obj.wrapper
100
+ end
101
+
102
+ def unwrapped!
103
+ @_unwrapped_obj = true
104
+ end
105
+
106
+ def unwrapped?
107
+ !!@_unwrapped_obj
108
+ end
78
109
 
79
- is_node, data = if transaction_response?
80
- add_transaction_entity_id
81
- [!mapped_rest_data['start'], mapped_rest_data]
82
- elsif value['labels'] || value['type']
83
- add_entity_id(value)
84
- [value['labels'], value]
85
- end
86
- (is_node ? CypherNode : CypherRelationship).new(session, data).wrapper
110
+ def node?(value)
111
+ transaction_response? ? !mapped_rest_data[:start] : value[:labels]
87
112
  end
88
113
 
89
114
  attr_reader :struct
@@ -95,17 +120,17 @@ module Neo4j
95
120
 
96
121
  def entity_data(id = nil)
97
122
  if @uncommited
98
- data = @data.first['row'].first
99
- data.is_a?(Hash) ? {'data' => data, 'id' => id} : data
123
+ data = @data.first[:row].first
124
+ data.is_a?(Hash) ? {data: data, id: id} : data
100
125
  else
101
126
  data = @data[0][0]
102
127
  data.is_a?(Hash) ? add_entity_id(data) : data
103
128
  end
104
129
  end
105
130
 
106
- def first_data(id = nil)
131
+ def first_data
107
132
  if @uncommited
108
- data = @data.first['row'].first
133
+ @data.first[:row].first
109
134
  # data.is_a?(Hash) ? {'data' => data, 'id' => id} : data
110
135
  else
111
136
  data = @data[0][0]
@@ -114,45 +139,57 @@ module Neo4j
114
139
  end
115
140
 
116
141
  def add_entity_id(data)
117
- data.merge!('id' => self.class.id_from_url(data['self']))
142
+ data[:id] = if data[:metadata] && data[:metadata][:id]
143
+ data[:metadata][:id]
144
+ else
145
+ self.class.id_from_url(data[:self])
146
+ end
147
+ data
118
148
  end
119
149
 
120
150
  def add_transaction_entity_id
121
- mapped_rest_data.merge!('id' => mapped_rest_data['self'].split('/').last.to_i)
151
+ mapped_rest_data[:id] = mapped_rest_data[:self].split('/').last.to_i
152
+ mapped_rest_data
122
153
  end
123
154
 
124
155
  def error?
125
156
  !!@error
126
157
  end
127
158
 
159
+ RETRYABLE_ERROR_STATUSES = %w(DeadlockDetectedException AcquireLockTimeoutException ExternalResourceFailureException UnknownFailureException)
160
+ def retryable_error?
161
+ return unless error?
162
+ RETRYABLE_ERROR_STATUSES.include?(@error_status)
163
+ end
164
+
128
165
  def data?
129
- !response.body['data'].nil?
166
+ !response.body[:data].nil?
130
167
  end
131
168
 
132
169
  def raise_unless_response_code(code)
133
- fail "Response code #{response.status}, expected #{code} for #{response.headers['location']}, #{response.body}" unless response.status == code
170
+ fail "Response code #{response.status}, expected #{code} for #{response.headers[:location]}, #{response.body}" unless response.status == code
134
171
  end
135
172
 
136
173
  def each_data_row
137
174
  if @uncommited
138
- data.each { |r| yield r['row'] }
175
+ data.each { |r| yield r[:row] }
139
176
  else
140
177
  data.each { |r| yield r }
141
178
  end
142
179
  end
143
180
 
144
- def set_data(data, columns)
145
- @data = data
146
- @columns = columns
147
- @struct = columns.empty? ? Object.new : Struct.new(*columns.map(&:to_sym))
181
+ def set_data(response)
182
+ @data = response[:data]
183
+ @columns = response[:columns]
184
+ @struct = @columns.empty? ? Object.new : Struct.new(*@columns.map(&:to_sym))
148
185
  self
149
186
  end
150
187
 
151
- def set_error(error_msg, error_status, error_core)
188
+ def set_error(error)
152
189
  @error = true
153
- @error_msg = error_msg
154
- @error_status = error_status
155
- @error_code = error_core
190
+ @error_msg = error[:message]
191
+ @error_status = error[:status] || error[:exception] || error[:code]
192
+ @error_code = error[:code] || error[:fullname]
156
193
  self
157
194
  end
158
195
 
@@ -170,9 +207,9 @@ module Neo4j
170
207
  def self.create_with_no_tx(response)
171
208
  case response.status
172
209
  when 200
173
- CypherResponse.new(response).set_data(response.body['data'], response.body['columns'])
210
+ new(response).set_data(response.body)
174
211
  when 400
175
- CypherResponse.new(response).set_error(response.body['message'], response.body['exception'], response.body['fullname'])
212
+ new(response).set_error(response.body)
176
213
  else
177
214
  fail "Unknown response code #{response.status} for #{response.env[:url]}"
178
215
  end
@@ -181,20 +218,18 @@ module Neo4j
181
218
  def self.create_with_tx(response)
182
219
  fail "Unknown response code #{response.status} for #{response.request_uri}" unless response.status == 200
183
220
 
184
- first_result = response.body['results'][0]
185
- cr = CypherResponse.new(response, true)
186
-
187
- if response.body['errors'].empty?
188
- cr.set_data(first_result['data'], first_result['columns'])
189
- else
190
- first_error = response.body['errors'].first
191
- cr.set_error(first_error['message'], first_error['status'], first_error['code'])
221
+ new(response, true).tap do |cr|
222
+ body = response.body
223
+ if body[:errors].empty?
224
+ cr.set_data(body[:results].first)
225
+ else
226
+ cr.set_error(body[:errors].first)
227
+ end
192
228
  end
193
- cr
194
229
  end
195
230
 
196
231
  def transaction_response?
197
- response.respond_to?('body') && !response.body['commit'].nil?
232
+ response.respond_to?(:body) && !response.body[:commit].nil?
198
233
  end
199
234
 
200
235
  def rest_data
@@ -203,7 +238,8 @@ module Neo4j
203
238
  end
204
239
 
205
240
  def rest_data_with_id
206
- rest_data.merge!('id' => mapped_rest_data['self'].split('/').last.to_i)
241
+ rest_data[:id] = mapped_rest_data[:self].split('/').last.to_i
242
+ rest_data
207
243
  end
208
244
 
209
245
  class << self
@@ -219,7 +255,7 @@ module Neo4j
219
255
  attr_reader :result_index
220
256
 
221
257
  def mapped_rest_data
222
- response.body['results'][0]['data'][result_index]['rest'][row_index]
258
+ response.body[:results][0][:data][result_index][:rest][row_index]
223
259
  end
224
260
  end
225
261
  end
@@ -1,8 +1,7 @@
1
1
  module Neo4j
2
2
  module Server
3
- # Plugin
4
- Neo4j::Session.register_db(:server_db) do |*url_opts|
5
- Neo4j::Server::CypherSession.open(*url_opts)
3
+ Neo4j::Session.register_db(:server_db) do |endpoint_url, url_opts|
4
+ Neo4j::Server::CypherSession.open(endpoint_url, url_opts)
6
5
  end
7
6
 
8
7
  class CypherSession < Neo4j::Session
@@ -26,9 +25,10 @@ module Neo4j
26
25
  init_params = params[:initialize] && params.delete(:initialize)
27
26
  conn = Faraday.new(url, init_params) do |b|
28
27
  b.request :basic_auth, params[:basic_auth][:username], params[:basic_auth][:password] if params[:basic_auth]
29
- b.request :json
28
+ b.request :multi_json
30
29
  # b.response :logger
31
- b.response :json, content_type: 'application/json'
30
+
31
+ b.response :multi_json, symbolize_keys: true, content_type: 'application/json'
32
32
  # b.use Faraday::Response::RaiseError
33
33
  b.use Faraday::Adapter::NetHttpPersistent
34
34
  # b.adapter Faraday.default_adapter
@@ -52,17 +52,14 @@ module Neo4j
52
52
  end
53
53
 
54
54
  def self.establish_session(root_data, connection)
55
- data_url = root_data['data']
55
+ data_url = root_data[:data]
56
56
  data_url << '/' unless data_url.nil? || data_url.end_with?('/')
57
57
  CypherSession.new(data_url, connection)
58
58
  end
59
59
 
60
60
  def self.extract_basic_auth(url, params)
61
61
  return unless url && URI(url).userinfo
62
- params[:basic_auth] = {
63
- username: URI(url).user,
64
- password: URI(url).password
65
- }
62
+ params[:basic_auth] = {username: URI(url).user, password: URI(url).password}
66
63
  end
67
64
 
68
65
  private_class_method :extract_basic_auth
@@ -80,12 +77,12 @@ module Neo4j
80
77
  end
81
78
 
82
79
  def version
83
- resource_data ? resource_data['neo4j_version'] : ''
80
+ resource_data ? resource_data[:neo4j_version] : ''
84
81
  end
85
82
 
86
83
  def initialize_resource(data_url)
87
84
  response = @connection.get(data_url)
88
- expect_response_code(response, 200)
85
+ expect_response_code!(response, 200)
89
86
  data_resource = response.body
90
87
  fail "No data_resource for #{response.body}" unless data_resource
91
88
  # store the resource data
@@ -98,43 +95,27 @@ module Neo4j
98
95
  end
99
96
 
100
97
  def begin_tx
101
- if Neo4j::Transaction.current
102
- # Handle nested transaction "placebo transaction"
103
- Neo4j::Transaction.current.push_nested!
104
- else
105
- wrap_resource(@connection)
106
- end
98
+ Neo4j::Transaction.current ? Neo4j::Transaction.current.push_nested! : wrap_resource(@connection)
107
99
  Neo4j::Transaction.current
108
100
  end
109
101
 
110
102
  def create_node(props = nil, labels = [])
111
- id = _query_or_fail(cypher_string(labels, props), true, cypher_prop_list(props))
112
- value = props.nil? ? id : {'id' => id, 'metadata' => {'labels' => labels}, 'data' => props}
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}
113
105
  CypherNode.new(self, value)
114
106
  end
115
107
 
116
108
  def load_node(neo_id)
117
- load_entity(CypherNode, _query("MATCH (n) WHERE ID(n) = #{neo_id} RETURN n"))
109
+ query.unwrapped.match(:n).where(n: {neo_id: neo_id}).pluck(:n).first
118
110
  end
119
111
 
120
112
  def load_relationship(neo_id)
121
- load_entity(CypherRelationship, _query("MATCH (n)-[r]-() WHERE ID(r) = #{neo_id} RETURN r"))
122
- end
123
-
124
- def load_entity(clazz, cypher_response)
125
- return nil if cypher_response.data.nil? || cypher_response.data[0].nil?
126
- data = if cypher_response.transaction_response?
127
- cypher_response.rest_data_with_id
128
- else
129
- cypher_response.first_data
130
- end
131
-
132
- if cypher_response.error?
133
- cypher_response.raise_error
134
- elsif cypher_response.error_msg =~ /not found/ # Ugly that the Neo4j API gives us this error message
135
- return nil
113
+ query.unwrapped.optional_match('(n)-[r]-()').where(r: {neo_id: neo_id}).pluck(:r).first
114
+ rescue Neo4j::Session::CypherError => cypher_error
115
+ if cypher_error.message.match(/not found$/)
116
+ nil
136
117
  else
137
- clazz.new(self, data)
118
+ raise cypher_error
138
119
  end
139
120
  end
140
121
 
@@ -143,17 +124,17 @@ module Neo4j
143
124
  end
144
125
 
145
126
  def uniqueness_constraints(label)
146
- schema_properties("#{@resource_url}schema/constraint/#{label}/uniqueness")
127
+ schema_properties("/db/data/schema/constraint/#{label}/uniqueness")
147
128
  end
148
129
 
149
130
  def indexes(label)
150
- schema_properties("#{@resource_url}schema/index/#{label}")
131
+ schema_properties("/db/data/schema/index/#{label}")
151
132
  end
152
133
 
153
134
  def schema_properties(query_string)
154
135
  response = @connection.get(query_string)
155
- expect_response_code(response, 200)
156
- {property_keys: response.body.map { |row| row['property_keys'].map(&:to_sym) }}
136
+ expect_response_code!(response, 200)
137
+ {property_keys: response.body.map! { |row| row[:property_keys].map(&:to_sym) }}
157
138
  end
158
139
 
159
140
  def find_all_nodes(label_name)
@@ -163,17 +144,15 @@ module Neo4j
163
144
  def find_nodes(label_name, key, value)
164
145
  value = "'#{value}'" if value.is_a? String
165
146
 
166
- response = _query_or_fail <<-CYPHER
167
- MATCH (n:`#{label_name}`)
168
- WHERE n.#{key} = #{value}
169
- RETURN ID(n)
170
- CYPHER
147
+ response = _query_or_fail("MATCH (n:`#{label_name}`) WHERE n.#{key} = #{value} RETURN ID(n)")
171
148
  search_result_to_enumerable_first_column(response)
172
149
  end
173
150
 
174
151
  def query(*args)
175
152
  if [[String], [String, Hash]].include?(args.map(&:class))
176
- query, params = args[0, 2]
153
+ query = args[0]
154
+ params = args[1]
155
+
177
156
  response = _query(query, params)
178
157
  response.raise_error if response.error?
179
158
  response.to_node_enumeration(query)
@@ -183,77 +162,85 @@ module Neo4j
183
162
  end
184
163
  end
185
164
 
186
- def _query_data(q)
187
- r = _query_or_fail(q, true)
188
- # the response is different if we have a transaction or not
189
- Neo4j::Transaction.current ? r : r['data']
165
+ def _query_data(query)
166
+ r = _query_or_fail(query, true)
167
+ Neo4j::Transaction.current ? r : r[:data]
190
168
  end
191
169
 
192
- def _query_or_fail(q, single_row = false, params = {})
193
- if q.is_a?(::Neo4j::Core::Query)
194
- cypher = q.to_cypher
195
- params = q.send(:merge_params).merge(params)
196
- q = cypher
170
+ DEFAULT_RETRY_COUNT = ENV['NEO4J_RETRY_COUNT'].nil? ? 10 : ENV['NEO4J_RETRY_COUNT'].to_i
171
+
172
+ def _query_or_fail(query, single_row = false, params = {}, retry_count = DEFAULT_RETRY_COUNT)
173
+ query, params = query_and_params(query, params)
174
+
175
+ response = _query(query, params)
176
+ if response.error?
177
+ _retry_or_raise(query, params, single_row, retry_count, response)
178
+ else
179
+ single_row ? response.first_data : response
197
180
  end
181
+ end
198
182
 
199
- response = _query(q, params)
200
- response.raise_error if response.error?
201
- single_row ? response.first_data : response
183
+ def query_and_params(query_or_query_string, params)
184
+ if query_or_query_string.is_a?(::Neo4j::Core::Query)
185
+ cypher = query_or_query_string.to_cypher
186
+ [cypher, query_or_query_string.send(:merge_params).merge(params)]
187
+ else
188
+ [query_or_query_string, params]
189
+ end
202
190
  end
203
191
 
204
- def _query_entity_data(q, id = nil, params = nil)
205
- response = _query(q, params)
206
- response.raise_error if response.error?
207
- response.entity_data(id)
192
+ def _retry_or_raise(query, params, single_row, retry_count, response)
193
+ response.raise_error unless response.retryable_error?
194
+ retry_count > 0 ? _query_or_fail(query, single_row, params, retry_count - 1) : response.raise_error
208
195
  end
209
196
 
210
- def _query(q, params = nil)
211
- # puts "q #{q}"
197
+ 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
+ _query(query, params).tap do |response|
203
+ response.raise_error if response.error?
204
+ end
205
+ end
206
+
207
+ def _query(query, params = {})
208
+ query, params = query_and_params(query, params)
209
+
212
210
  curr_tx = Neo4j::Transaction.current
213
211
  if curr_tx
214
- curr_tx._query(q, params)
212
+ curr_tx._query(query, params)
215
213
  else
216
- url = resource_url('cypher')
217
- q = params.nil? ? {'query' => q} : {'query' => q, 'params' => params}
218
- response = @connection.post(url, q)
214
+ url = resource_url(:cypher)
215
+ query = params.nil? ? {'query' => query} : {'query' => query, 'params' => params}
216
+ response = @connection.post(url, query)
219
217
  CypherResponse.create_with_no_tx(response)
220
218
  end
221
219
  end
222
220
 
223
221
  def search_result_to_enumerable_first_column(response)
224
222
  return [] unless response.data
225
- if Neo4j::Transaction.current
226
- search_result_to_enumerable_first_column_with_tx(response)
227
- else
228
- search_result_to_enumerable_first_column_without_tx(response)
229
- end
230
- end
231
223
 
232
- def search_result_to_enumerable_first_column_with_tx(response)
233
224
  Enumerator.new do |yielder|
234
225
  response.data.each do |data|
235
- data['row'].each do |id|
236
- yielder << CypherNode.new(self, id).wrapper
226
+ if Neo4j::Transaction.current
227
+ data[:row].each do |id|
228
+ yielder << CypherNode.new(self, id).wrapper
229
+ end
230
+ else
231
+ yielder << CypherNode.new(self, data[0]).wrapper
237
232
  end
238
233
  end
239
234
  end
240
235
  end
241
236
 
242
- def search_result_to_enumerable_first_column_without_tx(response)
243
- Enumerator.new do |yielder|
244
- response.data.each do |data|
245
- yielder << CypherNode.new(self, data[0]).wrapper
246
- end
247
- end
248
- end
249
-
250
- def map_column(key, map, data)
251
- if map[key] == :node
252
- CypherNode.new(self, data).wrapper
253
- elsif map[key] == :rel || map[:key] || :relationship
254
- CypherRelationship.new(self, data)
255
- else
256
- data
237
+ EMPTY = ''
238
+ def self.log_with
239
+ clear, yellow, cyan = %W(\e[0m \e[33m \e[36m)
240
+ ActiveSupport::Notifications.subscribe('neo4j.cypher_query') do |_, start, finish, _id, payload|
241
+ 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}")
257
244
  end
258
245
  end
259
246
  end
@@ -2,9 +2,9 @@ module Neo4j
2
2
  module Server
3
3
  # The CypherTransaction object lifecycle is as follows:
4
4
  # * It is initialized with the transactional endpoint URL and the connection object to use for communication. It does not communicate with the server to create this.
5
- # * The first query within the transaction sets the commit and execution addresses, :commit_url and :exec_url.
5
+ # * The first query within the transaction sets the commit and execution addresses, :commit_url and :query_url.
6
6
  # * At any time, `failure` can be called to mark a transaction failed and trigger a rollback upon closure.
7
- # * `close` is called to end the transaction. It calls `_commit_tx` or `_delete_tx`.
7
+ # * `close` is called to end the transaction. It calls `commit` or `delete`.
8
8
  #
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
@@ -12,7 +12,7 @@ module Neo4j
12
12
  include Neo4j::Core::CypherTranslator
13
13
  include Resource
14
14
 
15
- attr_reader :commit_url, :exec_url, :base_url, :connection
15
+ attr_reader :commit_url, :query_url, :base_url, :connection
16
16
 
17
17
  def initialize(url, session_connection)
18
18
  @base_url = url
@@ -26,49 +26,58 @@ module Neo4j
26
26
  statement = {statement: cypher_query, parameters: params, resultDataContents: ROW_REST}
27
27
  body = {statements: [statement]}
28
28
 
29
- response = exec_url && commit_url ? connection.post(exec_url, body) : register_urls(body)
30
- _create_cypher_response(response)
29
+ response = @query_url ? query(body) : start(body)
30
+
31
+ create_cypher_response(response)
31
32
  end
32
33
 
33
- def _delete_tx
34
- _tx_query(:delete, exec_url, headers: resource_headers)
34
+ def start(body)
35
+ request(:post, @base_url, 201, body).tap do |response|
36
+ @commit_url = response.body[:commit]
37
+ @query_url = response.headers[:Location]
38
+
39
+ fail "NO ENDPOINT URL #{connection} : HEAD: #{response.headers.inspect}" if !@query_url || @query_url.empty?
40
+
41
+ init_resource_data(response.body, @base_url)
42
+ end
35
43
  end
36
44
 
37
- def _commit_tx
38
- _tx_query(:post, commit_url, nil)
45
+ def query(body)
46
+ request(:post, @query_url, 200, body)
39
47
  end
40
48
 
41
- private
49
+ def delete
50
+ return empty_response if !@commit_url || expired?
42
51
 
43
- def _tx_query(action, endpoint, headers = {})
44
- return empty_response if !commit_url || expired?
45
- response = connection.send(action, endpoint, headers)
46
- expect_response_code(response, 200)
47
- response
52
+ request(:delete, @query_url, 200, nil, resource_headers)
48
53
  end
49
54
 
50
- def register_urls(body)
51
- response = connection.post(base_url, body)
52
- @commit_url = response.body['commit']
53
- @exec_url = response.headers['Location']
54
- fail "NO ENDPOINT URL #{connection} : HEAD: #{response.headers.inspect}" if !exec_url || exec_url.empty?
55
- init_resource_data(response.body, base_url)
56
- expect_response_code(response, 201)
57
- response
55
+ def commit
56
+ return empty_response if !@commit_url || expired?
57
+
58
+ request(:post, @commit_url, 200, nil, resource_headers)
59
+ end
60
+
61
+ private
62
+
63
+ def request(action, endpoint_url, expected_code = 200, body = nil, headers = {})
64
+ connection.send(action, endpoint_url, body, headers).tap do |response|
65
+ expect_response_code!(response, expected_code)
66
+ end
58
67
  end
59
68
 
60
- def _create_cypher_response(response)
61
- first_result = response.body['results'][0]
69
+ def create_cypher_response(response)
70
+ first_result = response.body[:results][0]
62
71
 
63
- cr = CypherResponse.new(response, true)
64
- if response.body['errors'].empty?
65
- cr.set_data(first_result['data'], first_result['columns'])
66
- else
67
- first_error = response.body['errors'].first
68
- expired if first_error['message'].match(/Unrecognized transaction id/)
69
- cr.set_error(first_error['message'], first_error['code'], first_error['code'])
72
+ CypherResponse.new(response, true).tap do |cypher_response|
73
+ if response.body[:errors].empty?
74
+ cypher_response.set_data(first_result)
75
+ else
76
+ first_error = response.body[:errors].first
77
+ mark_expired if first_error[:message].match(/Unrecognized transaction id/)
78
+ cypher_response.set_error(first_error)
79
+ end
70
80
  end
71
- cr
72
81
  end
73
82
 
74
83
  def empty_response